Dwayne Harris 4 years ago
parent
commit
b89fa00333
  1. 4
      src/lib/authentication.ts
  2. 5
      src/lib/utils.ts
  3. 52
      src/plugins/api/apps.ts
  4. 5
      src/plugins/api/authentication.ts
  5. 29
      src/plugins/api/users.ts
  6. 10
      src/schemas.ts
  7. 7
      src/types/collections.ts

4
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<string> {
@ -8,7 +8,7 @@ export async function createAccessToken(userId: string): Promise<string> {
export function createRefreshToken(userId: string, userAgent: string, ip: string): UserToken {
return {
id: 'r' + v1().replace(/-/g, ''),
id: createToken(),
pk: userId,
t: UserItemType.Token,
userAgent,

5
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<void> {
return new Promise(resolve => {

52
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<Server, IncomingMessage, ServerResponse>) {
@ -653,7 +653,10 @@ function installationsRoute(server: FastifyInstance<Server, IncomingMessage, Ser
properties: {
id: { type: 'string' },
app: appSchema,
settings: { type: 'object' },
settings: {
type: 'object',
additionalProperties: true,
},
created: { type: 'number' },
},
},
@ -803,6 +806,50 @@ function setPreinstallRoute(server: FastifyInstance<Server, IncomingMessage, Ser
})
}
function updateSettingsRoute(server: FastifyInstance<Server, IncomingMessage, ServerResponse>) {
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<DefaultQuery, Params, DefaultHeaders, Body>('/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<Installation>()
if (!installation) return badRequestError(reply, 'Installation not found')
if (installation.userId !== request.viewer.id) return badRequestError(reply)
await installationItem.replace<Installation>({
...installation,
settings: request.body.settings,
})
reply.code(204)
})
}
const plugin: Plugin<Server, IncomingMessage, ServerResponse, PluginOptions> = async server => {
availabilityRoute(server)
appsRoute(server)
@ -815,6 +862,7 @@ const plugin: Plugin<Server, IncomingMessage, ServerResponse, PluginOptions> = a
installationsRoute(server)
activateRoute(server)
setPreinstallRoute(server)
updateSettingsRoute(server)
}
export default plugin

5
src/plugins/api/authentication.ts

@ -181,6 +181,11 @@ function registerRoute(server: FastifyInstance<Server, IncomingMessage, ServerRe
imageUrl,
coverImageUrl,
theme,
settings: {
allowThemeChange: true,
alwaysReveal: false,
autoPlayGifs: true,
},
installations,
awards: 0,
points: 0,

29
src/plugins/api/users.ts

@ -16,7 +16,7 @@ import { containerFor, createQuerySpec, queryItems, getItem, normalize } from '.
import { deleteMedia, attachMedia } from '../../lib/media'
import { MAX_NAME_LENGTH } from '../../constants'
import { userSchema, selfSchema, errorSchema } from '../../schemas'
import { userSchema, selfSchema, errorSchema, userSettingsSchema } from '../../schemas'
import {
User,
@ -28,6 +28,7 @@ import {
GroupItemType,
BlockType,
UserInverseSubscription,
UserSettings,
} from '../../types/collections'
import { PluginOptions } from '../../types'
@ -88,6 +89,7 @@ function updateRoute(server: FastifyInstance<Server, IncomingMessage, ServerResp
imageUrl?: string
coverImageUrl?: string
theme?: string
settings?: UserSettings
}
const options: RouteShorthandOptions = {
@ -108,6 +110,7 @@ function updateRoute(server: FastifyInstance<Server, IncomingMessage, ServerResp
imageUrl: { type: 'string' },
coverImageUrl: { type: 'string' },
theme: { type: 'string' },
settings: userSettingsSchema,
},
},
response: {
@ -136,13 +139,8 @@ function updateRoute(server: FastifyInstance<Server, IncomingMessage, ServerResp
if (about !== '') viewer.about = about
}
if (request.body.requiresApproval !== undefined) {
viewer.requiresApproval = request.body.requiresApproval
}
if (request.body.privacy) {
viewer.privacy = request.body.privacy
}
if (request.body.requiresApproval !== undefined) viewer.requiresApproval = request.body.requiresApproval
if (request.body.privacy) viewer.privacy = request.body.privacy
const mediaContainer = containerFor(server.database.client, 'Media')
@ -152,17 +150,10 @@ function updateRoute(server: FastifyInstance<Server, IncomingMessage, ServerResp
if (!viewer.imageUrl && request.body.imageUrl) await attachMedia(mediaContainer, request.body.imageUrl)
if (!viewer.coverImageUrl && request.body.coverImageUrl) await attachMedia(mediaContainer, request.body.coverImageUrl)
if (request.body.imageUrl) {
viewer.imageUrl = request.body.imageUrl
}
if (request.body.coverImageUrl) {
viewer.coverImageUrl = request.body.coverImageUrl
}
if (request.body.theme) {
viewer.theme = request.body.theme
}
if (request.body.imageUrl) viewer.imageUrl = request.body.imageUrl
if (request.body.coverImageUrl) viewer.coverImageUrl = request.body.coverImageUrl
if (request.body.theme) viewer.theme = request.body.theme
if (request.body.settings) viewer.settings = request.body.settings
await viewerItem.replace<User>(viewer)
return viewer

10
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' },

7
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

Loading…
Cancel
Save