mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-13 16:16:46 +08:00
@@ -0,0 +1,86 @@
|
||||
import test from 'ava';
|
||||
|
||||
import {
|
||||
createTestingApp,
|
||||
getSettings,
|
||||
TestingApp,
|
||||
updateSettings,
|
||||
} from '../../../__tests__/utils';
|
||||
|
||||
let app: TestingApp;
|
||||
|
||||
test.before(async () => {
|
||||
app = await createTestingApp();
|
||||
});
|
||||
|
||||
test.after.always(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
test('should get user settings', async t => {
|
||||
await app.signup();
|
||||
const settings = await getSettings(app);
|
||||
t.deepEqual(settings, {
|
||||
receiveInvitationEmail: true,
|
||||
receiveMentionEmail: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('should update user settings', async t => {
|
||||
await app.signup();
|
||||
await updateSettings(app, {
|
||||
receiveInvitationEmail: false,
|
||||
receiveMentionEmail: false,
|
||||
});
|
||||
const settings = await getSettings(app);
|
||||
t.deepEqual(settings, {
|
||||
receiveInvitationEmail: false,
|
||||
receiveMentionEmail: false,
|
||||
});
|
||||
|
||||
await updateSettings(app, {
|
||||
receiveMentionEmail: true,
|
||||
});
|
||||
const settings2 = await getSettings(app);
|
||||
t.deepEqual(settings2, {
|
||||
receiveInvitationEmail: false,
|
||||
receiveMentionEmail: true,
|
||||
});
|
||||
|
||||
await updateSettings(app, {
|
||||
// ignore undefined value
|
||||
receiveInvitationEmail: undefined,
|
||||
});
|
||||
const settings3 = await getSettings(app);
|
||||
t.deepEqual(settings3, {
|
||||
receiveInvitationEmail: false,
|
||||
receiveMentionEmail: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('should throw error when update user settings with invalid input', async t => {
|
||||
await app.signup();
|
||||
await t.throwsAsync(
|
||||
updateSettings(app, {
|
||||
receiveInvitationEmail: false,
|
||||
// @ts-expect-error invalid value
|
||||
receiveMentionEmail: null,
|
||||
}),
|
||||
{
|
||||
message: /Expected boolean, received null/,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('should not update user settings when not logged in', async t => {
|
||||
await app.logout();
|
||||
await t.throwsAsync(
|
||||
updateSettings(app, {
|
||||
receiveInvitationEmail: false,
|
||||
receiveMentionEmail: false,
|
||||
}),
|
||||
{
|
||||
message: 'You must sign in first to access this resource.',
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -4,11 +4,20 @@ import { PermissionModule } from '../permission';
|
||||
import { StorageModule } from '../storage';
|
||||
import { UserAvatarController } from './controller';
|
||||
import { UserEventsListener } from './event';
|
||||
import { UserManagementResolver, UserResolver } from './resolver';
|
||||
import {
|
||||
UserManagementResolver,
|
||||
UserResolver,
|
||||
UserSettingsResolver,
|
||||
} from './resolver';
|
||||
|
||||
@Module({
|
||||
imports: [StorageModule, PermissionModule],
|
||||
providers: [UserResolver, UserManagementResolver, UserEventsListener],
|
||||
providers: [
|
||||
UserResolver,
|
||||
UserManagementResolver,
|
||||
UserEventsListener,
|
||||
UserSettingsResolver,
|
||||
],
|
||||
controllers: [UserAvatarController],
|
||||
})
|
||||
export class UserModule {}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Mutation,
|
||||
ObjectType,
|
||||
Query,
|
||||
ResolveField,
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
@@ -19,7 +20,7 @@ import {
|
||||
Throttle,
|
||||
UserNotFound,
|
||||
} from '../../base';
|
||||
import { Models } from '../../models';
|
||||
import { Models, SettingsSchema } from '../../models';
|
||||
import { Public } from '../auth/guard';
|
||||
import { sessionUser } from '../auth/service';
|
||||
import { CurrentUser } from '../auth/session';
|
||||
@@ -31,6 +32,8 @@ import {
|
||||
ManageUserInput,
|
||||
PublicUserType,
|
||||
RemoveAvatar,
|
||||
SettingsType,
|
||||
UpdateSettingsInput,
|
||||
UpdateUserInput,
|
||||
UserOrLimitedUser,
|
||||
UserType,
|
||||
@@ -155,6 +158,33 @@ export class UserResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Resolver(() => UserType)
|
||||
export class UserSettingsResolver {
|
||||
constructor(private readonly models: Models) {}
|
||||
|
||||
@Mutation(() => Boolean, {
|
||||
name: 'updateSettings',
|
||||
description: 'Update user settings',
|
||||
})
|
||||
async updateSettings(
|
||||
@CurrentUser() user: CurrentUser,
|
||||
@Args('input', { type: () => UpdateSettingsInput })
|
||||
input: UpdateSettingsInput
|
||||
) {
|
||||
SettingsSchema.parse(input);
|
||||
await this.models.settings.set(user.id, input);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ResolveField(() => SettingsType, {
|
||||
name: 'settings',
|
||||
description: 'Get user settings',
|
||||
})
|
||||
async getSettings(@CurrentUser() me: CurrentUser): Promise<SettingsType> {
|
||||
return await this.models.settings.get(me.id);
|
||||
}
|
||||
}
|
||||
|
||||
@InputType()
|
||||
class ListUserInput {
|
||||
@Field(() => Int, { nullable: true, defaultValue: 0 })
|
||||
|
||||
@@ -7,7 +7,12 @@ import {
|
||||
} from '@nestjs/graphql';
|
||||
import type { User } from '@prisma/client';
|
||||
|
||||
import { PublicUser, WorkspaceUser } from '../../models';
|
||||
import {
|
||||
PublicUser,
|
||||
Settings,
|
||||
SettingsInput,
|
||||
WorkspaceUser,
|
||||
} from '../../models';
|
||||
import { type CurrentUser } from '../auth/session';
|
||||
|
||||
@ObjectType()
|
||||
@@ -109,6 +114,15 @@ export class RemoveAvatar {
|
||||
success!: boolean;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
export class SettingsType implements Settings {
|
||||
@Field({ description: 'Receive invitation email' })
|
||||
receiveInvitationEmail!: boolean;
|
||||
|
||||
@Field({ description: 'Receive mention email' })
|
||||
receiveMentionEmail!: boolean;
|
||||
}
|
||||
|
||||
@InputType()
|
||||
export class UpdateUserInput implements Partial<User> {
|
||||
@Field({ description: 'User name', nullable: true })
|
||||
@@ -123,3 +137,12 @@ export class ManageUserInput {
|
||||
@Field({ description: 'User name', nullable: true })
|
||||
name?: string;
|
||||
}
|
||||
|
||||
@InputType()
|
||||
export class UpdateSettingsInput implements SettingsInput {
|
||||
@Field({ description: 'Receive invitation email', nullable: true })
|
||||
receiveInvitationEmail?: boolean;
|
||||
|
||||
@Field({ description: 'Receive mention email', nullable: true })
|
||||
receiveMentionEmail?: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user