misskey/packages/backend/src/core/AchievementService.ts

122 lines
2.5 KiB
TypeScript

import { Inject, Injectable } from '@nestjs/common';
import type { UserProfilesRepository, UsersRepository } from '@/models/index.js';
import type { User } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { NotificationService } from '@/core/NotificationService.js';
export const ACHIEVEMENT_TYPES = [
'notes1',
'notes10',
'notes100',
'notes500',
'notes1000',
'notes5000',
'notes10000',
'notes20000',
'notes30000',
'notes40000',
'notes50000',
'notes60000',
'notes70000',
'notes80000',
'notes90000',
'notes100000',
'login3',
'login7',
'login15',
'login30',
'login60',
'login100',
'login200',
'login300',
'login400',
'login500',
'login600',
'login700',
'login800',
'login900',
'login1000',
'passedSinceAccountCreated1',
'passedSinceAccountCreated2',
'passedSinceAccountCreated3',
'loggedInOnBirthday',
'loggedInOnNewYearsDay',
'noteClipped1',
'noteFavorited1',
'myNoteFavorited1',
'profileFilled',
'markedAsCat',
'following1',
'following10',
'following50',
'following100',
'following300',
'followers1',
'followers10',
'followers50',
'followers100',
'followers300',
'followers500',
'followers1000',
'collectAchievements30',
'viewAchievements3min',
'iLoveMisskey',
'foundTreasure',
'client30min',
'noteDeletedWithin1min',
'postedAtLateNight',
'postedAt0min0sec',
'selfQuote',
'htl20npm',
'viewInstanceChart',
'outputHelloWorldOnScratchpad',
'open3windows',
'driveFolderCircularReference',
'reactWithoutRead',
'clickedClickHere',
'justPlainLucky',
'setNameToSyuilo',
'cookieClicked',
'brainDiver',
] as const;
@Injectable()
export class AchievementService {
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
private notificationService: NotificationService,
) {
}
@bindThis
public async create(
userId: User['id'],
type: typeof ACHIEVEMENT_TYPES[number],
): Promise<void> {
if (!ACHIEVEMENT_TYPES.includes(type)) return;
const date = Date.now();
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: userId });
if (profile.achievements.some(a => a.name === type)) return;
await this.userProfilesRepository.update(userId, {
achievements: [...profile.achievements, {
name: type,
unlockedAt: date,
}],
});
this.notificationService.createNotification(userId, 'achievementEarned', {
achievement: type,
});
}
}