fix(backend): enumerate achievement types in some response schema (#15953)
* fix(backend): enumerate achievement types in some response schema * refactor: use `ref`
This commit is contained in:
parent
09317150e1
commit
3b676f39df
|
@ -9,87 +9,7 @@ import type { MiUser } from '@/models/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',
|
||||
'client60min',
|
||||
'noteDeletedWithin1min',
|
||||
'postedAtLateNight',
|
||||
'postedAt0min0sec',
|
||||
'selfQuote',
|
||||
'htl20npm',
|
||||
'viewInstanceChart',
|
||||
'outputHelloWorldOnScratchpad',
|
||||
'open3windows',
|
||||
'driveFolderCircularReference',
|
||||
'reactWithoutRead',
|
||||
'clickedClickHere',
|
||||
'justPlainLucky',
|
||||
'setNameToSyuilo',
|
||||
'cookieClicked',
|
||||
'brainDiver',
|
||||
'smashTestNotificationButton',
|
||||
'tutorialCompleted',
|
||||
'bubbleGameExplodingHead',
|
||||
'bubbleGameDoubleExplodingHead',
|
||||
] as const;
|
||||
import { ACHIEVEMENT_TYPES } from '@/models/UserProfile.js';
|
||||
|
||||
@Injectable()
|
||||
export class AchievementService {
|
||||
|
|
|
@ -67,6 +67,7 @@ import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessage
|
|||
import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js';
|
||||
import { packedChatRoomInvitationSchema } from '@/models/json-schema/chat-room-invitation.js';
|
||||
import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-membership.js';
|
||||
import { packedAchievementNameSchema, packedAchievementSchema } from '@/models/json-schema/achievement.js';
|
||||
|
||||
export const refs = {
|
||||
UserLite: packedUserLiteSchema,
|
||||
|
@ -78,6 +79,8 @@ export const refs = {
|
|||
User: packedUserSchema,
|
||||
|
||||
UserList: packedUserListSchema,
|
||||
Achievement: packedAchievementSchema,
|
||||
AchievementName: packedAchievementNameSchema,
|
||||
Ad: packedAdSchema,
|
||||
Announcement: packedAnnouncementSchema,
|
||||
App: packedAppSchema,
|
||||
|
|
|
@ -274,7 +274,7 @@ export class MiUserProfile {
|
|||
default: [],
|
||||
})
|
||||
public achievements: {
|
||||
name: string;
|
||||
name: typeof ACHIEVEMENT_TYPES[number];
|
||||
unlockedAt: number;
|
||||
}[];
|
||||
|
||||
|
@ -295,3 +295,84 @@ export class MiUserProfile {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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',
|
||||
'client60min',
|
||||
'noteDeletedWithin1min',
|
||||
'postedAtLateNight',
|
||||
'postedAt0min0sec',
|
||||
'selfQuote',
|
||||
'htl20npm',
|
||||
'viewInstanceChart',
|
||||
'outputHelloWorldOnScratchpad',
|
||||
'open3windows',
|
||||
'driveFolderCircularReference',
|
||||
'reactWithoutRead',
|
||||
'clickedClickHere',
|
||||
'justPlainLucky',
|
||||
'setNameToSyuilo',
|
||||
'cookieClicked',
|
||||
'brainDiver',
|
||||
'smashTestNotificationButton',
|
||||
'tutorialCompleted',
|
||||
'bubbleGameExplodingHead',
|
||||
'bubbleGameDoubleExplodingHead',
|
||||
] as const;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { ACHIEVEMENT_TYPES } from '@/models/UserProfile.js';
|
||||
|
||||
export const packedAchievementNameSchema = {
|
||||
type: 'string',
|
||||
enum: ACHIEVEMENT_TYPES,
|
||||
optional: false,
|
||||
} as const;
|
||||
|
||||
export const packedAchievementSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
ref: 'AchievementName',
|
||||
},
|
||||
unlockedAt: {
|
||||
type: 'number',
|
||||
optional: false,
|
||||
},
|
||||
},
|
||||
} as const;
|
|
@ -3,7 +3,6 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { ACHIEVEMENT_TYPES } from '@/core/AchievementService.js';
|
||||
import { notificationTypes, userExportableEntities } from '@/types.js';
|
||||
|
||||
const baseSchema = {
|
||||
|
@ -312,9 +311,7 @@ export const packedNotificationSchema = {
|
|||
enum: ['achievementEarned'],
|
||||
},
|
||||
achievement: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ACHIEVEMENT_TYPES,
|
||||
ref: 'AchievementName',
|
||||
},
|
||||
},
|
||||
}, {
|
||||
|
|
|
@ -630,18 +630,7 @@ export const packedMeDetailedOnlySchema = {
|
|||
type: 'array',
|
||||
nullable: false, optional: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
nullable: false, optional: false,
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
unlockedAt: {
|
||||
type: 'number',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
},
|
||||
ref: 'Achievement',
|
||||
},
|
||||
},
|
||||
loggedInDays: {
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { AchievementService, ACHIEVEMENT_TYPES } from '@/core/AchievementService.js';
|
||||
import { AchievementService } from '@/core/AchievementService.js';
|
||||
import { ACHIEVEMENT_TYPES } from '@/models/UserProfile.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
|
|
@ -14,15 +14,7 @@ export const meta = {
|
|||
res: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
},
|
||||
unlockedAt: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
ref: 'Achievement',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -232,7 +232,7 @@ describe('UserEntityService', () => {
|
|||
});
|
||||
|
||||
test('MeDetailed', async() => {
|
||||
const achievements = [{ name: 'achievement', unlockedAt: new Date().getTime() }];
|
||||
const achievements = [{ name: 'iLoveMisskey' as const, unlockedAt: new Date().getTime() }];
|
||||
const me = await createUser({}, {
|
||||
birthday: '2000-01-01',
|
||||
achievements: achievements,
|
||||
|
|
|
@ -30,6 +30,12 @@ declare namespace acct {
|
|||
}
|
||||
export { acct }
|
||||
|
||||
// @public (undocumented)
|
||||
type Achievement = components['schemas']['Achievement'];
|
||||
|
||||
// @public (undocumented)
|
||||
type AchievementName = components['schemas']['AchievementName'];
|
||||
|
||||
// @public (undocumented)
|
||||
type Ad = components['schemas']['Ad'];
|
||||
|
||||
|
@ -2084,6 +2090,8 @@ declare namespace entities {
|
|||
UserDetailed,
|
||||
User,
|
||||
UserList,
|
||||
Achievement,
|
||||
AchievementName,
|
||||
Ad,
|
||||
Announcement,
|
||||
App,
|
||||
|
|
|
@ -8,6 +8,8 @@ export type MeDetailed = components['schemas']['MeDetailed'];
|
|||
export type UserDetailed = components['schemas']['UserDetailed'];
|
||||
export type User = components['schemas']['User'];
|
||||
export type UserList = components['schemas']['UserList'];
|
||||
export type Achievement = components['schemas']['Achievement'];
|
||||
export type AchievementName = components['schemas']['AchievementName'];
|
||||
export type Ad = components['schemas']['Ad'];
|
||||
export type Announcement = components['schemas']['Announcement'];
|
||||
export type App = components['schemas']['App'];
|
||||
|
|
|
@ -4303,10 +4303,7 @@ export type components = {
|
|||
}]>;
|
||||
};
|
||||
emailNotificationTypes: string[];
|
||||
achievements: {
|
||||
name: string;
|
||||
unlockedAt: number;
|
||||
}[];
|
||||
achievements: components['schemas']['Achievement'][];
|
||||
loggedInDays: number;
|
||||
policies: components['schemas']['RolePolicies'];
|
||||
/** @default false */
|
||||
|
@ -4344,6 +4341,12 @@ export type components = {
|
|||
userIds?: string[];
|
||||
isPublic: boolean;
|
||||
};
|
||||
Achievement: {
|
||||
name: components['schemas']['AchievementName'];
|
||||
unlockedAt: number;
|
||||
};
|
||||
/** @enum {string} */
|
||||
AchievementName: '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' | 'client60min' | 'noteDeletedWithin1min' | 'postedAtLateNight' | 'postedAt0min0sec' | 'selfQuote' | 'htl20npm' | 'viewInstanceChart' | 'outputHelloWorldOnScratchpad' | 'open3windows' | 'driveFolderCircularReference' | 'reactWithoutRead' | 'clickedClickHere' | 'justPlainLucky' | 'setNameToSyuilo' | 'cookieClicked' | 'brainDiver' | 'smashTestNotificationButton' | 'tutorialCompleted' | 'bubbleGameExplodingHead' | 'bubbleGameDoubleExplodingHead';
|
||||
Ad: {
|
||||
/**
|
||||
* Format: id
|
||||
|
@ -4619,16 +4622,15 @@ export type components = {
|
|||
/** @enum {string} */
|
||||
type: 'chatRoomInvitationReceived';
|
||||
invitation: components['schemas']['ChatRoomInvitation'];
|
||||
} | ({
|
||||
} | {
|
||||
/** Format: id */
|
||||
id: string;
|
||||
/** Format: date-time */
|
||||
createdAt: string;
|
||||
/** @enum {string} */
|
||||
type: 'achievementEarned';
|
||||
/** @enum {string} */
|
||||
achievement: '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' | 'client60min' | 'noteDeletedWithin1min' | 'postedAtLateNight' | 'postedAt0min0sec' | 'selfQuote' | 'htl20npm' | 'viewInstanceChart' | 'outputHelloWorldOnScratchpad' | 'open3windows' | 'driveFolderCircularReference' | 'reactWithoutRead' | 'clickedClickHere' | 'justPlainLucky' | 'setNameToSyuilo' | 'cookieClicked' | 'brainDiver' | 'smashTestNotificationButton' | 'tutorialCompleted' | 'bubbleGameExplodingHead' | 'bubbleGameDoubleExplodingHead';
|
||||
}) | ({
|
||||
achievement: components['schemas']['AchievementName'];
|
||||
} | ({
|
||||
/** Format: id */
|
||||
id: string;
|
||||
/** Format: date-time */
|
||||
|
@ -28531,10 +28533,7 @@ export type operations = {
|
|||
/** @description OK (with results) */
|
||||
200: {
|
||||
content: {
|
||||
'application/json': {
|
||||
name: string;
|
||||
unlockedAt: number;
|
||||
}[];
|
||||
'application/json': components['schemas']['Achievement'][];
|
||||
};
|
||||
};
|
||||
/** @description Client error */
|
||||
|
|
Loading…
Reference in New Issue