diff --git a/src/lib/authentication.ts b/src/lib/authentication.ts index 20644a3..7ac94a3 100644 --- a/src/lib/authentication.ts +++ b/src/lib/authentication.ts @@ -1,5 +1,5 @@ -import { v1 } from 'uuid' import { JWT } from '../lib/crypto' +import { createRefreshToken as createToken } from '../lib/utils' import { UserToken, UserItemType } from '../types/collections' export async function createAccessToken(userId: string): Promise { @@ -8,7 +8,7 @@ export async function createAccessToken(userId: string): Promise { export function createRefreshToken(userId: string, userAgent: string, ip: string): UserToken { return { - id: 'r' + v1().replace(/-/g, ''), + id: createToken(), pk: userId, t: UserItemType.Token, userAgent, diff --git a/src/lib/utils.ts b/src/lib/utils.ts index ec29c87..9523742 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,4 +1,4 @@ -import { v1 } from 'uuid' +import { v4 } from 'uuid' import { generateString } from './crypto' export function trimContent(content?: string, length: number = 128): string { @@ -8,10 +8,11 @@ export function trimContent(content?: string, length: number = 128): string { return content.slice(0, length).trim() } -export const createId = () => v1().replace(/-/g, '') +export const createId = () => v4().replace(/-/g, '') export const createPostId = () => 'p' + createId() export const createInvitationCode = () => generateString(8) export const createInstallationId = () => 'i' + createId() +export const createRefreshToken = () => 'r' + createId() export async function wait(ms: number = 5000): Promise { return new Promise(resolve => { diff --git a/src/plugins/api/apps.ts b/src/plugins/api/apps.ts index 323aa32..864c34e 100644 --- a/src/plugins/api/apps.ts +++ b/src/plugins/api/apps.ts @@ -21,7 +21,7 @@ import { createInstallationId } from '../../lib/utils' import { APP_PARTITION_KEY, MAX_NAME_LENGTH, INSTALLATION_PARTITION_KEY } from '../../constants' -import { App, User, Installation } from '../../types/collections' +import { App, User, Installation, UserSettings, InstallationSettings } from '../../types/collections' import { PluginOptions } from '../../types' function availabilityRoute(server: FastifyInstance) { @@ -653,7 +653,10 @@ function installationsRoute(server: FastifyInstance) { + interface Params { + id: string + } + + interface Body { + settings: InstallationSettings + } + + const options: RouteShorthandOptions = { + schema: { + body: { + type: 'object', + required: ['settings'], + properties: { + settings: { type: 'object' }, + }, + }, + response: { + 400: errorSchema, + } + }, + } + + server.put('/api/installation/:id/settings', options, async (request, reply) => { + if (!server.database) return serverError(reply) + if (!request.viewer) return unauthorizedError(reply) + + const container = containerFor(server.database.client, 'Apps') + const installationItem = container.item(request.params.id, INSTALLATION_PARTITION_KEY) + const { resource: installation } = await installationItem.read() + + if (!installation) return badRequestError(reply, 'Installation not found') + if (installation.userId !== request.viewer.id) return badRequestError(reply) + + await installationItem.replace({ + ...installation, + settings: request.body.settings, + }) + + reply.code(204) + }) +} + const plugin: Plugin = async server => { availabilityRoute(server) appsRoute(server) @@ -815,6 +862,7 @@ const plugin: Plugin = a installationsRoute(server) activateRoute(server) setPreinstallRoute(server) + updateSettingsRoute(server) } export default plugin diff --git a/src/plugins/api/authentication.ts b/src/plugins/api/authentication.ts index f3ae08c..29a5924 100644 --- a/src/plugins/api/authentication.ts +++ b/src/plugins/api/authentication.ts @@ -181,6 +181,11 @@ function registerRoute(server: FastifyInstance(viewer) return viewer diff --git a/src/schemas.ts b/src/schemas.ts index 8448981..b163984 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -10,6 +10,15 @@ export const tokenResponseSchema: JSONSchema = { }, } +export const userSettingsSchema: JSONSchema = { + type: 'object', + properties: { + allowThemeChange: { type: 'boolean' }, + alwaysReveal: { type: 'boolean' }, + autoPlayGifs: { type: 'boolean' }, + }, +} + export const awardSchema: JSONSchema = { type: 'object', properties: { @@ -146,6 +155,7 @@ export const selfSchema: JSONSchema = { name: { type: 'string' }, email: { type: 'string' }, about: { type: 'string' }, + settings: userSettingsSchema, imageUrl: { type: 'string' }, coverImageUrl: { type: 'string' }, theme: { type: 'string' }, diff --git a/src/types/collections.ts b/src/types/collections.ts index d2f62ea..3117c4e 100644 --- a/src/types/collections.ts +++ b/src/types/collections.ts @@ -168,6 +168,12 @@ export interface GroupLog { created: number } +export interface UserSettings { + allowThemeChange: boolean + alwaysReveal: boolean + autoPlayGifs: boolean +} + export interface User { id: string pk: string // ID @@ -182,6 +188,7 @@ export interface User { email: string emailVerified: boolean passwordHash: string + settings: UserSettings installations: string[] awards: number // Total Awards points: number