Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
5e77cc5
feat: add achievements in user info page
Hazel-Lin Apr 2, 2024
e5825de
fix: update achievement card
Hazel-Lin Apr 3, 2024
9494076
fix: update set achievement page
Hazel-Lin Apr 3, 2024
3b0a5bf
fix: update setAchievementActive function
Hazel-Lin Apr 3, 2024
aee654f
Merge branch 'feat/achievements' of github.com:Hazel-Lin/earthworm in…
Hazel-Lin Apr 3, 2024
d874ee7
fix: update display of setAchievement page
Hazel-Lin Apr 3, 2024
63a7f40
feat: addAchievementsApi
Torstentjh Apr 4, 2024
a4e85e8
fix: achievefeature
Torstentjh Apr 4, 2024
113741c
chore: fix typos
Hazel-Lin Apr 4, 2024
c8e6a3b
fix: update setAchievement page
Hazel-Lin Apr 4, 2024
c628f30
fix: update achievement api
Hazel-Lin Apr 4, 2024
33b04ec
fix: update set achievement api
Hazel-Lin Apr 4, 2024
0c75990
fix: update achievement in user info page
Hazel-Lin Apr 4, 2024
a25247f
fix: achievefeature
Torstentjh Apr 5, 2024
c7328c3
fix: achievefeature
Torstentjh Apr 5, 2024
bbbf204
fix: update resetForm function
Hazel-Lin Apr 5, 2024
fe19e1c
Merge branch 'feat/achievements' of github.com:Hazel-Lin/earthworm in…
Hazel-Lin Apr 5, 2024
0af1018
fix: update achievement api
Hazel-Lin Apr 6, 2024
c9ad1b6
fix: update style in achievement card
Hazel-Lin Apr 6, 2024
8d282db
fix: update setAchievementActive function
Hazel-Lin Apr 6, 2024
a4a93c8
fix: Merge branch 'main' into feat/achievements
Hazel-Lin Apr 6, 2024
2041b94
fix: add achievement in info page
Hazel-Lin Apr 6, 2024
e96d0f1
fix: achievementStyle
Torstentjh Apr 6, 2024
3ea68ea
fix: updated the verification of phone
Hazel-Lin Apr 6, 2024
c0f82f4
style: updated the style of setAchievement page
Hazel-Lin Apr 6, 2024
399e4e6
style: updated the style of achievement card
Hazel-Lin Apr 6, 2024
d4f9132
style: updated the style of achievement card
Hazel-Lin Apr 6, 2024
4ffecc3
fix: updated api prompt
Hazel-Lin Apr 6, 2024
85f5f58
fix: updated styles achievement in info page
Hazel-Lin Apr 6, 2024
6a417f9
fix: updated useAchievement func
Hazel-Lin Apr 6, 2024
59c06cf
fix: achievementStyle
Torstentjh Apr 6, 2024
35b6eae
fix: updated style of achievement card
Hazel-Lin Apr 6, 2024
8312cd6
fix: updated useAchievement func
Hazel-Lin Apr 6, 2024
78675fe
fix: updated achievement type in the info page
Hazel-Lin Apr 6, 2024
2dc6361
fix: updated achievement func
Hazel-Lin Apr 6, 2024
a7dbca8
fix: updated achievement func
Hazel-Lin Apr 6, 2024
fd4a26c
fix: update validation for phone
Hazel-Lin Apr 7, 2024
7d78a48
chore: formatting code for achievement page
Hazel-Lin Apr 7, 2024
e46eca0
Merge branch 'main' into feat/achievements
Hazel-Lin Apr 7, 2024
33557e5
feat: update achievement logo in share page
Hazel-Lin Apr 7, 2024
046d47e
chore: delete code
Hazel-Lin Apr 8, 2024
ceb0500
fix: update the client test file about the sharing function
Hazel-Lin Apr 8, 2024
538b2c2
chore: rename code
Hazel-Lin Apr 8, 2024
3b594fa
feat(client): add test file for achievement
Hazel-Lin Apr 8, 2024
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
44 changes: 44 additions & 0 deletions apps/api/src/achievement/achievement.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
import { AuthGuard } from 'src/auth/auth.guard';
import { AchieveService } from './achievement.service';
import {
FindUserDto,
UserAchievementDto,
publishAchievementDto,
setAchievementDto,
} from './model/pub.dto';
@Controller('achievement')
export class AchievementController {
constructor(private readonly AchieveService: AchieveService) {}

// @UseGuards(PubAchievementGuard)
@Post('/publish')
async publishAchievement(@Body() dto: publishAchievementDto) {
return this.AchieveService.PubAchievement(dto);
}
// @UseGuards(AuthGuard)
@Get('/list')
async allAchievement() {
return this.AchieveService.AllAchievement();
}

@Post('/authUser')
async authUser(@Body() dto: FindUserDto) {
return this.AchieveService.authUser(dto);
}
@UseGuards(AuthGuard)
@Post('/set')
async setAchievement(@Body() dto: setAchievementDto) {
return this.AchieveService.setAchievement(dto);
}
@UseGuards(AuthGuard)
@Post('/use')
async useAchievement(@Body() dto: UserAchievementDto) {
return this.AchieveService.useAchievement(dto);
}
@UseGuards(AuthGuard)
@Post('/allHave')
async haveAchievement(@Body() dto: UserAchievementDto) {
return this.AchieveService.haveAchievement(dto);
}
}
16 changes: 16 additions & 0 deletions apps/api/src/achievement/achievement.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';

@Injectable()
export class PubAchievementGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean | Promise<boolean> {
const request = context.switchToHttp().getRequest();
const secretKey = request.body.secretKey; // 获取请求体中的密钥值
const compareKey = process.env.PubsecretKey; // 获取环境变量中的密钥值
// 在这里进行密钥验证逻辑
if (secretKey === compareKey) {
return true; // 密钥验证通过,允许使用功能
} else {
return false; // 密钥验证失败,禁止使用功能
}
}
}
10 changes: 10 additions & 0 deletions apps/api/src/achievement/achievement.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { UserModule } from '../user/user.module';
import { AchievementController } from './achievement.controller';
import { AchieveService } from './achievement.service';
@Module({
imports: [UserModule],
controllers: [AchievementController],
providers: [AchieveService],
})
export class AchievementModule {}
145 changes: 145 additions & 0 deletions apps/api/src/achievement/achievement.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { achievements, userAchievements, userProfile } from '@earthworm/schema';
import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common';
import { eq } from 'drizzle-orm';
import { UserService } from 'src/user/user.service';
import { DB, DbType } from '../global/providers/db.provider';
import {
FindUserDto,
UserAchievementDto,
publishAchievementDto,
setAchievementDto,
} from './model/pub.dto';
@Injectable()
export class AchieveService {
constructor(
@Inject(DB) private db: DbType,
private userService: UserService,
) {}
async authUser(dto: FindUserDto) {
const user = await this.userService.findWithPhone(dto);
if (!user) {
throw new HttpException('不存在该用户', HttpStatus.BAD_REQUEST);
}
return user;
}
async useAchievement(dto: UserAchievementDto) {
const userAchieve = await this.db.query.userProfile.findFirst({
where: eq(userProfile.userID, dto.userID),
});
if (!userAchieve) {
throw new HttpException('当前未设置使用中成就', HttpStatus.BAD_REQUEST);
}
return userAchieve;
}
async setAchievement(dto: setAchievementDto) {
const haveAchieve = await this.db.query.userAchievements.findFirst({
where: eq(userAchievements.achievementID, dto.achievementID),
});
if (!haveAchieve) {
throw new HttpException('不存在该成就', HttpStatus.BAD_REQUEST);
}
const activeAchieve = await this.db.query.userProfile.findFirst({
where: eq(userProfile.userID, dto.userID),
});
if (activeAchieve) {
if (activeAchieve.achievementID === dto.achievementID) {
throw new HttpException(
'当前成就为使用中成就,请更换其他成就',
HttpStatus.BAD_REQUEST,
);
} else {
const res = await this.db
.update(userProfile)
.set({
achievementID: dto.achievementID,
})
.where(eq(userProfile.userID, dto.userID));
if (res) {
throw new HttpException('更换成就成功', HttpStatus.OK);
}
}
} else {
const res = await this.db
.insert(userProfile)
.values({ userID: dto.userID, achievementID: dto.achievementID });
if (res) {
throw new HttpException('设置当前成就为使用中', HttpStatus.OK);
}
}
}
async PubAchievement(dto: publishAchievementDto) {
const existing = await this.db.query.userAchievements.findMany({
where: eq(userAchievements.userID, dto.userID),
});

if (existing) {
const existingAchievements = existing.map(
(record) => record.achievementID,
);
const newAchievements = dto.choiceAchievement.filter(
(achievementID) =>
!existingAchievements.includes(Number(achievementID)),
);
if (newAchievements.length > 0) {
const insertData = newAchievements.map((achievementID) => ({
userID: dto.userID,
achievementID: Number(achievementID), // Convert achievementID to a number
}));
const res = await this.db.insert(userAchievements).values(insertData);

if (res) {
throw new HttpException('添加成就完成', HttpStatus.OK);
}
} else {
throw new HttpException('当前用户已经拥有选中成就', HttpStatus.BAD_REQUEST);
}
} else {
const insertData = dto.choiceAchievement.map((achievementID) => ({
userID: dto.userID,
achievementID: Number(achievementID), // Convert achievementID to a number
}));
const res = await this.db.insert(userAchievements).values(insertData);

if (res) {
throw new HttpException('添加成就完成', HttpStatus.OK);
}
}
}

async AllAchievement() {
const achievementAll = await this.db
.select({
id: achievements.id,
name: achievements.name,
description: achievements.description,
})
.from(achievements);

return achievementAll;
}
async haveAchievement(dto: UserAchievementDto) {
const userAchieve = await this.db.query.userAchievements.findMany({
where: eq(userAchievements.userID, dto.userID),
});
if (!userAchieve.length) {
throw new HttpException('还没有获得成就', HttpStatus.BAD_REQUEST);
}
// 查询achievements表,获取详细信息
const promises = userAchieve.map(async (achievement) => {
const achievementDetails = await this.db.query.achievements.findFirst({
where: eq(achievements.id, achievement.achievementID),
});
if (!achievementDetails) {
throw new HttpException('找不到相应的成就信息', HttpStatus.BAD_REQUEST);
}
return achievementDetails;
});
const achievementDetails = await Promise.all(promises);
const result = userAchieve.map((achievement, index) => ({
...achievementDetails[index],
createdAt: achievement.createdAt,
}));

return result;
}
}
37 changes: 37 additions & 0 deletions apps/api/src/achievement/model/pub.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, Length } from 'class-validator';

export class publishAchievementDto {
@ApiProperty()
@IsNotEmpty({ message: 'secretKey不能为空' })
secretKey: string;

@ApiProperty()
@IsNotEmpty({ message: 'userID不能为空' })
userID: number;

@ApiProperty()
@IsNotEmpty({ message: 'choiceAchievement不能为空' })
// choiceAchievement: number;
choiceAchievement: number[];
}
export class FindUserDto {
@ApiProperty()
@IsNotEmpty({ message: '手机号码不能为空' })
@Length(6, 20, { message: '手机号码长度应在6到20位之间' })
phone: string;
}
export class UserAchievementDto {
@ApiProperty()
@IsNotEmpty({ message: 'userID不能为空' })
userID: number;
}
export class setAchievementDto {
@ApiProperty()
@IsNotEmpty({ message: 'userID不能为空' })
userID: number;

@ApiProperty()
@IsNotEmpty({ message: 'achievementID不能为空' })
achievementID: number;
}
21 changes: 11 additions & 10 deletions apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { RedisModule } from '@nestjs-modules/ioredis';
import { Module } from '@nestjs/common';
import { GlobalModule } from '../global/global.module';
import { UserModule } from '../user/user.module';
import { ScheduleModule } from '@nestjs/schedule';
import { AchievementModule } from '../achievement/achievement.module';
import { AuthModule } from '../auth/auth.module';
import { CourseHistoryModule } from '../course-history/course-history.module';
import { CourseModule } from '../course/course.module';
import { UserProgressModule } from '../user-progress/user-progress.module';
import { ToolModule } from '../tool/tool.module';
import { RedisModule } from '@nestjs-modules/ioredis';
import { RankModule } from '../rank/rank.module';
import { GameModule } from '../game/game.module';
import { ScheduleModule } from '@nestjs/schedule';
import { CronJobModule } from '../cron-job/cron-job.module';
import { CourseHistoryModule } from '../course-history/course-history.module';

import { GameModule } from '../game/game.module';
import { GlobalModule } from '../global/global.module';
import { RankModule } from '../rank/rank.module';
import { ToolModule } from '../tool/tool.module';
import { UserProgressModule } from '../user-progress/user-progress.module';
import { UserModule } from '../user/user.module';
@Module({
imports: [
AchievementModule,
GlobalModule,
UserModule,
AuthModule,
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import {
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { UserService } from '../user/user.service';
import { JwtService } from '@nestjs/jwt';
import { SignDto } from './model/auth.dto';
import * as argon2 from 'argon2';
import { CreateUserDto } from '../user/model/user.dto';
import { UserService } from '../user/user.service';
import { SignDto } from './model/auth.dto';

@Injectable()
export class AuthService {
Expand Down
6 changes: 3 additions & 3 deletions apps/api/src/user-progress/user-progress.controller.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Controller, Post, Body, UseGuards, Get, Put } from '@nestjs/common';
import { UserProgressService } from './user-progress.service';
import { Body, Controller, Get, Post, Put, UseGuards } from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';
import { User, UserEntity } from '../user/user.decorators';
import {
CreateUserProgressDto,
UpdateUserProgressDto,
} from './model/user-progress.dto';
import { User, UserEntity } from '../user/user.decorators';
import { UserProgressService } from './user-progress.service';

@Controller('user-progress')
export class UserProgressController {
Expand Down
54 changes: 54 additions & 0 deletions apps/client/api/achievement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { AchievementItem } from "~/composables/user/achievement";
import { http } from "./http";

interface PublishDto {
secretKey: string;
userID: number;
choiceAchievement: number[];
}
export interface AuthUserDto {
phone: string;
}

export interface SetDto {
// name: string;
userID: number;
achievementID: number;
}
export interface UserDto {
userID: number;
}
export interface UserInfo {
id: number;
phone: string;
name: string;
password: string;
}
// 颁布成就
export async function fetchPubAchievement(dto: PublishDto) {
return await http.post("/achievement/publish", dto);
}
// 获取成就列表
export async function fetchAllAchievements() {
return await http.get<AchievementItem[], AchievementItem[]>(
"/achievement/list"
);
}
// 验证用户 check userID
export async function fetchAuthUser(dto: AuthUserDto) {
return await http.post<UserInfo, UserInfo>("/achievement/authUser", dto);
// return await http.get("/achievement/authUser");
}
// 设置成就为使用中状态
export async function fetchSetUsing(dto: SetDto) {
return await http.post("/achievement/set", dto);
}
export async function fetchUserAchievement(dto: UserDto) {
return await http.post("/achievement/use", dto);
}
export async function fetchHaveAchievement(dto: UserDto) {
return await http.post<AchievementItem[], AchievementItem[]>(
"/achievement/allHave",
dto
);
}
Loading