summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/backend/src/core/AchievementService.ts82
-rw-r--r--packages/backend/src/misc/json-schema.ts3
-rw-r--r--packages/backend/src/models/UserProfile.ts83
-rw-r--r--packages/backend/src/models/json-schema/achievement.ts25
-rw-r--r--packages/backend/src/models/json-schema/notification.ts5
-rw-r--r--packages/backend/src/models/json-schema/user.ts13
-rw-r--r--packages/backend/src/server/api/endpoints/i/claim-achievement.ts3
-rw-r--r--packages/backend/src/server/api/endpoints/users/achievements.ts10
-rw-r--r--packages/backend/test/unit/entities/UserEntityService.ts2
-rw-r--r--packages/misskey-js/etc/misskey-js.api.md8
-rw-r--r--packages/misskey-js/src/autogen/models.ts2
-rw-r--r--packages/misskey-js/src/autogen/types.ts23
12 files changed, 138 insertions, 121 deletions
diff --git a/packages/backend/src/core/AchievementService.ts b/packages/backend/src/core/AchievementService.ts
index 4fc1193f32..8d2de89efd 100644
--- a/packages/backend/src/core/AchievementService.ts
+++ b/packages/backend/src/core/AchievementService.ts
@@ -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 {
diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts
index 27aa3d89de..e4eb10efca 100644
--- a/packages/backend/src/misc/json-schema.ts
+++ b/packages/backend/src/misc/json-schema.ts
@@ -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,
diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts
index 5544555296..c4c1fa5ec9 100644
--- a/packages/backend/src/models/UserProfile.ts
+++ b/packages/backend/src/models/UserProfile.ts
@@ -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;
diff --git a/packages/backend/src/models/json-schema/achievement.ts b/packages/backend/src/models/json-schema/achievement.ts
new file mode 100644
index 0000000000..39a621a570
--- /dev/null
+++ b/packages/backend/src/models/json-schema/achievement.ts
@@ -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;
diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts
index 7f23d2d6a1..6de120c8d7 100644
--- a/packages/backend/src/models/json-schema/notification.ts
+++ b/packages/backend/src/models/json-schema/notification.ts
@@ -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',
},
},
}, {
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index e475296702..2b5f706ff9 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -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: {
diff --git a/packages/backend/src/server/api/endpoints/i/claim-achievement.ts b/packages/backend/src/server/api/endpoints/i/claim-achievement.ts
index e70905ef1b..0e42647ef7 100644
--- a/packages/backend/src/server/api/endpoints/i/claim-achievement.ts
+++ b/packages/backend/src/server/api/endpoints/i/claim-achievement.ts
@@ -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,
diff --git a/packages/backend/src/server/api/endpoints/users/achievements.ts b/packages/backend/src/server/api/endpoints/users/achievements.ts
index f7139b3684..bae216e347 100644
--- a/packages/backend/src/server/api/endpoints/users/achievements.ts
+++ b/packages/backend/src/server/api/endpoints/users/achievements.ts
@@ -14,15 +14,7 @@ export const meta = {
res: {
type: 'array',
items: {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- },
- unlockedAt: {
- type: 'number',
- },
- },
+ ref: 'Achievement',
},
},
} as const;
diff --git a/packages/backend/test/unit/entities/UserEntityService.ts b/packages/backend/test/unit/entities/UserEntityService.ts
index ce3f931bb0..ca6a639be8 100644
--- a/packages/backend/test/unit/entities/UserEntityService.ts
+++ b/packages/backend/test/unit/entities/UserEntityService.ts
@@ -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,
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 7069d32317..79813d3f82 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -31,6 +31,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'];
// Warning: (ae-forgotten-export) The symbol "operations" needs to be exported by the entry point index.d.ts
@@ -2084,6 +2090,8 @@ declare namespace entities {
UserDetailed,
User,
UserList,
+ Achievement,
+ AchievementName,
Ad,
Announcement,
App,
diff --git a/packages/misskey-js/src/autogen/models.ts b/packages/misskey-js/src/autogen/models.ts
index 15c3ee7e55..354daf800b 100644
--- a/packages/misskey-js/src/autogen/models.ts
+++ b/packages/misskey-js/src/autogen/models.ts
@@ -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'];
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index c83e1f1fbe..c54cc571d2 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -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 */