feat: 時限ロール (#10145)

* feat: 時限ロール

* クライアントから期限を確認できるように

* リファクタとか

* fix test

* fix test

* fix test

* clean up
This commit is contained in:
syuilo 2023-03-01 10:20:03 +09:00 committed by GitHub
parent 7c3a390763
commit 1c5291f818
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 296 additions and 391 deletions

View file

@ -3,16 +3,18 @@ process.env.NODE_ENV = 'test';
import { jest } from '@jest/globals';
import { ModuleMocker } from 'jest-mock';
import { Test } from '@nestjs/testing';
import { DataSource } from 'typeorm';
import * as lolex from '@sinonjs/fake-timers';
import rndstr from 'rndstr';
import { GlobalModule } from '@/GlobalModule.js';
import { RoleService } from '@/core/RoleService.js';
import type { Role, RolesRepository, RoleAssignmentsRepository, UsersRepository, User } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
import { CoreModule } from '@/core/CoreModule.js';
import { MetaService } from '@/core/MetaService.js';
import { genAid } from '@/misc/id/aid.js';
import { UserCacheService } from '@/core/UserCacheService.js';
import { IdService } from '@/core/IdService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { sleep } from '../utils.js';
import type { TestingModule } from '@nestjs/testing';
import type { MockFunctionMetadata } from 'jest-mock';
@ -25,6 +27,7 @@ describe('RoleService', () => {
let rolesRepository: RolesRepository;
let roleAssignmentsRepository: RoleAssignmentsRepository;
let metaService: jest.Mocked<MetaService>;
let clock: lolex.InstalledClock;
function createUser(data: Partial<User> = {}) {
const un = rndstr('a-z0-9', 16);
@ -50,16 +53,12 @@ describe('RoleService', () => {
.then(x => rolesRepository.findOneByOrFail(x.identifiers[0]));
}
async function assign(roleId: Role['id'], userId: User['id']) {
await roleAssignmentsRepository.insert({
id: genAid(new Date()),
createdAt: new Date(),
roleId,
userId,
});
}
beforeEach(async () => {
clock = lolex.install({
now: new Date(),
shouldClearNativeTimers: true,
});
app = await Test.createTestingModule({
imports: [
GlobalModule,
@ -67,6 +66,8 @@ describe('RoleService', () => {
providers: [
RoleService,
UserCacheService,
IdService,
GlobalEventService,
],
})
.useMocker((token) => {
@ -92,12 +93,15 @@ describe('RoleService', () => {
});
afterEach(async () => {
clock.uninstall();
await Promise.all([
app.get(DI.metasRepository).delete({}),
usersRepository.delete({}),
rolesRepository.delete({}),
roleAssignmentsRepository.delete({}),
]);
await app.close();
});
@ -115,7 +119,7 @@ describe('RoleService', () => {
expect(result.canManageCustomEmojis).toBe(false);
});
test('instance default policies 2', async () => {
test('instance default policies 2', async () => {
const user = await createUser();
metaService.fetch.mockResolvedValue({
policies: {
@ -128,7 +132,7 @@ describe('RoleService', () => {
expect(result.canManageCustomEmojis).toBe(true);
});
test('with role', async () => {
test('with role', async () => {
const user = await createUser();
const role = await createRole({
name: 'a',
@ -140,7 +144,7 @@ describe('RoleService', () => {
},
},
});
await assign(role.id, user.id);
await roleService.assign(user.id, role.id);
metaService.fetch.mockResolvedValue({
policies: {
canManageCustomEmojis: false,
@ -152,7 +156,7 @@ describe('RoleService', () => {
expect(result.canManageCustomEmojis).toBe(true);
});
test('priority', async () => {
test('priority', async () => {
const user = await createUser();
const role1 = await createRole({
name: 'role1',
@ -174,8 +178,8 @@ describe('RoleService', () => {
},
},
});
await assign(role1.id, user.id);
await assign(role2.id, user.id);
await roleService.assign(user.id, role1.id);
await roleService.assign(user.id, role2.id);
metaService.fetch.mockResolvedValue({
policies: {
driveCapacityMb: 50,
@ -187,7 +191,7 @@ describe('RoleService', () => {
expect(result.driveCapacityMb).toBe(100);
});
test('conditional role', async () => {
test('conditional role', async () => {
const user1 = await createUser({
createdAt: new Date(Date.now() - (1000 * 60 * 60 * 24 * 365)),
});
@ -228,5 +232,42 @@ describe('RoleService', () => {
expect(user1Policies.canManageCustomEmojis).toBe(false);
expect(user2Policies.canManageCustomEmojis).toBe(true);
});
test('expired role', async () => {
const user = await createUser();
const role = await createRole({
name: 'a',
policies: {
canManageCustomEmojis: {
useDefault: false,
priority: 0,
value: true,
},
},
});
await roleService.assign(user.id, role.id, new Date(Date.now() + (1000 * 60 * 60 * 24)));
metaService.fetch.mockResolvedValue({
policies: {
canManageCustomEmojis: false,
},
} as any);
const result = await roleService.getUserPolicies(user.id);
expect(result.canManageCustomEmojis).toBe(true);
clock.tick('25:00:00');
const resultAfter25h = await roleService.getUserPolicies(user.id);
expect(resultAfter25h.canManageCustomEmojis).toBe(false);
await roleService.assign(user.id, role.id);
// ストリーミング経由で反映されるまでちょっと待つ
clock.uninstall();
await sleep(100);
const resultAfter25hAgain = await roleService.getUserPolicies(user.id);
expect(resultAfter25hAgain.canManageCustomEmojis).toBe(true);
});
});
});