Skip to content

Commit

Permalink
first version
Browse files Browse the repository at this point in the history
  • Loading branch information
amandal-cn committed Nov 7, 2024
1 parent 8c35ec2 commit 8e50264
Show file tree
Hide file tree
Showing 37 changed files with 5,527 additions and 335 deletions.
50 changes: 50 additions & 0 deletions app/api/articles/[slug]/comments/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { NextRequest, NextResponse } from 'next/server';
import { getDb } from '@/app/lib/db';
import { getUser } from '@/app/lib/auth';

export async function DELETE(
request: NextRequest,
{ params }: { params: { slug: string; id: string } }
) {
try {
const currentUser = await getUser();
if (!currentUser) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Authorization required'] } }),
{ status: 401 }
);
}

const db = await getDb();
const { slug, id } = params;

const article = await db.get('SELECT id FROM articles WHERE slug = ?', [slug]);
if (!article) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Article not found'] } }),
{ status: 404 }
);
}

const comment = await db.get(
'SELECT * FROM comments WHERE id = ? AND article_id = ? AND author_id = ?',
[id, article.id, currentUser.id]
);

if (!comment) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Comment not found or unauthorized'] } }),
{ status: 404 }
);
}

await db.run('DELETE FROM comments WHERE id = ?', [id]);

return new NextResponse(null, { status: 204 });
} catch (error) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Could not delete comment'] } }),
{ status: 422 }
);
}
}
138 changes: 138 additions & 0 deletions app/api/articles/[slug]/comments/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { NextRequest, NextResponse } from 'next/server';
import { getDb } from '@/app/lib/db';
import { getUser } from '@/app/lib/auth';

export async function GET(
request: NextRequest,
{ params }: { params: { slug: string } }
) {
try {
const db = await getDb();
const { slug } = params;

const article = await db.get('SELECT id FROM articles WHERE slug = ?', [slug]);
if (!article) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Article not found'] } }),
{ status: 404 }
);
}

const comments = await db.all(`
SELECT
c.id, c.body, c.created_at as createdAt, c.updated_at as updatedAt,
u.username, u.bio, u.image
FROM comments c
JOIN users u ON c.author_id = u.id
WHERE c.article_id = ?
ORDER BY c.created_at DESC
`, [article.id]);

const currentUser = await getUser();
const commentsWithAuthor = await Promise.all(
comments.map(async (comment: any) => {
let following = false;
if (currentUser) {
const follow = await db.get(
'SELECT 1 FROM follows WHERE follower_id = ? AND followed_id = (SELECT id FROM users WHERE username = ?)',
[currentUser.id, comment.username]
);
following = !!follow;
}

return {
id: comment.id,
createdAt: comment.createdAt,
updatedAt: comment.updatedAt,
body: comment.body,
author: {
username: comment.username,
bio: comment.bio,
image: comment.image,
following
}
};
})
);

return new NextResponse(
JSON.stringify({ comments: commentsWithAuthor })
);
} catch (error) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Could not get comments'] } }),
{ status: 422 }
);
}
}

export async function POST(
request: NextRequest,
{ params }: { params: { slug: string } }
) {
try {
const currentUser = await getUser();
if (!currentUser) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Authorization required'] } }),
{ status: 401 }
);
}

const db = await getDb();
const { slug } = params;
const { comment } = await request.json();

if (!comment.body) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Comment body is required'] } }),
{ status: 422 }
);
}

const article = await db.get('SELECT id FROM articles WHERE slug = ?', [slug]);
if (!article) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Article not found'] } }),
{ status: 404 }
);
}

const result = await db.run(
'INSERT INTO comments (body, article_id, author_id) VALUES (?, ?, ?)',
[comment.body, article.id, currentUser.id]
);

const createdComment = await db.get(`
SELECT
c.id, c.body, c.created_at as createdAt, c.updated_at as updatedAt,
u.username, u.bio, u.image
FROM comments c
JOIN users u ON c.author_id = u.id
WHERE c.id = ?
`, [result.lastID]);

return new NextResponse(
JSON.stringify({
comment: {
id: createdComment.id,
createdAt: createdComment.createdAt,
updatedAt: createdComment.updatedAt,
body: createdComment.body,
author: {
username: createdComment.username,
bio: createdComment.bio,
image: createdComment.image,
following: false
}
}
}),
{ status: 201 }
);
} catch (error) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Could not create comment'] } }),
{ status: 422 }
);
}
}
106 changes: 106 additions & 0 deletions app/api/articles/[slug]/favorite/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { NextRequest, NextResponse } from 'next/server';
import { getDb } from '@/app/lib/db';
import { getUser } from '@/app/lib/auth';

async function getArticleResponse(db: any, slug: string, currentUser: any) {
const article = await db.get(`
SELECT articles.*, users.username, users.bio, users.image,
(SELECT COUNT(*) FROM favorites WHERE article_id = articles.id) as favoritesCount,
EXISTS(SELECT 1 FROM favorites WHERE article_id = articles.id AND user_id = ?) as favorited
FROM articles
LEFT JOIN users ON articles.author_id = users.id
WHERE slug = ?
`, [currentUser.id, slug]);

if (!article) return null;

return {
article: {
...article,
favorited: Boolean(article.favorited),
author: {
username: article.username,
bio: article.bio,
image: article.image,
}
}
};
}

export async function POST(
request: NextRequest,
{ params }: { params: { slug: string } }
) {
try {
const currentUser = await getUser();
if (!currentUser) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Authorization required'] } }),
{ status: 401 }
);
}

const db = await getDb();
const { slug } = params;

const article = await db.get('SELECT * FROM articles WHERE slug = ?', [slug]);
if (!article) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Article not found'] } }),
{ status: 404 }
);
}

await db.run(
'INSERT OR IGNORE INTO favorites (user_id, article_id) VALUES (?, ?)',
[currentUser.id, article.id]
);

const response = await getArticleResponse(db, slug, currentUser);
return NextResponse.json(response);
} catch (error) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Could not favorite article'] } }),
{ status: 422 }
);
}
}

export async function DELETE(
request: NextRequest,
{ params }: { params: { slug: string } }
) {
try {
const currentUser = await getUser();
if (!currentUser) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Authorization required'] } }),
{ status: 401 }
);
}

const db = await getDb();
const { slug } = params;

const article = await db.get('SELECT * FROM articles WHERE slug = ?', [slug]);
if (!article) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Article not found'] } }),
{ status: 404 }
);
}

await db.run(
'DELETE FROM favorites WHERE user_id = ? AND article_id = ?',
[currentUser.id, article.id]
);

const response = await getArticleResponse(db, slug, currentUser);
return NextResponse.json(response);
} catch (error) {
return new NextResponse(
JSON.stringify({ errors: { body: ['Could not unfavorite article'] } }),
{ status: 422 }
);
}
}
Loading

0 comments on commit 8e50264

Please sign in to comment.