forked from gothinkster/realworld
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from gothinkster/main
Merge from upstream
- Loading branch information
Showing
45 changed files
with
2,339 additions
and
1,081 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
web: cd apps/api && npx prisma generate && && pnpm build && pnpm start |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
//https://nitro.unjs.io/config | ||
export default defineNitroConfig({ | ||
srcDir: "server" | ||
srcDir: "server", | ||
preset: 'heroku', | ||
routeRules: { | ||
'/api/**': { cors: true, headers: { 'access-control-allow-methods': '*' } }, | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import {default as jwt} from "jsonwebtoken"; | ||
|
||
export interface PrivateContext { | ||
auth: { | ||
id: number; | ||
} | ||
} | ||
|
||
export function definePrivateEventHandler<T>( | ||
handler: (event: H3Event, cxt: PrivateContext) => T, | ||
options: { requireAuth: boolean } = {requireAuth: true} | ||
) { | ||
return defineEventHandler(async (event) => { | ||
// you can check request hmac, user, token, etc.. | ||
const header = getHeader(event, 'authorization'); | ||
let token; | ||
|
||
if ( | ||
(header && header.split(' ')[0] === 'Token') || | ||
(header && header.split(' ')[0] === 'Bearer') | ||
) { | ||
token = header.split(' ')[1]; | ||
} | ||
|
||
if (options.requireAuth && !token) { | ||
throw createError({ | ||
status: 401, | ||
statusMessage: 'Unauthorized', | ||
message: 'Missing authentication token' | ||
}); | ||
} | ||
|
||
if (token) { | ||
const verified = jwt.verify(token, process.env.JWT_SECRET); | ||
|
||
if (!verified) { | ||
throw createError({ | ||
status: 403, | ||
statusMessage: 'Unauthorized', | ||
message: 'Invalid authentication token' | ||
}); | ||
} | ||
|
||
return handler(event, { | ||
auth: { | ||
id: Number(verified.user.id) | ||
}, | ||
}) | ||
} else { | ||
return handler(event, { | ||
auth: null, | ||
}) | ||
} | ||
|
||
|
||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Comment } from './comment.model'; | ||
|
||
export interface Article { | ||
id: number; | ||
title: string; | ||
slug: string; | ||
description: string; | ||
comments: Comment[]; | ||
favorited: boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Article } from './article.model'; | ||
|
||
export interface Comment { | ||
id: number; | ||
createdAt: Date; | ||
updatedAt: Date; | ||
body: string; | ||
article?: Article; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
class HttpException extends Error { | ||
errorCode: number; | ||
constructor( | ||
errorCode: number, | ||
public readonly message: string | any, | ||
) { | ||
super(message); | ||
this.errorCode = errorCode; | ||
} | ||
} | ||
|
||
export default HttpException; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export interface Profile { | ||
username: string; | ||
bio: string; | ||
image: string; | ||
following: boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export interface Tag { | ||
name: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Article } from './article.model'; | ||
import { Comment } from './comment.model'; | ||
|
||
export interface User { | ||
id: number; | ||
username: string; | ||
email: string; | ||
password: string; | ||
bio: string | null; | ||
image: any | null; | ||
articles: Article[]; | ||
favorites: Article[]; | ||
followedBy: User[]; | ||
following: User[]; | ||
comments: Comment[]; | ||
demo: boolean; | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export default defineEventHandler(async (event) => { | ||
setResponseStatus(event, 200); | ||
return ""; | ||
}); |
39 changes: 39 additions & 0 deletions
39
apps/api/server/routes/api/articles/[slug]/comments/[id].delete.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import HttpException from "~/models/http-exception.model"; | ||
import {definePrivateEventHandler} from "~/auth-event-handler"; | ||
|
||
export default definePrivateEventHandler(async (event, {auth}) => { | ||
const id = Number(getRouterParam(event, 'id')); | ||
|
||
const comment = await usePrisma().comment.findFirst({ | ||
where: { | ||
id, | ||
author: { | ||
id: auth.id, | ||
}, | ||
}, | ||
select: { | ||
author: { | ||
select: { | ||
id: true, | ||
username: true, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
if (!comment) { | ||
throw new HttpException(404, {}); | ||
} | ||
|
||
if (comment.author.id !== auth.id) { | ||
throw new HttpException(403, { | ||
message: 'You are not authorized to delete this comment', | ||
}); | ||
} | ||
|
||
await usePrisma().comment.delete({ | ||
where: { | ||
id, | ||
}, | ||
}); | ||
}); |
60 changes: 60 additions & 0 deletions
60
apps/api/server/routes/api/articles/[slug]/comments/index.get.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import {definePrivateEventHandler} from "~/auth-event-handler"; | ||
|
||
export default definePrivateEventHandler(async (event, {auth}) => { | ||
const slug = getRouterParam(event, 'slug'); | ||
|
||
const queries = []; | ||
|
||
queries.push({ | ||
author: { | ||
demo: true, | ||
}, | ||
}); | ||
|
||
if (auth?.id) { | ||
queries.push({ | ||
author: { | ||
id: auth.id, | ||
}, | ||
}); | ||
} | ||
|
||
const comments = await usePrisma().article.findUnique({ | ||
where: { | ||
slug, | ||
}, | ||
include: { | ||
comments: { | ||
where: { | ||
OR: queries, | ||
}, | ||
select: { | ||
id: true, | ||
createdAt: true, | ||
updatedAt: true, | ||
body: true, | ||
author: { | ||
select: { | ||
username: true, | ||
bio: true, | ||
image: true, | ||
followedBy: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
const result = comments?.comments.map((comment: any) => ({ | ||
...comment, | ||
author: { | ||
username: comment.author.username, | ||
bio: comment.author.bio, | ||
image: comment.author.image, | ||
following: comment.author.followedBy.some((follow: any) => follow.id === auth.id), | ||
}, | ||
})); | ||
|
||
return {comments: result}; | ||
}, {requireAuth: false}); |
61 changes: 61 additions & 0 deletions
61
apps/api/server/routes/api/articles/[slug]/comments/index.post.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import HttpException from "~/models/http-exception.model"; | ||
import {definePrivateEventHandler} from "~/auth-event-handler"; | ||
|
||
export default definePrivateEventHandler(async (event, {auth}) => { | ||
const {comment} = await readBody(event); | ||
const slug = getRouterParam(event, 'slug'); | ||
|
||
if (!comment.body) { | ||
throw new HttpException(422, {errors: {body: ["can't be blank"]}}); | ||
} | ||
|
||
const article = await usePrisma().article.findUnique({ | ||
where: { | ||
slug, | ||
}, | ||
select: { | ||
id: true, | ||
}, | ||
}); | ||
|
||
const createdComment = await usePrisma().comment.create({ | ||
data: { | ||
body: comment.body, | ||
article: { | ||
connect: { | ||
id: article?.id, | ||
}, | ||
}, | ||
author: { | ||
connect: { | ||
id: auth.id, | ||
}, | ||
}, | ||
}, | ||
include: { | ||
author: { | ||
select: { | ||
username: true, | ||
bio: true, | ||
image: true, | ||
followedBy: true, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
return { | ||
comment: { | ||
id: createdComment.id, | ||
createdAt: createdComment.createdAt, | ||
updatedAt: createdComment.updatedAt, | ||
body: createdComment.body, | ||
author: { | ||
username: createdComment.author.username, | ||
bio: createdComment.author.bio, | ||
image: createdComment.author.image, | ||
following: createdComment.author.followedBy.some((follow: any) => follow.id === auth.id), | ||
}, | ||
} | ||
}; | ||
}); |
51 changes: 51 additions & 0 deletions
51
apps/api/server/routes/api/articles/[slug]/favorite/index.delete.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import profileMapper from "~/utils/profile.utils"; | ||
import {Tag} from "~/models/tag.model"; | ||
import {definePrivateEventHandler} from "~/auth-event-handler"; | ||
|
||
export default definePrivateEventHandler(async (event, {auth}) => { | ||
const slug = getRouterParam(event, "slug"); | ||
|
||
const { _count, ...article } = await usePrisma().article.update({ | ||
where: { | ||
slug, | ||
}, | ||
data: { | ||
favoritedBy: { | ||
disconnect: { | ||
id: auth.id, | ||
}, | ||
}, | ||
}, | ||
include: { | ||
tagList: { | ||
select: { | ||
name: true, | ||
}, | ||
}, | ||
author: { | ||
select: { | ||
username: true, | ||
bio: true, | ||
image: true, | ||
followedBy: true, | ||
}, | ||
}, | ||
favoritedBy: true, | ||
_count: { | ||
select: { | ||
favoritedBy: true, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
const result = { | ||
...article, | ||
author: profileMapper(article.author, auth.id), | ||
tagList: article?.tagList.map((tag: Tag) => tag.name), | ||
favorited: article.favoritedBy.some((favorited: any) => favorited.id === auth.id), | ||
favoritesCount: _count?.favoritedBy, | ||
}; | ||
|
||
return {article: result}; | ||
}); |
Oops, something went wrong.