Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions prisma/migrations/20250803113800_badge/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Warnings:

- A unique constraint covering the columns `[type,threshold]` on the table `badges` will be added. If there are existing duplicate values, this will fail.
- Added the required column `threshold` to the `badges` table without a default value. This is not possible if the table is not empty.
- Added the required column `type` to the `badges` table without a default value. This is not possible if the table is not empty.

*/
-- AlterTable
ALTER TABLE `badges` ADD COLUMN `badge_image` VARCHAR(255) NULL,
ADD COLUMN `threshold` INTEGER NOT NULL,
ADD COLUMN `type` VARCHAR(100) NOT NULL;

-- CreateTable
CREATE TABLE `user_badges` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`account_id` BIGINT NOT NULL,
`badge_id` BIGINT NOT NULL,
`earned_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),

UNIQUE INDEX `user_badges_account_id_badge_id_key`(`account_id`, `badge_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- CreateIndex
CREATE UNIQUE INDEX `badges_type_threshold_key` ON `badges`(`type`, `threshold`);

-- AddForeignKey
ALTER TABLE `user_badges` ADD CONSTRAINT `user_badges_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `user_badges` ADD CONSTRAINT `user_badges_badge_id_fkey` FOREIGN KEY (`badge_id`) REFERENCES `badges`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
24 changes: 22 additions & 2 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ model Account {
userAgreements UserAgreement[]
userCategories UserCategory[]
follows Follow[]
userBadges UserBadge[]

@@unique([provider, oauthId])
@@map("accounts")
Expand Down Expand Up @@ -348,12 +349,31 @@ model UserAgreement {
}

model Badge {
id BigInt @id @default(autoincrement())
name String @db.VarChar(100)
id BigInt @id @default(autoincrement())
type String @db.VarChar(100)
threshold Int
name String @db.VarChar(100)
badgeImage String? @map("badge_image") @db.VarChar(255)

userBadges UserBadge[]

@@unique([type, threshold])
@@map("badges")
}

model UserBadge {
id BigInt @id @default(autoincrement())
accountId BigInt @map("account_id")
badgeId BigInt @map("badge_id")
earnedAt DateTime @default(now()) @map("earned_at")

account Account @relation(fields: [accountId], references: [id])
badge Badge @relation(fields:[badgeId], references:[id])

@@unique([accountId, badgeId])
@@map("user_badges")
}

model Session {
id String @id
sid String @unique
Expand Down
107 changes: 107 additions & 0 deletions prisma/seed.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,113 @@ async function main() {
},
});

const badges = await prisma.badge.createMany({
data:[
{
name: "์ฒซ ์ปค๋ฏธ์…˜ ์™„๋ฃŒ!",
type: "comm_finish",
threshold: 1,
badgeImage: "https://example.com/badge_comm1.png",
},
{
name: "5ํšŒ ์ปค๋ฏธ์…˜ ์™„๋ฃŒ!",
type: "comm_finish",
threshold: 5,
badgeImage: "https://example.com/badge_comm5.png",
},
{
name: "15ํšŒ ์ปค๋ฏธ์…˜ ์™„๋ฃŒ!",
type: "comm_finish",
threshold: 15,
badgeImage: "https://example.com/badge_comm15.png",
},
{
name: "50ํšŒ ์ปค๋ฏธ์…˜ ์™„๋ฃŒ!",
type: "comm_finish",
threshold: 50,
badgeImage: "https://example.com/badge_com50.png",
},
{
name: "์ฒซ ํŒ”๋กœ์šฐ ์™„๋ฃŒ!",
type: "follow",
threshold: 1,
badgeImage: "https://example.com/badge_follow1.png",
},
{
name: "ํŒ”๋กœ์šฐ 5ํšŒ!",
type: "follow",
threshold: 5,
badgeImage: "https://example.com/badge_follow5.png",
},
{
name: "ํŒ”๋กœ์šฐ 15ํšŒ!",
type: "follow",
threshold: 15,
badgeImage: "https://example.com/badge_follow15.png",
},
{
name: "ํŒ”๋กœ์šฐ 50ํšŒ!",
type: "follow",
threshold: 50,
badgeImage: "https://example.com/badge_follow50.png",
},
{
name: "์ฒซ ํ›„๊ธฐ ์ž‘์„ฑ ์™„๋ฃŒ!",
type: "review",
threshold: 1,
badgeImage: "https://example.com/badge_review1.png",
},
{
name: "5ํšŒ ํ›„๊ธฐ ์ž‘์„ฑ!",
type: "review",
threshold: 5,
badgeImage: "https://example.com/badge_review5.png",
},
{
name: "15ํšŒ ํ›„๊ธฐ ์ž‘์„ฑ!",
type: "review",
threshold: 15,
badgeImage: "https://example.com/badge_review15.png",
},
{
name: "50ํšŒ ํ›„๊ธฐ ์ž‘์„ฑ!",
type: "review",
threshold: 50,
badgeImage: "https://example.com/badge_review50.png",
},
{
name: "์ฒซ ์ปค๋ฏธ์…˜ ์‹ ์ฒญ ์™„๋ฃŒ!",
type: "comm_request",
threshold: 1,
badgeImage: "https://example.com/badge_request1.png",
},
{
name: "5ํšŒ ์ปค๋ฏธ์…˜ ์‹ ์ฒญ ์™„๋ฃŒ!",
type: "comm_request",
threshold: 5,
badgeImage: "https://example.com/badge_request5.png",
},
{
name: "15ํšŒ ์ปค๋ฏธ์…˜ ์‹ ์ฒญ ์™„๋ฃŒ!",
type: "comm_request",
threshold: 15,
badgeImage: "https://example.com/badge_request15.png",
},
{
name: "50ํšŒ ์ปค๋ฏธ์…˜ ์‹ ์ฒญ ์™„๋ฃŒ!",
type: "comm_request",
threshold: 50,
badgeImage: "https://example.com/badge_request50.png",
},
{
name: "๊ฐ€์ž… 1์ฃผ๋…„!",
type: "signup_1year",
threshold: 50,
badgeImage: "https://example.com/badge_signup_1year.png",
},
]
})

console.log("โœ… Seed completed successfully.");
}

Expand Down
2 changes: 2 additions & 0 deletions src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import paymentRouter from "./payment/payment.routes.js"
import pointRouter from "./point/point.routes.js"
import requestRouter from "./request/request.routes.js"
import homeRouter from "./home/home.routes.js"
import artistRouter from "./user/artist.routes.js"
import tokenRouter from "./token.routes.js"

const router = express.Router();
Expand All @@ -19,6 +20,7 @@ router.use("/", bookmarkRouter);
router.use("/search", searchRouter)
router.use("/commissions", commissionRouter);
router.use("/users", userRouter);
router.use("/artists", artistRouter);
router.use("/reviews", reviewRouter);
router.use("/notifications", notificationRouter);
router.use("/payments", paymentRouter);
Expand Down
12 changes: 12 additions & 0 deletions src/user/artist.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import express from "express";
import { AccessArtistProfile } from "./controller/user.controller.js";
import { authenticate } from "../middlewares/auth.middleware.js";

const router = express.Router();


// ์ž‘๊ฐ€ ํ”„๋กœํ•„ ์กฐํšŒ
router.get("/:artistId", authenticate,AccessArtistProfile );


export default router;
33 changes: 32 additions & 1 deletion src/user/controller/user.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,35 @@ export const LookUserFollow = async(req, res, next) => {
}catch(err) {
next(err);
}
}
}

// ์‚ฌ์šฉ์ž์˜ ๋ฑƒ์ง€ ์กฐํšŒํ•˜๊ธฐ
export const LookUserBadge = async(req, res, next) => {
try{
console.log("๐ŸŽ–๏ธDecoded JWT from req.user:", req.user);

const accountId = req.user.accountId.toString();
console.log("์‚ฌ์šฉ์ž์˜ ๋ฑƒ์ง€ ์กฐํšŒ accountId -> ", accountId);

const result = await UserService.ViewUserBadge(accountId);

res.status(StatusCodes.OK).success(result);
}catch(err) {
next(err);
}
}

// ์ž‘๊ฐ€ ํ”„๋กœํ•„ ์กฐํšŒํ•˜๊ธฐ
export const AccessArtistProfile = async(req, res, next) => {
try{
const artistId = req.params.artistId;
const accountId = req.user.accountId;

const result = await UserService.AccessArtistProfile(artistId, accountId);

res.status(StatusCodes.OK).success(result);
} catch(err) {
next(err);
}
}

63 changes: 63 additions & 0 deletions src/user/repository/badge.repository.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { prisma } from "../../db.config.js"

export const BadgeRepository = {
// type๊ณผ progress๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฐœ๊ธ‰ ๊ฐ€๋Šฅํ•œ ๋ฑƒ์ง€๋ฅผ ์กฐํšŒํ•˜๊ธฐ
async findEligibleBadgesByProgress(type, progress) {
return await prisma.badge.findMany({
where: {
type,
threshold:{
lte:progress,
},
},
orderBy:{
threshold:"asc"
}
});
},
// ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋ฑƒ์ง€๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ•œ ๋ฒˆ์— ๋ฐœ๊ธ‰ํ•˜๊ธฐ
async createManyUserBadges(accountId, badgeIds){
if(!badgeIds.length) return;

const data=badgeIds.map((badgeId)=> ({
accountId,
badgeId,
earnedAt: new Date(),
}));

return await prisma.userBadge.createMany({
data,
skipDuplicates:true, // ๊ฐ™์€ ๋ฑƒ์ง€ ์ค‘๋ณต ๋ฐœ๊ธ‰ ๋ฐฉ์ง€
})
},
// ์‚ฌ์šฉ์ž์˜ ๋ฑƒ์ง€ ์กฐํšŒํ•˜๊ธฐ
async ViewUserBadges(accountId){
return await prisma.userBadge.findMany({
where:{
accountId,
},
include:{
badge:true,
},
orderBy:{
earnedAt:'desc',
}
});
},
// ์ž‘๊ฐ€ ๋ฑƒ์ง€ ์กฐํšŒํ•˜๊ธฐ
async ViewArtistBadges(accountId){
return await prisma.userBadge.findMany({
where:{
accountId,
},
include:{
badge:true,
},
orderBy:{
earnedAt:'desc',
}
});
}

};

Loading