diff --git a/packages/backend/src/server/api/endpoints/admin/roles/delete.ts b/packages/backend/src/server/api/endpoints/admin/roles/delete.ts index b56ebdb3ee..f52d9f8d71 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/delete.ts @@ -5,44 +5,20 @@ import { GlobalEventService } from '@/core/GlobalEventService.js'; import { DI } from '@/di-symbols.js'; import { ApiError } from '@/server/api/error.js'; -export const meta = { - tags: ['admin', 'role'], - - requireCredential: true, - requireAdmin: true, - - errors: { - noSuchRole: { - message: 'No such role.', - code: 'NO_SUCH_ROLE', - id: 'de0d6ecd-8e0a-4253-88ff-74bc89ae3d45', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - roleId: { type: 'string', format: 'misskey:id' }, - }, - required: [ - 'roleId', - ], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'admin/roles/delete'> { + name = 'admin/roles/delete' as const; constructor( @Inject(DI.rolesRepository) private rolesRepository: RolesRepository, private globalEventService: GlobalEventService, ) { - super(meta, paramDef, async (ps) => { + super(async (ps) => { const role = await this.rolesRepository.findOneBy({ id: ps.roleId }); if (role == null) { - throw new ApiError(meta.errors.noSuchRole); + throw new ApiError(this.meta.errors.noSuchRole); } await this.rolesRepository.delete({ id: ps.roleId, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/list.ts b/packages/backend/src/server/api/endpoints/admin/roles/list.ts index edaf638ea9..886c359513 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/list.ts @@ -4,31 +4,17 @@ import type { RolesRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; import { RoleEntityService } from '@/core/entities/RoleEntityService.js'; -export const meta = { - tags: ['admin', 'role'], - - requireCredential: true, - requireModerator: true, -} as const; - -export const paramDef = { - type: 'object', - properties: { - }, - required: [ - ], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'admin/roles/list'> { + name = 'admin/roles/list' as const; constructor( @Inject(DI.rolesRepository) private rolesRepository: RolesRepository, private roleEntityService: RoleEntityService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const roles = await this.rolesRepository.find({ order: { lastUsedAt: 'DESC' }, }); diff --git a/packages/backend/src/server/api/endpoints/admin/roles/show.ts b/packages/backend/src/server/api/endpoints/admin/roles/show.ts index 01028a086f..33febfe3c1 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/show.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/show.ts @@ -5,44 +5,20 @@ import { DI } from '@/di-symbols.js'; import { ApiError } from '@/server/api/error.js'; import { RoleEntityService } from '@/core/entities/RoleEntityService.js'; -export const meta = { - tags: ['admin', 'role'], - - requireCredential: true, - requireModerator: true, - - errors: { - noSuchRole: { - message: 'No such role.', - code: 'NO_SUCH_ROLE', - id: '07dc7d34-c0d8-49b7-96c6-db3ce64ee0b3', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - roleId: { type: 'string', format: 'misskey:id' }, - }, - required: [ - 'roleId', - ], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'admin/roles/show'> { + name = 'admin/roles/show' as const; constructor( @Inject(DI.rolesRepository) private rolesRepository: RolesRepository, private roleEntityService: RoleEntityService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const role = await this.rolesRepository.findOneBy({ id: ps.roleId }); if (role == null) { - throw new ApiError(meta.errors.noSuchRole); + throw new ApiError(this.meta.errors.noSuchRole); } return await this.roleEntityService.pack(role, me); }); diff --git a/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts b/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts index 45c4f76943..827d9d85a1 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/unassign.ts @@ -5,54 +5,10 @@ import { DI } from '@/di-symbols.js'; import { ApiError } from '@/server/api/error.js'; import { RoleService } from '@/core/RoleService.js'; -export const meta = { - tags: ['admin', 'role'], - - requireCredential: true, - requireModerator: true, - - errors: { - noSuchRole: { - message: 'No such role.', - code: 'NO_SUCH_ROLE', - id: '6e519036-a70d-4c76-b679-bc8fb18194e2', - }, - - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '2b730f78-1179-461b-88ad-d24c9af1a5ce', - }, - - notAssigned: { - message: 'Not assigned.', - code: 'NOT_ASSIGNED', - id: 'b9060ac7-5c94-4da4-9f55-2047c953df44', - }, - - accessDenied: { - message: 'Only administrators can edit members of the role.', - code: 'ACCESS_DENIED', - id: '24636eee-e8c1-493e-94b2-e16ad401e262', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - roleId: { type: 'string', format: 'misskey:id' }, - userId: { type: 'string', format: 'misskey:id' }, - }, - required: [ - 'roleId', - 'userId', - ], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'admin/roles/unassign'> { + name = 'admin/roles/unassign' as const; constructor( @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -62,19 +18,19 @@ export default class extends Endpoint { private roleService: RoleService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const role = await this.rolesRepository.findOneBy({ id: ps.roleId }); if (role == null) { - throw new ApiError(meta.errors.noSuchRole); + throw new ApiError(this.meta.errors.noSuchRole); } if (!role.canEditMembersByModerator && !(await this.roleService.isAdministrator(me))) { - throw new ApiError(meta.errors.accessDenied); + throw new ApiError(this.meta.errors.accessDenied); } const user = await this.usersRepository.findOneBy({ id: ps.userId }); if (user == null) { - throw new ApiError(meta.errors.noSuchUser); + throw new ApiError(this.meta.errors.noSuchUser); } await this.roleService.unassign(user.id, role.id); diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts index 5a34eee96c..77acecd8b1 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts @@ -3,33 +3,15 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { MetaService } from '@/core/MetaService.js'; -export const meta = { - tags: ['admin', 'role'], - - requireCredential: true, - requireAdmin: true, -} as const; - -export const paramDef = { - type: 'object', - properties: { - policies: { - type: 'object', - }, - }, - required: [ - 'policies', - ], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'admin/roles/update-default-policies'> { + name = 'admin/roles/update-default-policies' as const; constructor( private metaService: MetaService, private globalEventService: GlobalEventService, ) { - super(meta, paramDef, async (ps) => { + super(async (ps) => { await this.metaService.update({ policies: ps.policies, }); diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts index 467f157a61..ebb734e74c 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts @@ -5,73 +5,20 @@ import { GlobalEventService } from '@/core/GlobalEventService.js'; import { DI } from '@/di-symbols.js'; import { ApiError } from '@/server/api/error.js'; -export const meta = { - tags: ['admin', 'role'], - - requireCredential: true, - requireAdmin: true, - - errors: { - noSuchRole: { - message: 'No such role.', - code: 'NO_SUCH_ROLE', - id: 'cd23ef55-09ad-428a-ac61-95a45e124b32', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - roleId: { type: 'string', format: 'misskey:id' }, - name: { type: 'string' }, - description: { type: 'string' }, - color: { type: 'string', nullable: true }, - iconUrl: { type: 'string', nullable: true }, - target: { type: 'string', enum: ['manual', 'conditional'] }, - condFormula: { type: 'object' }, - isPublic: { type: 'boolean' }, - isModerator: { type: 'boolean' }, - isAdministrator: { type: 'boolean' }, - isExplorable: { type: 'boolean' }, - asBadge: { type: 'boolean' }, - canEditMembersByModerator: { type: 'boolean' }, - displayOrder: { type: 'number' }, - policies: { - type: 'object', - }, - }, - required: [ - 'roleId', - 'name', - 'description', - 'color', - 'iconUrl', - 'target', - 'condFormula', - 'isPublic', - 'isModerator', - 'isAdministrator', - 'asBadge', - 'canEditMembersByModerator', - 'displayOrder', - 'policies', - ], -} as const; - // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'admin/roles/update'> { + name = 'admin/roles/update' as const; constructor( @Inject(DI.rolesRepository) private rolesRepository: RolesRepository, private globalEventService: GlobalEventService, ) { - super(meta, paramDef, async (ps) => { + super(async (ps) => { const role = await this.rolesRepository.findOneBy({ id: ps.roleId }); if (role == null) { - throw new ApiError(meta.errors.noSuchRole); + throw new ApiError(this.meta.errors.noSuchRole); } const date = new Date(); diff --git a/packages/backend/src/server/api/endpoints/admin/roles/users.ts b/packages/backend/src/server/api/endpoints/admin/roles/users.ts index 35edca5460..0f9a7ffa9e 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/users.ts @@ -6,36 +6,12 @@ import { QueryService } from '@/core/QueryService.js'; import { DI } from '@/di-symbols.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { ApiError } from '../../../error.js'; - -export const meta = { - tags: ['admin', 'role', 'users'], - - requireCredential: false, - requireAdmin: true, - - errors: { - noSuchRole: { - message: 'No such role.', - code: 'NO_SUCH_ROLE', - id: '224eff5e-2488-4b18-b3e7-f50d94421648', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - roleId: { type: 'string', format: 'misskey:id' }, - sinceId: { type: 'string', format: 'misskey:id' }, - untilId: { type: 'string', format: 'misskey:id' }, - limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - }, - required: ['roleId'], -} as const; +import { Packed } from 'misskey-js'; // eslint-disable-next-line import/no-default-export @Injectable() -export default class extends Endpoint { +export default class extends Endpoint<'admin/roles/users'> { + name = 'admin/roles/users' as const; constructor( @Inject(DI.rolesRepository) private rolesRepository: RolesRepository, @@ -46,13 +22,13 @@ export default class extends Endpoint { private queryService: QueryService, private userEntityService: UserEntityService, ) { - super(meta, paramDef, async (ps, me) => { + super(async (ps, me) => { const role = await this.rolesRepository.findOneBy({ id: ps.roleId, }); if (role == null) { - throw new ApiError(meta.errors.noSuchRole); + throw new ApiError(this.meta.errors.noSuchRole); } const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId) @@ -67,7 +43,7 @@ export default class extends Endpoint { .take(ps.limit) .getMany(); - return await Promise.all(assigns.map(async assign => ({ + return await Promise.all(assigns.map(async (assign): Promise> => ({ id: assign.id, createdAt: assign.createdAt, user: await this.userEntityService.pack(assign.user!, me, { detail: true }), diff --git a/packages/misskey-js/src/endpoints.ts b/packages/misskey-js/src/endpoints.ts index 6d629d8501..7ee8706e3a 100644 --- a/packages/misskey-js/src/endpoints.ts +++ b/packages/misskey-js/src/endpoints.ts @@ -1149,6 +1149,235 @@ export const endpoints = { }, }], }, + 'admin/roles/delete': { + tags: ['admin', 'role'], + + requireCredential: true, + requireAdmin: true, + + errors: { + noSuchRole: { + message: 'No such role.', + code: 'NO_SUCH_ROLE', + id: 'de0d6ecd-8e0a-4253-88ff-74bc89ae3d45', + }, + }, + + defines: [{ + req: { + type: 'object', + properties: { + roleId: { type: 'string', format: 'misskey:id' }, + }, + required: [ + 'roleId', + ], + }, + res: undefined, + }], + }, + 'admin/roles/list': { + tags: ['admin', 'role'], + + requireCredential: true, + requireModerator: true, + + defines: [{ + req: undefined, + res: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/Role', + }, + }, + }], + }, + 'admin/roles/show': { + tags: ['admin', 'role'], + + requireCredential: true, + requireModerator: true, + + errors: { + noSuchRole: { + message: 'No such role.', + code: 'NO_SUCH_ROLE', + id: '07dc7d34-c0d8-49b7-96c6-db3ce64ee0b3', + }, + }, + + defines: [{ + req: { + type: 'object', + properties: { + roleId: { type: 'string', format: 'misskey:id' }, + }, + required: [ + 'roleId', + ], + }, + res: { + $ref: 'https://misskey-hub.net/api/schemas/Role', + } + }], + }, + 'admin/roles/unassign': { + tags: ['admin', 'role'], + + requireCredential: true, + requireModerator: true, + + errors: { + noSuchRole: { + message: 'No such role.', + code: 'NO_SUCH_ROLE', + id: '6e519036-a70d-4c76-b679-bc8fb18194e2', + }, + + noSuchUser: { + message: 'No such user.', + code: 'NO_SUCH_USER', + id: '2b730f78-1179-461b-88ad-d24c9af1a5ce', + }, + + notAssigned: { + message: 'Not assigned.', + code: 'NOT_ASSIGNED', + id: 'b9060ac7-5c94-4da4-9f55-2047c953df44', + }, + + accessDenied: { + message: 'Only administrators can edit members of the role.', + code: 'ACCESS_DENIED', + id: '24636eee-e8c1-493e-94b2-e16ad401e262', + }, + }, + + defines: [{ + req: { + type: 'object', + properties: { + roleId: { type: 'string', format: 'misskey:id' }, + userId: { type: 'string', format: 'misskey:id' }, + }, + required: [ + 'roleId', + 'userId', + ], + }, + res: undefined, + }], + }, + 'admin/roles/update-default-policies': { + tags: ['admin', 'role'], + + requireCredential: true, + requireAdmin: true, + + defines: [{ + req: { + type: 'object', + properties: { + policies: { + type: 'object', + }, + }, + required: [ + 'policies', + ], + }, + res: undefined, + }], + }, + 'admin/roles/update': { + tags: ['admin', 'role'], + + requireCredential: true, + requireAdmin: true, + + errors: { + noSuchRole: { + message: 'No such role.', + code: 'NO_SUCH_ROLE', + id: 'cd23ef55-09ad-428a-ac61-95a45e124b32', + }, + }, + + defines: [{ + req: { + type: 'object', + properties: { + roleId: { type: 'string', format: 'misskey:id' }, + name: { type: 'string' }, + description: { type: 'string' }, + color: { type: ['string', 'null'] }, + iconUrl: { type: ['string', 'null'] }, + target: { type: 'string', enum: ['manual', 'conditional'] }, + condFormula: { type: 'object' }, + isPublic: { type: 'boolean' }, + isModerator: { type: 'boolean' }, + isAdministrator: { type: 'boolean' }, + isExplorable: { type: 'boolean' }, + asBadge: { type: 'boolean' }, + canEditMembersByModerator: { type: 'boolean' }, + displayOrder: { type: 'number' }, + policies: { + type: 'object', + }, + }, + required: [ + 'roleId', + 'name', + 'description', + 'color', + 'iconUrl', + 'target', + 'condFormula', + 'isPublic', + 'isModerator', + 'isAdministrator', + 'asBadge', + 'canEditMembersByModerator', + 'displayOrder', + 'policies', + ], + }, + res: undefined, + }], + }, + 'admin/roles/users': { + tags: ['admin', 'role', 'users'], + + requireCredential: false, + requireAdmin: true, + + errors: { + noSuchRole: { + message: 'No such role.', + code: 'NO_SUCH_ROLE', + id: '224eff5e-2488-4b18-b3e7-f50d94421648', + }, + }, + + defines: [{ + req: { + type: 'object', + properties: { + roleId: { type: 'string', format: 'misskey:id' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['roleId'], + }, + res: { + type: 'array', + items: { + $ref: 'https://misskey-hub.net/api/schemas/RoleAssign' + }, + } + }], + }, } as const satisfies { [x: string]: IEndpointMeta; }; /** diff --git a/packages/misskey-js/src/schemas.ts b/packages/misskey-js/src/schemas.ts index 8671c80806..5891b91ae2 100644 --- a/packages/misskey-js/src/schemas.ts +++ b/packages/misskey-js/src/schemas.ts @@ -36,6 +36,7 @@ import { packedFlashSchema } from './schemas/flash.js'; import { packedAdSchema } from './schemas/ad.js'; import { packedAnnouncementSchema } from './schemas/announcement.js'; import { packedRelaySchema } from './schemas/relay.js'; +import { packedRoleAssignSchema } from './schemas/role.js'; import { Error, ApiError } from './schemas/error.js'; import type { JSONSchema7, JSONSchema7Definition, GetDef, GetRefs, GetKeys, UnionToArray } from 'schema-type'; @@ -78,6 +79,8 @@ export const refs = { Announcement: packedAnnouncementSchema, Relay: packedRelaySchema, + RoleAssign: packedRoleAssignSchema, + Error: Error, ApiError: ApiError, } as const satisfies { [x: string]: JSONSchema7Definition }; diff --git a/packages/misskey-js/src/schemas/role.ts b/packages/misskey-js/src/schemas/role.ts new file mode 100644 index 0000000000..f9a6279fd8 --- /dev/null +++ b/packages/misskey-js/src/schemas/role.ts @@ -0,0 +1,69 @@ +import type { JSONSchema7Definition } from 'schema-type'; + +export const packedRoleSchema = { + $id: 'https://misskey-hub.net/api/schemas/Role', + + type: 'object', + properties: { + id: { $ref: 'https://misskey-hub.net/api/schemas/Id' }, + createdAt: { + type: 'string', + format: 'date-time', + }, + updatedAt: { + type: 'string', + format: 'date-time', + }, + name: { + type: 'string', + }, + description: { + type: 'string', + }, + color: { + type: ['string', 'null'], + }, + iconUrl: { + type: ['string', 'null'], + }, + target: { + enum: [ + 'manual', + 'conditional', + ], + } + }, + required: [ + 'id', + 'createdAt', + 'updatedAt', + ], +} + +export const packedRoleAssignSchema = { + $id: 'https://misskey-hub.net/api/schemas/RoleAssign', + + type: 'object', + properties: { + id: { $ref: 'https://misskey-hub.net/api/schemas/Id' }, + createdAt: { + type: 'string', + format: 'date-time', + }, + user: { $ref: 'https://misskey-hub.net/api/schemas/UserDetailed' }, + expiresAt: { + oneOf: [{ + type: 'string', + format: 'date-time', + }, { + type: 'null', + }], + }, + }, + required: [ + 'id', + 'createdAt', + 'user', + 'expiresAt', + ], +} as const satisfies JSONSchema7Definition; diff --git a/packages/misskey-js/test-d/schemas.ts b/packages/misskey-js/test-d/schemas.ts index 62bdec6614..0ba22fd92b 100644 --- a/packages/misskey-js/test-d/schemas.ts +++ b/packages/misskey-js/test-d/schemas.ts @@ -100,6 +100,10 @@ describe('schemas', () => { test('relay', () => { type Relay = Packed<'Relay'>; }); + test('role': () => { + + type RoleAssign = Packed<'RoleAssign'>; + }); test('error', () => { type Error = Packed<'Error'>; type ApiError = Packed<'ApiError'>;