PROGRAMING/FULL STACK

[Auth] Protecting the upvote and comment endpoints

donghunl 2024. 3. 26. 10:07
반응형

이제 본격적으로 좋아요를 한번 클릭 할수 있고 댓글을 사용자 인증이 된 상태에서만 될수 있도록 리팩토링을 해보겠습니다. 먼저 사용자가 아직 로그인 하지 않은 경우 사용자가 위의 엔드포인트에 요청할수 없도로 위의 두 경로(put upvote request, post comment request)에만 적용되는 또 다른 미들웨어를 추가 해줍니다.

그리고 좋아요 upvote에는 좋아요 버튼을 누른 사용자의 id를 데이터베이스에 같이 저장하는 작업을 합니다.

그리고 댓글 comment에는 이름과 댓글이외에 email 정보도 함께 추가합니다.

변경된 코드는 다음과 같습니다.

server.js

import fs from 'fs';
import admin, { auth } from 'firebase-admin';
import express from 'express';
import { db, connectToDb } from './db.js';

const credentials = JSON.parse(
    fs.readFileSync('../credentials.json')
);
admin.initializeApp({
    credential: admin.credential.cert(credentials),
});

const app = express();
app.use(express.json());

app.use(async (req, res, next) => {
    const { authtoken } = req.headers;

    if (authtoken) {
        try {
            req.user = await admin.auth().verifyIdToken(authtoken);
        } catch (e) {
            res.sendStatus(400);
        }
    }

    next();
});

app.get('/api/articles/:name', async (req, res) => {
    const { name } = req.params;
    const { uid } = req.user;

    const article = await db.collection('articles').findOne({ name });

    if (article) {
        const upvoteIds = article.upvoteIds || [];
        article.canUpvote = uid && !upvoteIds.include(uid);
        res.json(article);
    } else {
        res.sendStatus(404);
    }
});

// check user login status
app.use((req, res, next) => {
    if (req.user) {
        next();
    } else {
        res.sendStatus(401); // not allow to access
    }
});

app.put('/api/articles/:name/upvote', async (req, res) => {
    const { name } = req.params;
    const { uid } = req.user;

    const article = await db.collection('articles').findOne({ name });

    if (article) {
        const upvoteIds = article.upvoteIds || [];
        const canUpvote = uid && !upvoteIds.include(uid);

        if (canUpvote) {
            await db.collection('articles').updateOne({ name }, {
                $inc: { upvotes: 1 },
                $push: { upvoteIds: uid }, // add upvote user id
            });
        }

        const updatedArticle = await db.collection('articles').findOne({ name });
        res.json(updatedArticle);
    } else {
        res.send('That article doesn\'t exist');
    }
});

app.post('/api/articles/:name/comments', async (req, res) => {
    const { name } = req.params;
    const { text } = req.body;
    const { email } = req.user; // add email

    await db.collection('articles').updateOne({ name }, {
        $push: { comments: { postedBy: email, text } }, // add email
    });
    const article = await db.collection('articles').findOne({ name });

    if (article) {
        res.json(article);
    } else {
        res.send('That article doesn\'t exist!');
    }
});

connectToDb(() => {
    console.log('Successfully connected to database!');
    app.listen(8000, () => {
        console.log('Server is listening on port 8000');
    });
})

 

반응형