mirror of https://github.com/requarks/wiki
parent
dc78af9156
commit
68e6a2787a
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
"$schema": "./backend/node_modules/oxfmt/configuration_schema.json",
|
||||||
"semi": false,
|
"semi": false,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"eslint.enable": false,
|
"eslint.enable": false,
|
||||||
"editor.formatOnSave": false,
|
|
||||||
"editor.tabSize": 2,
|
"editor.tabSize": 2,
|
||||||
"i18n-ally.localesPaths": [
|
"i18n-ally.localesPaths": ["backend/locales"],
|
||||||
"backend/locales",
|
|
||||||
],
|
|
||||||
"i18n-ally.pathMatcher": "{locale}.json",
|
"i18n-ally.pathMatcher": "{locale}.json",
|
||||||
"i18n-ally.keystyle": "flat",
|
"i18n-ally.keystyle": "flat",
|
||||||
"i18n-ally.sortKeys": true,
|
"i18n-ally.sortKeys": true,
|
||||||
"i18n-ally.enabledFrameworks": [
|
"i18n-ally.enabledFrameworks": ["vue"],
|
||||||
"vue"
|
"[javascript]": {
|
||||||
]
|
"editor.defaultFormatter": "oxc.oxc-vscode",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.formatOnSaveMode": "file"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,100 +1,204 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Authentication API Routes
|
* Authentication API Routes
|
||||||
*/
|
*/
|
||||||
async function routes (app, options) {
|
async function routes(app, options) {
|
||||||
/**
|
/**
|
||||||
* GET SITE AUTHENTICATION STRATEGIES
|
* GET SITE AUTHENTICATION STRATEGIES
|
||||||
*/
|
*/
|
||||||
app.get('/sites/:siteId/auth/strategies', {
|
app.get(
|
||||||
schema: {
|
'/sites/:siteId/auth/strategies',
|
||||||
summary: 'List all site authentication strategies',
|
{
|
||||||
tags: ['Authentication'],
|
schema: {
|
||||||
params: {
|
summary: 'List all site authentication strategies',
|
||||||
type: 'object',
|
tags: ['Authentication'],
|
||||||
properties: {
|
params: {
|
||||||
siteId: {
|
type: 'object',
|
||||||
type: 'string',
|
properties: {
|
||||||
format: 'uuid'
|
siteId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
querystring: {
|
||||||
querystring: {
|
type: 'object',
|
||||||
type: 'object',
|
properties: {
|
||||||
properties: {
|
visibleOnly: {
|
||||||
visibleOnly: {
|
type: 'boolean',
|
||||||
type: 'boolean',
|
default: false
|
||||||
default: false
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}, async (req, reply) => {
|
async (req, reply) => {
|
||||||
const site = await WIKI.models.sites.getSiteById({ id: req.params.siteId })
|
const site = await WIKI.models.sites.getSiteById({ id: req.params.siteId })
|
||||||
const activeStrategies = await WIKI.models.authentication.getStrategies({ enabledOnly: true })
|
if (!site) {
|
||||||
const siteStrategies = activeStrategies.map(str => {
|
return reply.badRequest('Invalid Site ID')
|
||||||
const authModule = WIKI.data.authentication.find(m => m.key === str.module)
|
|
||||||
const siteStr = site.config.authStrategies.find(s => s.id === str.id) || {}
|
|
||||||
return {
|
|
||||||
id: str.id,
|
|
||||||
displayName: str.displayName,
|
|
||||||
useForm: authModule.useForm,
|
|
||||||
usernameType: authModule.usernameType,
|
|
||||||
color: authModule.color,
|
|
||||||
icon: authModule.icon,
|
|
||||||
order: siteStr.order ?? 0,
|
|
||||||
isVisible: siteStr.isVisible ?? false
|
|
||||||
}
|
}
|
||||||
}).sort((a,b) => a.order - b.order)
|
const activeStrategies = await WIKI.models.authentication.getStrategies({ enabledOnly: true })
|
||||||
return req.query.visibleOnly ? siteStrategies.filter(s => s.isVisible) : siteStrategies
|
const siteStrategies = activeStrategies
|
||||||
})
|
.map((str) => {
|
||||||
|
const authModule = WIKI.data.authentication.find((m) => m.key === str.module)
|
||||||
|
const siteStr = site.config.authStrategies.find((s) => s.id === str.id) || {}
|
||||||
|
return {
|
||||||
|
id: str.id,
|
||||||
|
displayName: str.displayName,
|
||||||
|
useForm: authModule.useForm,
|
||||||
|
usernameType: authModule.usernameType,
|
||||||
|
color: authModule.color,
|
||||||
|
icon: authModule.icon,
|
||||||
|
order: siteStr.order ?? 0,
|
||||||
|
isVisible: siteStr.isVisible ?? false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sort((a, b) => a.order - b.order)
|
||||||
|
return req.query.visibleOnly ? siteStrategies.filter((s) => s.isVisible) : siteStrategies
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LOGIN USING USER/PASS
|
* LOGIN USING USER/PASS
|
||||||
*/
|
*/
|
||||||
app.post('/sites/:siteId/auth/login', {
|
app.put(
|
||||||
schema: {
|
'/sites/:siteId/auth/login',
|
||||||
summary: 'Login',
|
{
|
||||||
tags: ['Authentication'],
|
schema: {
|
||||||
params: {
|
summary: 'Login',
|
||||||
type: 'object',
|
tags: ['Authentication'],
|
||||||
properties: {
|
params: {
|
||||||
siteId: {
|
type: 'object',
|
||||||
type: 'string',
|
properties: {
|
||||||
format: 'uuid'
|
siteId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
type: 'object',
|
||||||
|
required: ['strategyId'],
|
||||||
|
properties: {
|
||||||
|
strategyId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 255
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 255
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
body: {
|
},
|
||||||
type: 'object',
|
async (req, reply) => {
|
||||||
required: ['strategyId', 'username', 'password'],
|
try {
|
||||||
properties: {
|
const result = await WIKI.models.users.login(
|
||||||
strategyId: {
|
{
|
||||||
type: 'string',
|
siteId: req.params.siteId,
|
||||||
format: 'uuid'
|
strategyId: req.body.strategyId,
|
||||||
},
|
username: req.body.username,
|
||||||
username: {
|
password: req.body.password,
|
||||||
type: 'string',
|
ip: req.ip
|
||||||
minLength: 1,
|
|
||||||
maxLength: 255
|
|
||||||
},
|
},
|
||||||
password: {
|
req
|
||||||
type: 'string',
|
)
|
||||||
minLength: 1,
|
if (!result) {
|
||||||
maxLength: 255
|
throw new Error('Unexpected empty login response.')
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
...result
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (err.message.startsWith('ERR_')) {
|
||||||
|
return reply.badRequest(err.message)
|
||||||
|
} else {
|
||||||
|
WIKI.logger.info(err) // TODO: change to debug once stable
|
||||||
|
return reply.badRequest('ERR_LOGIN_FAILED')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CHANGE PASSWORD
|
||||||
|
*/
|
||||||
|
app.put(
|
||||||
|
'/sites/:siteId/auth/changePassword',
|
||||||
|
{
|
||||||
|
schema: {
|
||||||
|
summary: 'Change Password From Login',
|
||||||
|
tags: ['Authentication'],
|
||||||
|
params: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
siteId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
type: 'object',
|
||||||
|
required: ['strategyId', 'continuationToken', 'newPassword'],
|
||||||
|
properties: {
|
||||||
|
strategyId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
},
|
||||||
|
continuationToken: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 255
|
||||||
|
},
|
||||||
|
newPassword: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 255
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async (req, reply) => {
|
||||||
|
try {
|
||||||
|
const result = await WIKI.models.users.loginChangePassword(
|
||||||
|
{
|
||||||
|
siteId: req.params.siteId,
|
||||||
|
strategyId: req.body.strategyId,
|
||||||
|
continuationToken: req.body.continuationToken,
|
||||||
|
newPassword: req.body.newPassword,
|
||||||
|
ip: req.ip
|
||||||
|
},
|
||||||
|
req
|
||||||
|
)
|
||||||
|
if (!result) {
|
||||||
|
throw new Error('Unexpected empty change password response.')
|
||||||
|
}
|
||||||
|
if (result?.authenticated) {
|
||||||
|
req.session.authenticated = true
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
...result
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (err.message.startsWith('ERR_')) {
|
||||||
|
return reply.badRequest(err.message)
|
||||||
|
} else {
|
||||||
|
WIKI.logger.debug(err)
|
||||||
|
return reply.badRequest('ERR_CHANGE_PASSWORD_FAILED')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, async (req, reply) => {
|
)
|
||||||
return WIKI.models.users.login({
|
|
||||||
siteId: req.params.siteId,
|
|
||||||
strategyId: req.body.strategyId,
|
|
||||||
username: req.body.username,
|
|
||||||
password: req.body.password,
|
|
||||||
ip: req.ip
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default routes
|
export default routes
|
||||||
|
|||||||
@ -1,92 +1,101 @@
|
|||||||
/**
|
/**
|
||||||
* Pages API Routes
|
* Pages API Routes
|
||||||
*/
|
*/
|
||||||
async function routes (app, options) {
|
async function routes(app, options) {
|
||||||
app.get('/sites/:siteId/pages', {
|
app.get(
|
||||||
schema: {
|
'/sites/:siteId/pages',
|
||||||
summary: 'List all pages',
|
{
|
||||||
tags: ['Pages'],
|
schema: {
|
||||||
params: {
|
summary: 'List all pages',
|
||||||
type: 'object',
|
tags: ['Pages'],
|
||||||
properties: {
|
params: {
|
||||||
siteId: {
|
type: 'object',
|
||||||
type: 'string',
|
properties: {
|
||||||
format: 'uuid'
|
siteId: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async (req, reply) => {
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
}, async (req, reply) => {
|
)
|
||||||
return []
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get('/sites/:siteId/pages/:pageIdOrHash', {
|
app.get(
|
||||||
schema: {
|
'/sites/:siteId/pages/:pageIdOrHash',
|
||||||
summary: 'List all pages',
|
{
|
||||||
tags: ['Pages'],
|
schema: {
|
||||||
params: {
|
summary: 'List all pages',
|
||||||
type: 'object',
|
tags: ['Pages'],
|
||||||
properties: {
|
params: {
|
||||||
siteId: {
|
type: 'object',
|
||||||
type: 'string',
|
properties: {
|
||||||
format: 'uuid'
|
siteId: {
|
||||||
},
|
type: 'string',
|
||||||
pageIdOrHash: {
|
format: 'uuid'
|
||||||
type: 'string',
|
},
|
||||||
oneOf: [
|
pageIdOrHash: {
|
||||||
{ format: 'uuid' },
|
type: 'string',
|
||||||
{ pattern: '^[a-f0-9]+$' }
|
oneOf: [{ format: 'uuid' }, { pattern: '^[a-f0-9]+$' }]
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
querystring: {
|
||||||
querystring: {
|
type: 'object',
|
||||||
type: 'object',
|
properties: {
|
||||||
properties: {
|
withContent: {
|
||||||
withContent: {
|
type: 'boolean',
|
||||||
type: 'boolean',
|
default: false
|
||||||
default: false
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async (req, reply) => {
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
}, async (req, reply) => {
|
)
|
||||||
return []
|
|
||||||
})
|
|
||||||
|
|
||||||
app.post('/sites/:siteId/pages/userPermissions', {
|
app.post(
|
||||||
schema: {
|
'/sites/:siteId/pages/userPermissions',
|
||||||
summary: 'Get page user permissions',
|
{
|
||||||
tags: ['Pages'],
|
schema: {
|
||||||
params: {
|
summary: 'Get page user permissions',
|
||||||
type: 'object',
|
tags: ['Pages'],
|
||||||
properties: {
|
params: {
|
||||||
siteId: {
|
type: 'object',
|
||||||
type: 'string',
|
properties: {
|
||||||
format: 'uuid'
|
siteId: {
|
||||||
}
|
type: 'string',
|
||||||
}
|
format: 'uuid'
|
||||||
},
|
}
|
||||||
body: {
|
|
||||||
type: 'object',
|
|
||||||
required: ['path'],
|
|
||||||
properties: {
|
|
||||||
path: {
|
|
||||||
type: 'string',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 255
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
examples: [
|
body: {
|
||||||
{
|
type: 'object',
|
||||||
path: 'foo/bar'
|
required: ['path'],
|
||||||
}
|
properties: {
|
||||||
]
|
path: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 1,
|
||||||
|
maxLength: 255
|
||||||
|
}
|
||||||
|
},
|
||||||
|
examples: [
|
||||||
|
{
|
||||||
|
path: 'foo/bar'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async (req, reply) => {
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
}, async (req, reply) => {
|
)
|
||||||
return []
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default routes
|
export default routes
|
||||||
|
|||||||
@ -1,24 +1,74 @@
|
|||||||
|
import path from 'node:path'
|
||||||
|
import os from 'node:os'
|
||||||
|
import { DateTime } from 'luxon'
|
||||||
|
import { filesize } from 'filesize'
|
||||||
|
import { isNil } from 'es-toolkit/predicate'
|
||||||
|
import { gte, sql } from 'drizzle-orm'
|
||||||
|
import {
|
||||||
|
groups as groupsTable,
|
||||||
|
pages as pagesTable,
|
||||||
|
tags as tagsTable,
|
||||||
|
users as usersTable
|
||||||
|
} from '../db/schema.mjs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* System API Routes
|
* System API Routes
|
||||||
*/
|
*/
|
||||||
async function routes (app, options) {
|
async function routes(app, options) {
|
||||||
app.get('/info', {
|
app.get(
|
||||||
schema: {
|
'/info',
|
||||||
summary: 'System Info',
|
{
|
||||||
tags: ['System']
|
config: {
|
||||||
|
permissions: ['read:dashboard', 'manage:sites']
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
summary: 'System Info',
|
||||||
|
tags: ['System']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (request, reply) => {
|
||||||
|
return {
|
||||||
|
configFile: path.join(process.cwd(), 'config.yml'),
|
||||||
|
cpuCores: os.cpus().length,
|
||||||
|
currentVersion: WIKI.version,
|
||||||
|
dbHost: WIKI.config.db.host,
|
||||||
|
dbVersion: WIKI.dbManager.VERSION,
|
||||||
|
groupsTotal: await WIKI.db.$count(groupsTable),
|
||||||
|
hostname: os.hostname(),
|
||||||
|
httpPort: 0,
|
||||||
|
isMailConfigured: WIKI.config?.mail?.host?.length > 2,
|
||||||
|
isSchedulerHealthy: true,
|
||||||
|
latestVersion: WIKI.config.update.version,
|
||||||
|
latestVersionReleaseDate: DateTime.fromISO(WIKI.config.update.versionDate).toJSDate(),
|
||||||
|
loginsPastDay: await WIKI.db.$count(
|
||||||
|
usersTable,
|
||||||
|
gte(usersTable.lastLoginAt, sql`NOW() - INTERVAL '1 DAY'`)
|
||||||
|
),
|
||||||
|
nodeVersion: process.version.substring(1),
|
||||||
|
operatingSystem: `${os.type()} (${os.platform()}) ${os.release()} ${os.arch()}`,
|
||||||
|
pagesTotal: await WIKI.db.$count(pagesTable),
|
||||||
|
platform: os.platform(),
|
||||||
|
ramTotal: filesize(os.totalmem()),
|
||||||
|
tagsTotal: await WIKI.db.$count(tagsTable),
|
||||||
|
upgradeCapable: !isNil(process.env.UPGRADE_COMPANION),
|
||||||
|
usersTotal: await WIKI.db.$count(usersTable),
|
||||||
|
workingDirectory: process.cwd()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, async (request, reply) => {
|
)
|
||||||
return { hello: 'world' }
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get('/flags', {
|
app.get(
|
||||||
schema: {
|
'/flags',
|
||||||
summary: 'System Flags',
|
{
|
||||||
tags: ['System']
|
schema: {
|
||||||
|
summary: 'System Flags',
|
||||||
|
tags: ['System']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (request, reply) => {
|
||||||
|
return WIKI.config.flags
|
||||||
}
|
}
|
||||||
}, async (request, reply) => {
|
)
|
||||||
return { hello: 'world' }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default routes
|
export default routes
|
||||||
|
|||||||
@ -1,51 +1,95 @@
|
|||||||
/**
|
/**
|
||||||
* Users API Routes
|
* Users API Routes
|
||||||
*/
|
*/
|
||||||
async function routes (app, options) {
|
async function routes(app, options) {
|
||||||
app.get('/', {
|
app.get(
|
||||||
schema: {
|
'/',
|
||||||
summary: 'List all users',
|
{
|
||||||
tags: ['Users']
|
schema: {
|
||||||
|
summary: 'List all users',
|
||||||
|
tags: ['Users']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (request, reply) => {
|
||||||
|
return { hello: 'world' }
|
||||||
}
|
}
|
||||||
}, async (request, reply) => {
|
)
|
||||||
return { hello: 'world' }
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get('/:userId', {
|
app.get(
|
||||||
schema: {
|
'/whoami',
|
||||||
summary: 'Get user info',
|
{
|
||||||
tags: ['Users']
|
schema: {
|
||||||
|
summary: 'Get currently logged in user info',
|
||||||
|
tags: ['Users']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (req, reply) => {
|
||||||
|
reply.preventCache()
|
||||||
|
if (req.session?.authenticated) {
|
||||||
|
return {
|
||||||
|
authenticated: true,
|
||||||
|
...req.session.user,
|
||||||
|
permissions: ['manage:system']
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
authenticated: false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, async (request, reply) => {
|
)
|
||||||
return { hello: 'world' }
|
|
||||||
})
|
|
||||||
|
|
||||||
app.post('/', {
|
app.get(
|
||||||
schema: {
|
'/:userId',
|
||||||
summary: 'Create a new user',
|
{
|
||||||
tags: ['Users']
|
schema: {
|
||||||
|
summary: 'Get user info',
|
||||||
|
tags: ['Users']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (request, reply) => {
|
||||||
|
return { hello: 'world' }
|
||||||
}
|
}
|
||||||
}, async (request, reply) => {
|
)
|
||||||
return { hello: 'world' }
|
|
||||||
})
|
|
||||||
|
|
||||||
app.put('/:userId', {
|
app.post(
|
||||||
schema: {
|
'/',
|
||||||
summary: 'Update a user',
|
{
|
||||||
tags: ['Users']
|
schema: {
|
||||||
|
summary: 'Create a new user',
|
||||||
|
tags: ['Users']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (request, reply) => {
|
||||||
|
return { hello: 'world' }
|
||||||
}
|
}
|
||||||
}, async (request, reply) => {
|
)
|
||||||
return { hello: 'world' }
|
|
||||||
})
|
|
||||||
|
|
||||||
app.delete('/:userId', {
|
app.put(
|
||||||
schema: {
|
'/:userId',
|
||||||
summary: 'Delete a user',
|
{
|
||||||
tags: ['Users']
|
schema: {
|
||||||
|
summary: 'Update a user',
|
||||||
|
tags: ['Users']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (request, reply) => {
|
||||||
|
return { hello: 'world' }
|
||||||
}
|
}
|
||||||
}, async (request, reply) => {
|
)
|
||||||
return { hello: 'world' }
|
|
||||||
})
|
app.delete(
|
||||||
|
'/:userId',
|
||||||
|
{
|
||||||
|
schema: {
|
||||||
|
summary: 'Delete a user',
|
||||||
|
tags: ['Users']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (request, reply) => {
|
||||||
|
return { hello: 'world' }
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default routes
|
export default routes
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
import { defineRelations } from 'drizzle-orm'
|
import { defineRelations } from 'drizzle-orm'
|
||||||
import * as schema from './schema.mjs'
|
import * as schema from './schema.mjs'
|
||||||
|
|
||||||
export const relations = defineRelations(schema,
|
export const relations = defineRelations(schema, (r) => ({
|
||||||
r => ({
|
users: {
|
||||||
users: {
|
groups: r.many.groups({
|
||||||
groups: r.many.groups({
|
from: r.users.id.through(r.userGroups.userId),
|
||||||
from: r.users.id.through(r.userGroups.userId),
|
to: r.groups.id.through(r.userGroups.groupId)
|
||||||
to: r.groups.id.through(r.userGroups.groupId)
|
})
|
||||||
})
|
},
|
||||||
},
|
groups: {
|
||||||
groups: {
|
members: r.many.users()
|
||||||
members: r.many.users()
|
},
|
||||||
}
|
userKeys: {
|
||||||
})
|
user: r.one.users({
|
||||||
)
|
from: r.userKeys.userId,
|
||||||
|
to: r.users.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|||||||
@ -0,0 +1,85 @@
|
|||||||
|
import { eq, sql } from 'drizzle-orm'
|
||||||
|
import { sessions as sessionsTable } from '../db/schema.mjs'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sessions model
|
||||||
|
*/
|
||||||
|
class Sessions {
|
||||||
|
/**
|
||||||
|
* Fetch all sessions from a single user
|
||||||
|
*
|
||||||
|
* @param {String} userId User ID
|
||||||
|
* @returns Promise<Array> User Sessions
|
||||||
|
*/
|
||||||
|
async getByUser(userId) {
|
||||||
|
return WIKI.db.select().from(sessionsTable).where(eq(sessionsTable.userId, userId))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a single session by id
|
||||||
|
*
|
||||||
|
* @param {String} id Session ID
|
||||||
|
* @returns Promise<Object> Session data
|
||||||
|
*/
|
||||||
|
async get(id) {
|
||||||
|
const res = await WIKI.db.select().from(sessionsTable).where(eq(sessionsTable.id, id))
|
||||||
|
return res?.[0]?.data ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set / Update a session
|
||||||
|
*
|
||||||
|
* @param {String} id Session ID
|
||||||
|
* @param {Object} data Session Data
|
||||||
|
*/
|
||||||
|
async set(id, data) {
|
||||||
|
await WIKI.db
|
||||||
|
.insert(sessionsTable)
|
||||||
|
.values([
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
userId: data?.user?.id ?? null,
|
||||||
|
data
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: sessionsTable.id,
|
||||||
|
set: {
|
||||||
|
data,
|
||||||
|
userId: data?.user?.id ?? null,
|
||||||
|
updatedAt: sql`now()`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a session
|
||||||
|
*
|
||||||
|
* @param {String} id Session ID
|
||||||
|
* @returns Promise<void>
|
||||||
|
*/
|
||||||
|
async destroy(id) {
|
||||||
|
return WIKI.db.delete(sessionsTable).where(eq(sessionsTable.id, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all sessions from all users
|
||||||
|
*
|
||||||
|
* @returns Promise<void>
|
||||||
|
*/
|
||||||
|
async clearAllSessions() {
|
||||||
|
return WIKI.db.delete(sessionsTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all sessions from a single user
|
||||||
|
*
|
||||||
|
* @param {String} userId User ID
|
||||||
|
* @returns Promise<void>
|
||||||
|
*/
|
||||||
|
async clearSessionsFromUser(userId) {
|
||||||
|
return WIKI.db.delete(sessionsTable).where(eq(sessionsTable.userId, userId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sessions = new Sessions()
|
||||||
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"bracketSameLine": true,
|
|
||||||
"endOfLine": "lf",
|
|
||||||
"insertFinalNewline": true
|
|
||||||
}
|
|
||||||
Loading…
Reference in new issue