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
29 changes: 3 additions & 26 deletions src/backend/src/content/content/content.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Content, Prisma } from "@prisma/client";
import { OrderByArg } from "src/common/object/order-by-arg.object";
import { NotFoundException } from "src/common/exception/not-found.exception";
import { PrismaService } from "src/prisma";
import { DEFAULT_CONTENT_ORDER_BY } from "../shared/constants";
import {
ContentListFilter,
ContentsFilter,
Expand Down Expand Up @@ -66,19 +67,7 @@ export class ContentService {
return orderBy.map((order) => ({ [order.field]: order.order }));
}

return [
{
contentCategory: {
id: "asc",
},
},
{
level: "asc",
},
{
id: "asc",
},
];
return DEFAULT_CONTENT_ORDER_BY;
}

async createContent(input: CreateContentInput): Promise<CreateContentResult> {
Expand Down Expand Up @@ -153,19 +142,7 @@ export class ContentService {

async findContents(filter?: ContentsFilter): Promise<Content[]> {
return await this.prisma.content.findMany({
orderBy: [
{
contentCategory: {
id: "asc",
},
},
{
level: "asc",
},
{
id: "asc",
},
],
orderBy: DEFAULT_CONTENT_ORDER_BY,
where: this.buildContentsWhere(filter),
});
}
Expand Down
15 changes: 2 additions & 13 deletions src/backend/src/content/group/group.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ValidationException } from "src/common/exception";
import { OrderByArg } from "src/common/object/order-by-arg.object";
import { PrismaService } from "src/prisma";
import { UserContentService } from "src/user/service/user-content.service";
import { DEFAULT_CONTENT_ORDER_BY } from "../shared/constants";
import { ContentWageService } from "../wage/wage.service";
import { ContentGroupFilter, ContentGroupWageListFilter } from "./group.dto";
import { ContentGroup, ContentGroupWage } from "./group.object";
Expand Down Expand Up @@ -171,19 +172,7 @@ export class GroupService {
}

private getContentOrderBy(): Prisma.ContentOrderByWithRelationInput[] {
return [
{
contentCategory: {
id: "asc",
},
},
{
level: "asc",
},
{
id: "asc",
},
];
return DEFAULT_CONTENT_ORDER_BY;
}

private sortResults(results: ContentGroupWage[], orderBy: OrderByArg[]): ContentGroupWage[] {
Expand Down
14 changes: 14 additions & 0 deletions src/backend/src/content/shared/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
import { Prisma } from "@prisma/client";

/**
* Content 기본 정렬 순서
* - 카테고리 ID 오름차순
* - 레벨 오름차순
* - ID 오름차순
*/
export const DEFAULT_CONTENT_ORDER_BY: Prisma.ContentOrderByWithRelationInput[] = [
{ contentCategory: { id: "asc" } },
{ level: "asc" },
{ id: "asc" },
];

// 추후 유지보수성이 확실치 않은 데이터 구조 및 순서라 db에서 관리하지 않고 임시로 상수로 보상 아이템 순서를 관리함.
export const ItemSortOrder = {
"1레벨 보석": 7,
Expand Down
119 changes: 48 additions & 71 deletions src/backend/src/content/wage/wage.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,21 @@ type Reward = {
itemId: number;
};

type WageFilter = {
includeBound?: boolean;
includeItemIds?: number[];
includeSeeMore?: boolean;
};

type ContentWageData = {
duration: number;
gold: number;
};

@Injectable()
export class ContentWageService {
private static readonly SECONDS_PER_HOUR = 3600;

constructor(
private userContentService: UserContentService,
private userGoldExchangeRateService: UserGoldExchangeRateService,
Expand Down Expand Up @@ -57,7 +70,7 @@ export class ContentWageService {

const totalKRW = (gold * goldExchangeRate.krwAmount) / goldExchangeRate.goldAmount;

const hours = duration / 3600;
const hours = duration / ContentWageService.SECONDS_PER_HOUR;
const hourlyWage = totalKRW / hours;
const hourlyGold = gold / hours;

Expand All @@ -67,77 +80,47 @@ export class ContentWageService {
};
}

async getContentGroupWage(
contentIds: number[],
userId: number | undefined,
filter: {
includeBound?: boolean;
includeItemIds?: number[];
includeSeeMore?: boolean;
}
) {
let totalGold = 0;
let totalDuration = 0;

for (const contentId of contentIds) {
const content = await this.prisma.content.findUniqueOrThrow({
where: { id: contentId },
});

const rewards = await this.userContentService.getContentRewards(content.id, userId, {
includeBound: filter?.includeBound,
includeItemIds: filter?.includeItemIds,
});

const seeMoreRewards = await this.userContentService.getContentSeeMoreRewards(
content.id,
userId,
{
includeItemIds: filter?.includeItemIds,
}
);

const rewardsGold = await this.calculateGold(rewards, userId);
async getContentGroupWage(contentIds: number[], userId: number | undefined, filter: WageFilter) {
const dataList = await Promise.all(
contentIds.map((id) => this.calculateContentWageData(id, userId, filter))
);

const shouldIncludeSeeMoreRewards =
filter?.includeSeeMore && filter?.includeBound !== false && seeMoreRewards.length > 0;
const totalGold = dataList.reduce((sum, data) => sum + data.gold, 0);
const totalDuration = dataList.reduce((sum, data) => sum + data.duration, 0);

const seeMoreGold = shouldIncludeSeeMoreRewards
? await this.calculateSeeMoreRewardsGold(seeMoreRewards, userId, filter.includeItemIds)
: 0;
const { goldAmountPerHour, krwAmountPerHour } = await this.calculateWage(
{ duration: totalDuration, gold: totalGold },
userId
);

const gold = rewardsGold + seeMoreGold;
totalGold += gold;
return {
goldAmountPerClear: Math.round(totalGold),
goldAmountPerHour,
krwAmountPerHour,
};
}

const duration = await this.userContentService.getContentDuration(content.id, userId);
totalDuration += duration;
}
async getContentWage(contentId: number, userId: number | undefined, filter: WageFilter) {
const { duration, gold } = await this.calculateContentWageData(contentId, userId, filter);

const { goldAmountPerHour, krwAmountPerHour } = await this.calculateWage(
{
duration: totalDuration,
gold: totalGold,
},
{ duration, gold },
userId
);

return {
goldAmountPerClear: Math.round(totalGold),
contentId,
goldAmountPerClear: Math.round(gold),
goldAmountPerHour,
krwAmountPerHour,
};
}

// TODO: test
async getContentWage(
private async calculateContentWageData(
contentId: number,
userId: number | undefined,
filter: {
includeBound?: boolean;
includeItemIds?: number[];
includeSeeMore?: boolean;
}
) {
filter: WageFilter
): Promise<ContentWageData> {
const content = await this.prisma.content.findUniqueOrThrow({
where: { id: contentId },
});
Expand All @@ -157,30 +140,24 @@ export class ContentWageService {

const rewardsGold = await this.calculateGold(rewards, userId);

const shouldIncludeSeeMoreRewards =
filter?.includeSeeMore && filter?.includeBound !== false && seeMoreRewards.length > 0;
const shouldIncludeSeeMoreRewards = this.shouldIncludeSeeMore(filter, seeMoreRewards);

const seeMoreGold = shouldIncludeSeeMoreRewards
? await this.calculateSeeMoreRewardsGold(seeMoreRewards, userId, filter.includeItemIds)
: 0;

const gold = rewardsGold + seeMoreGold;

const duration = await this.userContentService.getContentDuration(content.id, userId);

const { goldAmountPerHour, krwAmountPerHour } = await this.calculateWage(
{
duration,
gold,
},
userId
);
return { duration, gold };
}

return {
contentId: content.id,
goldAmountPerClear: Math.round(gold),
goldAmountPerHour,
krwAmountPerHour,
};
private shouldIncludeSeeMore(
filter: WageFilter,
seeMoreRewards: { itemId: number; quantity: number }[]
): boolean {
return (
filter?.includeSeeMore === true && filter?.includeBound !== false && seeMoreRewards.length > 0
);
}
}
Loading
Loading