| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787 | 
							- import { v4 as uuid } from 'uuid'
 
- import bcrypt from 'bcryptjs'
 
- import crypto from 'node:crypto'
 
- import { DateTime } from 'luxon'
 
- import { pem2jwk } from 'pem-jwk'
 
- export async function up (knex) {
 
-   WIKI.logger.info('Running 3.0.0 database migration...')
 
-   // =====================================
 
-   // PG EXTENSIONS
 
-   // =====================================
 
-   await knex.raw('CREATE EXTENSION IF NOT EXISTS ltree;')
 
-   await knex.raw('CREATE EXTENSION IF NOT EXISTS pgcrypto;')
 
-   await knex.schema
 
-     // =====================================
 
-     // MODEL TABLES
 
-     // =====================================
 
-     // ACTIVITY LOGS -----------------------
 
-     .createTable('activityLogs', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.timestamp('ts').notNullable().defaultTo(knex.fn.now())
 
-       table.string('action').notNullable()
 
-       table.jsonb('meta').notNullable()
 
-     })
 
-     // ANALYTICS ---------------------------
 
-     .createTable('analytics', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('module').notNullable()
 
-       table.boolean('isEnabled').notNullable().defaultTo(false)
 
-       table.jsonb('config').notNullable()
 
-     })
 
-     // API KEYS ----------------------------
 
-     .createTable('apiKeys', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('name').notNullable()
 
-       table.text('key').notNullable()
 
-       table.timestamp('expiration').notNullable().defaultTo(knex.fn.now())
 
-       table.boolean('isRevoked').notNullable().defaultTo(false)
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // ASSETS ------------------------------
 
-     .createTable('assets', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('fileName').notNullable()
 
-       table.string('fileExt').notNullable()
 
-       table.boolean('isSystem').notNullable().defaultTo(false)
 
-       table.enum('kind', ['document', 'image', 'other']).notNullable().defaultTo('other')
 
-       table.string('mimeType').notNullable().defaultTo('application/octet-stream')
 
-       table.integer('fileSize').unsigned().comment('In bytes')
 
-       table.jsonb('meta').notNullable().defaultTo('{}')
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-       table.binary('data')
 
-       table.binary('preview')
 
-       table.enum('previewState', ['none', 'pending', 'ready', 'failed']).notNullable().defaultTo('none')
 
-       table.jsonb('storageInfo')
 
-     })
 
-     // AUTHENTICATION ----------------------
 
-     .createTable('authentication', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('module').notNullable()
 
-       table.boolean('isEnabled').notNullable().defaultTo(false)
 
-       table.string('displayName').notNullable().defaultTo('')
 
-       table.jsonb('config').notNullable().defaultTo('{}')
 
-       table.boolean('selfRegistration').notNullable().defaultTo(false)
 
-       table.jsonb('domainWhitelist').notNullable().defaultTo('[]')
 
-       table.jsonb('autoEnrollGroups').notNullable().defaultTo('[]')
 
-     })
 
-     .createTable('commentProviders', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('module').notNullable()
 
-       table.boolean('isEnabled').notNullable().defaultTo(false)
 
-       table.json('config').notNullable()
 
-     })
 
-     // COMMENTS ----------------------------
 
-     .createTable('comments', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.uuid('replyTo')
 
-       table.text('content').notNullable()
 
-       table.text('render').notNullable().defaultTo('')
 
-       table.string('name').notNullable().defaultTo('')
 
-       table.string('email').notNullable().defaultTo('')
 
-       table.string('ip').notNullable().defaultTo('')
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // GROUPS ------------------------------
 
-     .createTable('groups', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('name').notNullable()
 
-       table.jsonb('permissions').notNullable()
 
-       table.jsonb('rules').notNullable()
 
-       table.string('redirectOnLogin').notNullable().defaultTo('')
 
-       table.string('redirectOnFirstLogin').notNullable().defaultTo('')
 
-       table.string('redirectOnLogout').notNullable().defaultTo('')
 
-       table.boolean('isSystem').notNullable().defaultTo(false)
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // HOOKS -------------------------------
 
-     .createTable('hooks', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('name').notNullable()
 
-       table.jsonb('events').notNullable().defaultTo('[]')
 
-       table.string('url').notNullable()
 
-       table.boolean('includeMetadata').notNullable().defaultTo(false)
 
-       table.boolean('includeContent').notNullable().defaultTo(false)
 
-       table.boolean('acceptUntrusted').notNullable().defaultTo(false)
 
-       table.string('authHeader')
 
-       table.enum('state', ['pending', 'error', 'success']).notNullable().defaultTo('pending')
 
-       table.string('lastErrorMessage')
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // JOB HISTORY -------------------------
 
-     .createTable('jobHistory', table => {
 
-       table.uuid('id').notNullable().primary()
 
-       table.string('task').notNullable()
 
-       table.enum('state', ['active', 'completed', 'failed', 'interrupted']).notNullable()
 
-       table.boolean('useWorker').notNullable().defaultTo(false)
 
-       table.boolean('wasScheduled').notNullable().defaultTo(false)
 
-       table.jsonb('payload')
 
-       table.integer('attempt').notNullable().defaultTo(1)
 
-       table.integer('maxRetries').notNullable().defaultTo(0)
 
-       table.text('lastErrorMessage')
 
-       table.string('executedBy')
 
-       table.timestamp('createdAt').notNullable()
 
-       table.timestamp('startedAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('completedAt')
 
-     })
 
-     // JOB SCHEDULE ------------------------
 
-     .createTable('jobSchedule', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('task').notNullable()
 
-       table.string('cron').notNullable()
 
-       table.string('type').notNullable().defaultTo('system')
 
-       table.jsonb('payload')
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // JOB SCHEDULE ------------------------
 
-     .createTable('jobLock', table => {
 
-       table.string('key').notNullable().primary()
 
-       table.string('lastCheckedBy')
 
-       table.timestamp('lastCheckedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // JOBS --------------------------------
 
-     .createTable('jobs', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('task').notNullable()
 
-       table.boolean('useWorker').notNullable().defaultTo(false)
 
-       table.jsonb('payload')
 
-       table.integer('retries').notNullable().defaultTo(0)
 
-       table.integer('maxRetries').notNullable().defaultTo(0)
 
-       table.timestamp('waitUntil')
 
-       table.boolean('isScheduled').notNullable().defaultTo(false)
 
-       table.string('createdBy')
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // LOCALES -----------------------------
 
-     .createTable('locales', table => {
 
-       table.string('code', 5).notNullable().primary()
 
-       table.jsonb('strings')
 
-       table.boolean('isRTL').notNullable().defaultTo(false)
 
-       table.string('name').notNullable()
 
-       table.string('nativeName').notNullable()
 
-       table.integer('availability').notNullable().defaultTo(0)
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // NAVIGATION ----------------------------
 
-     .createTable('navigation', table => {
 
-       table.string('key').notNullable().primary()
 
-       table.jsonb('config')
 
-     })
 
-     // PAGE HISTORY ------------------------
 
-     .createTable('pageHistory', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.uuid('pageId').notNullable().index()
 
-       table.string('action').defaultTo('updated')
 
-       table.jsonb('affectedFields').notNullable().defaultTo('[]')
 
-       table.string('path').notNullable()
 
-       table.string('hash').notNullable()
 
-       table.string('alias')
 
-       table.string('title').notNullable()
 
-       table.string('description')
 
-       table.string('icon')
 
-       table.enu('publishState', ['draft', 'published', 'scheduled']).notNullable().defaultTo('draft')
 
-       table.timestamp('publishStartDate')
 
-       table.timestamp('publishEndDate')
 
-       table.jsonb('config').notNullable().defaultTo('{}')
 
-       table.jsonb('relations').notNullable().defaultTo('[]')
 
-       table.text('content')
 
-       table.text('render')
 
-       table.jsonb('toc')
 
-       table.string('editor').notNullable()
 
-       table.string('contentType').notNullable()
 
-       table.jsonb('scripts').notNullable().defaultTo('{}')
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('versionDate').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // PAGE LINKS --------------------------
 
-     .createTable('pageLinks', table => {
 
-       table.increments('id').primary()
 
-       table.string('path').notNullable()
 
-       table.string('localeCode', 5).notNullable()
 
-     })
 
-     // PAGES -------------------------------
 
-     .createTable('pages', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('path').notNullable()
 
-       table.string('hash').notNullable()
 
-       table.string('alias')
 
-       table.string('title').notNullable()
 
-       table.string('description')
 
-       table.string('icon')
 
-       table.enu('publishState', ['draft', 'published', 'scheduled']).notNullable().defaultTo('draft')
 
-       table.timestamp('publishStartDate')
 
-       table.timestamp('publishEndDate')
 
-       table.jsonb('config').notNullable().defaultTo('{}')
 
-       table.jsonb('relations').notNullable().defaultTo('[]')
 
-       table.text('content')
 
-       table.text('render')
 
-       table.jsonb('toc')
 
-       table.string('editor').notNullable()
 
-       table.string('contentType').notNullable()
 
-       table.boolean('isBrowsable').notNullable().defaultTo(true)
 
-       table.string('password')
 
-       table.integer('ratingScore').notNullable().defaultTo(0)
 
-       table.integer('ratingCount').notNullable().defaultTo(0)
 
-       table.jsonb('scripts').notNullable().defaultTo('{}')
 
-       table.jsonb('historyData').notNullable().defaultTo('{}')
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // RENDERERS ---------------------------
 
-     .createTable('renderers', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('module').notNullable()
 
-       table.boolean('isEnabled').notNullable().defaultTo(false)
 
-       table.jsonb('config').notNullable().defaultTo('{}')
 
-     })
 
-     // SETTINGS ----------------------------
 
-     .createTable('settings', table => {
 
-       table.string('key').notNullable().primary()
 
-       table.jsonb('value')
 
-     })
 
-     // SITES -------------------------------
 
-     .createTable('sites', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('hostname').notNullable()
 
-       table.boolean('isEnabled').notNullable().defaultTo(false)
 
-       table.jsonb('config').notNullable()
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // STORAGE -----------------------------
 
-     .createTable('storage', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('module').notNullable()
 
-       table.boolean('isEnabled').notNullable().defaultTo(false)
 
-       table.jsonb('contentTypes')
 
-       table.jsonb('assetDelivery')
 
-       table.jsonb('versioning')
 
-       table.jsonb('schedule')
 
-       table.jsonb('config')
 
-       table.jsonb('state')
 
-     })
 
-     // TAGS --------------------------------
 
-     .createTable('tags', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('tag').notNullable()
 
-       table.jsonb('display').notNullable().defaultTo('{}')
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // TREE --------------------------------
 
-     .createTable('tree', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.specificType('folderPath', 'ltree').index().index('tree_folderpath_gist_index', { indexType: 'GIST' })
 
-       table.string('fileName').notNullable().index()
 
-       table.string('hash').notNullable().index()
 
-       table.enu('type', ['folder', 'page', 'asset']).notNullable().index()
 
-       table.string('localeCode', 5).notNullable().defaultTo('en').index()
 
-       table.string('title').notNullable()
 
-       table.jsonb('meta').notNullable().defaultTo('{}')
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // USER AVATARS ------------------------
 
-     .createTable('userAvatars', table => {
 
-       table.uuid('id').notNullable().primary()
 
-       table.binary('data').notNullable()
 
-     })
 
-     // USER KEYS ---------------------------
 
-     .createTable('userKeys', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('kind').notNullable()
 
-       table.string('token').notNullable()
 
-       table.jsonb('meta').notNullable().defaultTo('{}')
 
-       table.timestamp('validUntil').notNullable()
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // USERS -------------------------------
 
-     .createTable('users', table => {
 
-       table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
 
-       table.string('email').notNullable()
 
-       table.string('name').notNullable()
 
-       table.jsonb('auth').notNullable().defaultTo('{}')
 
-       table.jsonb('meta').notNullable().defaultTo('{}')
 
-       table.jsonb('prefs').notNullable().defaultTo('{}')
 
-       table.boolean('hasAvatar').notNullable().defaultTo(false)
 
-       table.boolean('isSystem').notNullable().defaultTo(false)
 
-       table.boolean('isActive').notNullable().defaultTo(false)
 
-       table.boolean('isVerified').notNullable().defaultTo(false)
 
-       table.timestamp('lastLoginAt').index()
 
-       table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
 
-       table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
 
-     })
 
-     // =====================================
 
-     // RELATION TABLES
 
-     // =====================================
 
-     // PAGE TAGS ---------------------------
 
-     .createTable('pageTags', table => {
 
-       table.increments('id').primary()
 
-       table.uuid('pageId').references('id').inTable('pages').onDelete('CASCADE')
 
-       table.uuid('tagId').references('id').inTable('tags').onDelete('CASCADE')
 
-     })
 
-     // USER GROUPS -------------------------
 
-     .createTable('userGroups', table => {
 
-       table.increments('id').primary()
 
-       table.uuid('userId').references('id').inTable('users').onDelete('CASCADE')
 
-       table.uuid('groupId').references('id').inTable('groups').onDelete('CASCADE')
 
-     })
 
-     // =====================================
 
-     // REFERENCES
 
-     // =====================================
 
-     .table('activityLogs', table => {
 
-       table.uuid('userId').notNullable().references('id').inTable('users')
 
-     })
 
-     .table('analytics', table => {
 
-       table.uuid('siteId').notNullable().references('id').inTable('sites')
 
-     })
 
-     .table('assets', table => {
 
-       table.uuid('authorId').notNullable().references('id').inTable('users')
 
-       table.uuid('siteId').notNullable().references('id').inTable('sites').index()
 
-     })
 
-     .table('commentProviders', table => {
 
-       table.uuid('siteId').notNullable().references('id').inTable('sites')
 
-     })
 
-     .table('comments', table => {
 
-       table.uuid('pageId').notNullable().references('id').inTable('pages').index()
 
-       table.uuid('authorId').notNullable().references('id').inTable('users').index()
 
-     })
 
-     .table('navigation', table => {
 
-       table.uuid('siteId').notNullable().references('id').inTable('sites').index()
 
-     })
 
-     .table('pageHistory', table => {
 
-       table.string('localeCode', 5).references('code').inTable('locales')
 
-       table.uuid('authorId').notNullable().references('id').inTable('users')
 
-       table.uuid('siteId').notNullable().references('id').inTable('sites').index()
 
-     })
 
-     .table('pageLinks', table => {
 
-       table.uuid('pageId').notNullable().references('id').inTable('pages').onDelete('CASCADE')
 
-       table.index(['path', 'localeCode'])
 
-     })
 
-     .table('pages', table => {
 
-       table.string('localeCode', 5).references('code').inTable('locales').index()
 
-       table.uuid('authorId').notNullable().references('id').inTable('users').index()
 
-       table.uuid('creatorId').notNullable().references('id').inTable('users').index()
 
-       table.uuid('ownerId').notNullable().references('id').inTable('users').index()
 
-       table.uuid('siteId').notNullable().references('id').inTable('sites').index()
 
-     })
 
-     .table('storage', table => {
 
-       table.uuid('siteId').notNullable().references('id').inTable('sites')
 
-     })
 
-     .table('tags', table => {
 
-       table.uuid('siteId').notNullable().references('id').inTable('sites')
 
-       table.unique(['siteId', 'tag'])
 
-     })
 
-     .table('tree', table => {
 
-       table.uuid('siteId').notNullable().references('id').inTable('sites')
 
-     })
 
-     .table('userKeys', table => {
 
-       table.uuid('userId').notNullable().references('id').inTable('users')
 
-     })
 
-     .table('users', table => {
 
-       table.string('localeCode', 5).references('code').inTable('locales').notNullable().defaultTo('en')
 
-     })
 
-   // =====================================
 
-   // DEFAULT DATA
 
-   // =====================================
 
-   // -> GENERATE IDS
 
-   const groupAdminId = uuid()
 
-   const groupGuestId = '10000000-0000-4000-8000-000000000001'
 
-   const siteId = uuid()
 
-   const authModuleId = uuid()
 
-   const userAdminId = uuid()
 
-   const userGuestId = uuid()
 
-   // -> SYSTEM CONFIG
 
-   WIKI.logger.info('Generating certificates...')
 
-   const secret = crypto.randomBytes(32).toString('hex')
 
-   const certs = crypto.generateKeyPairSync('rsa', {
 
-     modulusLength: 2048,
 
-     publicKeyEncoding: {
 
-       type: 'pkcs1',
 
-       format: 'pem'
 
-     },
 
-     privateKeyEncoding: {
 
-       type: 'pkcs1',
 
-       format: 'pem',
 
-       cipher: 'aes-256-cbc',
 
-       passphrase: secret
 
-     }
 
-   })
 
-   await knex('settings').insert([
 
-     {
 
-       key: 'auth',
 
-       value: {
 
-         audience: 'urn:wiki.js',
 
-         tokenExpiration: '30m',
 
-         tokenRenewal: '14d',
 
-         certs: {
 
-           jwk: pem2jwk(certs.publicKey),
 
-           public: certs.publicKey,
 
-           private: certs.privateKey
 
-         },
 
-         secret,
 
-         rootAdminUserId: userAdminId,
 
-         guestUserId: userGuestId
 
-       }
 
-     },
 
-     {
 
-       key: 'flags',
 
-       value: {
 
-         experimental: false,
 
-         authDebug: false,
 
-         sqlLog: false
 
-       }
 
-     },
 
-     {
 
-       key: 'icons',
 
-       value: {
 
-         fa: {
 
-           isActive: true,
 
-           config: {
 
-             version: 6,
 
-             license: 'free',
 
-             token: ''
 
-           }
 
-         },
 
-         la: {
 
-           isActive: true
 
-         }
 
-       }
 
-     },
 
-     {
 
-       key: 'mail',
 
-       value: {
 
-         senderName: '',
 
-         senderEmail: '',
 
-         host: '',
 
-         port: 465,
 
-         name: '',
 
-         secure: true,
 
-         verifySSL: true,
 
-         user: '',
 
-         pass: '',
 
-         useDKIM: false,
 
-         dkimDomainName: '',
 
-         dkimKeySelector: '',
 
-         dkimPrivateKey: ''
 
-       }
 
-     },
 
-     {
 
-       key: 'security',
 
-       value: {
 
-         corsConfig: '',
 
-         corsMode: 'OFF',
 
-         cspDirectives: '',
 
-         disallowFloc: true,
 
-         disallowIframe: true,
 
-         disallowOpenRedirect: true,
 
-         enforceCsp: false,
 
-         enforceHsts: false,
 
-         enforceSameOriginReferrerPolicy: true,
 
-         forceAssetDownload: true,
 
-         hstsDuration: 0,
 
-         trustProxy: false,
 
-         authJwtAudience: 'urn:wiki.js',
 
-         authJwtExpiration: '30m',
 
-         authJwtRenewablePeriod: '14d',
 
-         uploadMaxFileSize: 10485760,
 
-         uploadMaxFiles: 20,
 
-         uploadScanSVG: true
 
-       }
 
-     },
 
-     {
 
-       key: 'update',
 
-       value: {
 
-         locales: true
 
-       }
 
-     },
 
-     {
 
-       key: 'userDefaults',
 
-       value: {
 
-         timezone: 'America/New_York',
 
-         dateFormat: 'YYYY-MM-DD',
 
-         timeFormat: '12h'
 
-       }
 
-     }
 
-   ])
 
-   // -> DEFAULT LOCALE
 
-   await knex('locales').insert({
 
-     code: 'en',
 
-     strings: {},
 
-     isRTL: false,
 
-     name: 'English',
 
-     nativeName: 'English'
 
-   })
 
-   // -> DEFAULT SITE
 
-   await knex('sites').insert({
 
-     id: siteId,
 
-     hostname: '*',
 
-     isEnabled: true,
 
-     config: {
 
-       title: 'My Wiki Site',
 
-       description: '',
 
-       company: '',
 
-       contentLicense: '',
 
-       footerExtra: '',
 
-       pageExtensions: ['md', 'html', 'txt'],
 
-       pageCasing: true,
 
-       defaults: {
 
-         tocDepth: {
 
-           min: 1,
 
-           max: 2
 
-         }
 
-       },
 
-       features: {
 
-         ratings: false,
 
-         ratingsMode: 'off',
 
-         comments: false,
 
-         contributions: false,
 
-         profile: true,
 
-         reasonForChange: 'required',
 
-         search: true
 
-       },
 
-       logoText: true,
 
-       sitemap: true,
 
-       robots: {
 
-         index: true,
 
-         follow: true
 
-       },
 
-       authStrategies: [{ id: authModuleId, order: 0, isVisible: true }],
 
-       locale: 'en',
 
-       localeNamespacing: false,
 
-       localeNamespaces: [],
 
-       assets: {
 
-         logo: false,
 
-         logoExt: 'svg',
 
-         favicon: false,
 
-         faviconExt: 'svg',
 
-         loginBg: false
 
-       },
 
-       editors: {
 
-         asciidoc: {
 
-           isActive: true,
 
-           config: {}
 
-         },
 
-         markdown: {
 
-           isActive: true,
 
-           config: {
 
-             allowHTML: true,
 
-             kroki: false,
 
-             krokiServerUrl: 'https://kroki.io',
 
-             latexEngine: 'katex',
 
-             lineBreaks: true,
 
-             linkify: true,
 
-             multimdTable: true,
 
-             plantuml: false,
 
-             plantumlServerUrl: 'https://www.plantuml.com/plantuml/',
 
-             quotes: 'english',
 
-             tabWidth: 2,
 
-             typographer: false,
 
-             underline: true
 
-           }
 
-         },
 
-         wysiwyg: {
 
-           isActive: true,
 
-           config: {}
 
-         }
 
-       },
 
-       theme: {
 
-         dark: false,
 
-         colorPrimary: '#1976D2',
 
-         colorSecondary: '#02C39A',
 
-         colorAccent: '#FF9800',
 
-         colorHeader: '#000000',
 
-         colorSidebar: '#1976D2',
 
-         injectCSS: '',
 
-         injectHead: '',
 
-         injectBody: '',
 
-         contentWidth: 'full',
 
-         sidebarPosition: 'left',
 
-         tocPosition: 'right',
 
-         showSharingMenu: true,
 
-         showPrintBtn: true,
 
-         baseFont: 'roboto',
 
-         contentFont: 'roboto'
 
-       },
 
-       uploads: {
 
-         conflictBehavior: 'overwrite',
 
-         normalizeFilename: true
 
-       }
 
-     }
 
-   })
 
-   // -> DEFAULT GROUPS
 
-   await knex('groups').insert([
 
-     {
 
-       id: groupAdminId,
 
-       name: 'Administrators',
 
-       permissions: JSON.stringify(['manage:system']),
 
-       rules: JSON.stringify([]),
 
-       isSystem: true
 
-     },
 
-     {
 
-       id: groupGuestId,
 
-       name: 'Guests',
 
-       permissions: JSON.stringify(['read:pages', 'read:assets', 'read:comments']),
 
-       rules: JSON.stringify([
 
-         {
 
-           id: uuid(),
 
-           name: 'Default Rule',
 
-           roles: ['read:pages', 'read:assets', 'read:comments'],
 
-           match: 'START',
 
-           mode: 'DENY',
 
-           path: '',
 
-           locales: [],
 
-           sites: []
 
-         }
 
-       ]),
 
-       isSystem: true
 
-     }
 
-   ])
 
-   // -> AUTHENTICATION MODULE
 
-   await knex('authentication').insert({
 
-     id: authModuleId,
 
-     module: 'local',
 
-     isEnabled: true,
 
-     displayName: 'Local Authentication'
 
-   })
 
-   // -> USERS
 
-   await knex('users').insert([
 
-     {
 
-       id: userAdminId,
 
-       email: process.env.ADMIN_EMAIL ?? 'admin@example.com',
 
-       auth: {
 
-         [authModuleId]: {
 
-           password: await bcrypt.hash(process.env.ADMIN_PASS || '12345678', 12),
 
-           mustChangePwd: false, // TODO: Revert to true (below) once change password flow is implemented
 
-           // mustChangePwd: !process.env.ADMIN_PASS,
 
-           restrictLogin: false,
 
-           tfaRequired: false,
 
-           tfaSecret: ''
 
-         }
 
-       },
 
-       name: 'Administrator',
 
-       isSystem: false,
 
-       isActive: true,
 
-       isVerified: true,
 
-       meta: {
 
-         location: '',
 
-         jobTitle: '',
 
-         pronouns: ''
 
-       },
 
-       prefs: {
 
-         timezone: 'America/New_York',
 
-         dateFormat: 'YYYY-MM-DD',
 
-         timeFormat: '12h',
 
-         appearance: 'site',
 
-         cvd: 'none'
 
-       },
 
-       localeCode: 'en'
 
-     },
 
-     {
 
-       id: userGuestId,
 
-       email: 'guest@example.com',
 
-       auth: {},
 
-       name: 'Guest',
 
-       isSystem: true,
 
-       isActive: true,
 
-       isVerified: true,
 
-       meta: {},
 
-       prefs: {
 
-         timezone: 'America/New_York',
 
-         dateFormat: 'YYYY-MM-DD',
 
-         timeFormat: '12h',
 
-         appearance: 'site',
 
-         cvd: 'none'
 
-       },
 
-       localeCode: 'en'
 
-     }
 
-   ])
 
-   await knex('userGroups').insert([
 
-     {
 
-       userId: userAdminId,
 
-       groupId: groupAdminId
 
-     },
 
-     {
 
-       userId: userGuestId,
 
-       groupId: groupGuestId
 
-     }
 
-   ])
 
-   // -> STORAGE MODULE
 
-   await knex('storage').insert({
 
-     module: 'db',
 
-     siteId,
 
-     isEnabled: true,
 
-     contentTypes: {
 
-       activeTypes: ['pages', 'images', 'documents', 'others', 'large'],
 
-       largeThreshold: '5MB'
 
-     },
 
-     assetDelivery: {
 
-       streaming: true,
 
-       directAccess: false
 
-     },
 
-     versioning: {
 
-       enabled: false
 
-     },
 
-     state: {
 
-       current: 'ok'
 
-     }
 
-   })
 
-   // -> SCHEDULED JOBS
 
-   await knex('jobSchedule').insert([
 
-     {
 
-       task: 'checkVersion',
 
-       cron: '0 0 * * *',
 
-       type: 'system'
 
-     },
 
-     {
 
-       task: 'cleanJobHistory',
 
-       cron: '5 0 * * *',
 
-       type: 'system'
 
-     },
 
-     {
 
-       task: 'updateLocales',
 
-       cron: '0 0 * * *',
 
-       type: 'system'
 
-     }
 
-   ])
 
-   await knex('jobLock').insert({
 
-     key: 'cron',
 
-     lastCheckedBy: 'init',
 
-     lastCheckedAt: DateTime.utc().minus({ hours: 1 }).toISO()
 
-   })
 
-   WIKI.logger.info('Completed 3.0.0 database migration.')
 
- }
 
- export function down (knex) { }
 
 
  |