diff --git a/packages/j-db-client/package.json b/packages/j-db-client/package.json index 0376bb64..70a63ac4 100644 --- a/packages/j-db-client/package.json +++ b/packages/j-db-client/package.json @@ -1,6 +1,6 @@ { "name": "@journaly/j-db-client", - "version": "13.20.0", + "version": "13.22.0", "description": "Journaly's internal database client.", "main": "dist/index", "scripts": { diff --git a/packages/j-db-client/prisma/migrations/20240822150636_add_posting_ip_to_posts_and_comments/migration.sql b/packages/j-db-client/prisma/migrations/20240822150636_add_posting_ip_to_posts_and_comments/migration.sql new file mode 100644 index 00000000..1af02ffb --- /dev/null +++ b/packages/j-db-client/prisma/migrations/20240822150636_add_posting_ip_to_posts_and_comments/migration.sql @@ -0,0 +1,8 @@ +-- AlterTable +ALTER TABLE "Comment" ADD COLUMN "postingIpAddress" TEXT; + +-- AlterTable +ALTER TABLE "Post" ADD COLUMN "postingIpAddress" TEXT; + +-- AlterTable +ALTER TABLE "PostComment" ADD COLUMN "postingIpAddress" TEXT; diff --git a/packages/j-db-client/prisma/schema.prisma b/packages/j-db-client/prisma/schema.prisma index aa67a385..b7bd3bcb 100644 --- a/packages/j-db-client/prisma/schema.prisma +++ b/packages/j-db-client/prisma/schema.prisma @@ -140,6 +140,7 @@ model Post { savedUsers User[] @relation("UserSavedPosts", references: [id]) privateShareId String? @unique newPostNotifications NewPostNotification[] + postingIpAddress String? } model Language { @@ -247,6 +248,7 @@ model Comment { authorLanguageLevel LanguageLevel @default(BEGINNER) threadCommentNotifications ThreadCommentNotification[] mentionNotifications MentionNotification[] + postingIpAddress String? } model PostComment { @@ -263,6 +265,7 @@ model PostComment { postCommentNotifications PostCommentNotification[] mentionNotifications MentionNotification[] authorLanguageLevel LanguageLevel @default(BEGINNER) + postingIpAddress String? } model Thread { diff --git a/packages/j-mail/package.json b/packages/j-mail/package.json index a9741169..ed0b8cf2 100644 --- a/packages/j-mail/package.json +++ b/packages/j-mail/package.json @@ -36,7 +36,7 @@ "typescript": "4.2.4" }, "dependencies": { - "@journaly/j-db-client": "^13.20.0", + "@journaly/j-db-client": "^13.22.0", "@types/nodemailer": "^6.4.0", "aws-sdk": "^2.737.0", "date-fns": "^2.16.1", diff --git a/packages/web/package-lock.json b/packages/web/package-lock.json index 72b543b0..42fff220 100644 --- a/packages/web/package-lock.json +++ b/packages/web/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@apollo/client": "3.7.14", "@github/text-expander-element": "^2.5.0", - "@journaly/j-db-client": "^13.20.0", + "@journaly/j-db-client": "^13.22.0", "@prisma/client": "^3.15.2", "@stripe/react-stripe-js": "^1.2.2", "@stripe/stripe-js": "^1.12.1", @@ -2747,9 +2747,9 @@ "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==" }, "node_modules/@journaly/j-db-client": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/@journaly/j-db-client/-/j-db-client-13.20.0.tgz", - "integrity": "sha512-azX4mKZhicDmomFZqtliVhRaEjlu2Y9gz9u+NkrN1epDewov4SvwAoSn98/90cRr6W2Vh6GbjfxjUddzs7YraQ==", + "version": "13.22.0", + "resolved": "https://registry.npmjs.org/@journaly/j-db-client/-/j-db-client-13.22.0.tgz", + "integrity": "sha512-yeqsGOHqf6KC39Up52cSXq/VxWo+MvzvBEqqllI30r6YigDBgXoO8PUYVZ+1UwSS6f9ssKsR/JY8UrB+oUQ84A==", "dependencies": { "@prisma/client": "^3.15.2" } @@ -20715,9 +20715,9 @@ "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==" }, "@journaly/j-db-client": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/@journaly/j-db-client/-/j-db-client-13.20.0.tgz", - "integrity": "sha512-azX4mKZhicDmomFZqtliVhRaEjlu2Y9gz9u+NkrN1epDewov4SvwAoSn98/90cRr6W2Vh6GbjfxjUddzs7YraQ==", + "version": "13.22.0", + "resolved": "https://registry.npmjs.org/@journaly/j-db-client/-/j-db-client-13.22.0.tgz", + "integrity": "sha512-yeqsGOHqf6KC39Up52cSXq/VxWo+MvzvBEqqllI30r6YigDBgXoO8PUYVZ+1UwSS6f9ssKsR/JY8UrB+oUQ84A==", "requires": { "@prisma/client": "^3.15.2" } diff --git a/packages/web/package.json b/packages/web/package.json index d9086453..da9aa363 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -43,7 +43,7 @@ "dependencies": { "@apollo/client": "3.7.14", "@github/text-expander-element": "^2.5.0", - "@journaly/j-db-client": "^13.20.0", + "@journaly/j-db-client": "^13.22.0", "@prisma/client": "^3.15.2", "@stripe/react-stripe-js": "^1.2.2", "@stripe/stripe-js": "^1.12.1", diff --git a/packages/web/resolvers/comment.ts b/packages/web/resolvers/comment.ts index 2a79ebe4..0f1bc3c4 100644 --- a/packages/web/resolvers/comment.ts +++ b/packages/web/resolvers/comment.ts @@ -25,6 +25,7 @@ import { ThreadWithRels, sendNewBadgeEmail, assignCountBadges, + getPostingIpAddress, } from './utils' import { NotFoundError } from './errors' @@ -41,7 +42,7 @@ const assignCommentCountBadges = async (db: PrismaClient, userId: number): Promi FROM "Comment" WHERE "authorId" = ${userId} ` - + const postCommentCountQuery = Prisma.sql` SELECT COUNT(*) AS count FROM "PostComment" @@ -184,10 +185,11 @@ type CreateCommentArg = { }> author: UserWithRels<{ languages: true }> body: string + postingIpAddress: string | undefined db: PrismaClient } -const createComment = async ({ db, thread, author, body }: CreateCommentArg) => { +const createComment = async ({ db, thread, author, body, postingIpAddress }: CreateCommentArg) => { const authorHasPostLanguage = author && author.languages.find((language) => language.languageId === thread.post.languageId) @@ -199,6 +201,7 @@ const createComment = async ({ db, thread, author, body }: CreateCommentArg) => data: { body, authorLanguageLevel, + postingIpAddress, author: { connect: { id: author.id }, }, @@ -363,11 +366,13 @@ const CommentMutations = extendType({ }, }) + const authorPostingIpAddress = getPostingIpAddress(ctx.request) await createComment({ db: ctx.db, thread, author, body, + postingIpAddress: authorPostingIpAddress, }) await assignCommentCountBadges(ctx.db, userId) @@ -453,13 +458,14 @@ const CommentMutations = extendType({ if (!author) { throw new NotFoundError('user') } - + const authorPostingIpAddress = getPostingIpAddress(ctx.request) const [comment, _] = await Promise.all([ createComment({ db: ctx.db, thread, author, body: args.body, + postingIpAddress: authorPostingIpAddress, }), assignCommentCountBadges(ctx.db, userId), ] as const) @@ -603,10 +609,13 @@ const CommentMutations = extendType({ const mentionedUserHandles = parseCommentBodyForMentions(args.body) + const authorPostingIpAddress = getPostingIpAddress(ctx.request) + const postComment = await ctx.db.postComment.create({ data: { body: args.body, authorLanguageLevel, + postingIpAddress: authorPostingIpAddress, author: { connect: { id: userId }, }, diff --git a/packages/web/resolvers/context.ts b/packages/web/resolvers/context.ts index f89e6c51..7e0954c8 100644 --- a/packages/web/resolvers/context.ts +++ b/packages/web/resolvers/context.ts @@ -1,8 +1,8 @@ import { PrismaClient } from '@journaly/j-db-client' import { IncomingMessage, ServerResponse } from 'http'; -interface Request extends IncomingMessage { - userId: number, +export interface Request extends IncomingMessage { + userId: number } diff --git a/packages/web/resolvers/post.ts b/packages/web/resolvers/post.ts index 353c3fba..b2876bcf 100644 --- a/packages/web/resolvers/post.ts +++ b/packages/web/resolvers/post.ts @@ -20,9 +20,9 @@ import { generatePostPrivateShareId, createInAppNotification, sendReportSpamPostEmail, + getPostingIpAddress, } from './utils' - import { NotFoundError, NotAuthorizedError, ResolverError } from './errors' import { Prisma, @@ -486,6 +486,7 @@ const PostMutations = extendType({ publishedAt: isPublished ? new Date() : null, bumpedAt: isPublished ? new Date() : null, publishedLanguageLevel: userLanguageLevel, + postingIpAddress: getPostingIpAddress(ctx.request), postCommentSubscriptions: { create: [ { diff --git a/packages/web/resolvers/utils/getPostingIpAddress.ts b/packages/web/resolvers/utils/getPostingIpAddress.ts new file mode 100644 index 00000000..4acc5047 --- /dev/null +++ b/packages/web/resolvers/utils/getPostingIpAddress.ts @@ -0,0 +1,15 @@ +import { NextRequest } from 'next/server' +import { Request } from '../context' + +const isNextRequest = (req: NextRequest | Request): req is NextRequest => { + return !!(req as NextRequest).ip +} + +export const getPostingIpAddress = (req: NextRequest | Request) => { + if (isNextRequest(req)) return req.ip + + const headers = req?.headers['X-Forwarded-For'] + if (typeof headers === 'string') return headers.split(',')?.[0] + + return undefined +} diff --git a/packages/web/resolvers/utils/index.ts b/packages/web/resolvers/utils/index.ts index d63cf9b5..df3a45a6 100644 --- a/packages/web/resolvers/utils/index.ts +++ b/packages/web/resolvers/utils/index.ts @@ -305,4 +305,5 @@ export * from './db' export * from './notifications' export * from './types' export * from './badges' +export * from './getPostingIpAddress' export type { NodeType }