3.0.0.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. const { v4: uuid } = require('uuid')
  2. const bcrypt = require('bcryptjs-then')
  3. const crypto = require('crypto')
  4. const pem2jwk = require('pem-jwk').pem2jwk
  5. /* global WIKI */
  6. exports.up = async knex => {
  7. WIKI.logger.info('Running 3.0.0 database migration...')
  8. // =====================================
  9. // PG EXTENSIONS
  10. // =====================================
  11. await knex.raw('CREATE EXTENSION IF NOT EXISTS pgcrypto;')
  12. await knex.schema
  13. // =====================================
  14. // MODEL TABLES
  15. // =====================================
  16. // ACTIVITY LOGS -----------------------
  17. .createTable('activityLogs', table => {
  18. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  19. table.timestamp('ts').notNullable().defaultTo(knex.fn.now())
  20. table.string('action').notNullable()
  21. table.jsonb('meta').notNullable()
  22. })
  23. // ANALYTICS ---------------------------
  24. .createTable('analytics', table => {
  25. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  26. table.string('module').notNullable()
  27. table.boolean('isEnabled').notNullable().defaultTo(false)
  28. table.jsonb('config').notNullable()
  29. })
  30. // API KEYS ----------------------------
  31. .createTable('apiKeys', table => {
  32. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  33. table.string('name').notNullable()
  34. table.text('key').notNullable()
  35. table.timestamp('expiration').notNullable().defaultTo(knex.fn.now())
  36. table.boolean('isRevoked').notNullable().defaultTo(false)
  37. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  38. table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
  39. })
  40. // ASSETS ------------------------------
  41. .createTable('assets', table => {
  42. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  43. table.string('filename').notNullable()
  44. table.string('hash').notNullable().index()
  45. table.string('ext').notNullable()
  46. table.enum('kind', ['binary', 'image']).notNullable().defaultTo('binary')
  47. table.string('mime').notNullable().defaultTo('application/octet-stream')
  48. table.integer('fileSize').unsigned().comment('In kilobytes')
  49. table.jsonb('metadata')
  50. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  51. table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
  52. })
  53. // ASSET DATA --------------------------
  54. .createTable('assetData', table => {
  55. table.uuid('id').notNullable().primary()
  56. table.binary('data').notNullable()
  57. })
  58. // ASSET FOLDERS -----------------------
  59. .createTable('assetFolders', table => {
  60. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  61. table.string('name').notNullable()
  62. table.string('slug').notNullable()
  63. })
  64. // AUTHENTICATION ----------------------
  65. .createTable('authentication', table => {
  66. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  67. table.string('module').notNullable()
  68. table.boolean('isEnabled').notNullable().defaultTo(false)
  69. table.string('displayName').notNullable().defaultTo('')
  70. table.jsonb('config').notNullable().defaultTo('{}')
  71. table.boolean('selfRegistration').notNullable().defaultTo(false)
  72. table.jsonb('domainWhitelist').notNullable().defaultTo('[]')
  73. table.jsonb('autoEnrollGroups').notNullable().defaultTo('[]')
  74. })
  75. .createTable('commentProviders', table => {
  76. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  77. table.string('module').notNullable()
  78. table.boolean('isEnabled').notNullable().defaultTo(false)
  79. table.json('config').notNullable()
  80. })
  81. // COMMENTS ----------------------------
  82. .createTable('comments', table => {
  83. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  84. table.uuid('replyTo')
  85. table.text('content').notNullable()
  86. table.text('render').notNullable().defaultTo('')
  87. table.string('name').notNullable().defaultTo('')
  88. table.string('email').notNullable().defaultTo('')
  89. table.string('ip').notNullable().defaultTo('')
  90. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  91. table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
  92. })
  93. // GROUPS ------------------------------
  94. .createTable('groups', table => {
  95. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  96. table.string('name').notNullable()
  97. table.jsonb('permissions').notNullable()
  98. table.jsonb('rules').notNullable()
  99. table.string('redirectOnLogin').notNullable().defaultTo('')
  100. table.string('redirectOnFirstLogin').notNullable().defaultTo('')
  101. table.string('redirectOnLogout').notNullable().defaultTo('')
  102. table.boolean('isSystem').notNullable().defaultTo(false)
  103. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  104. table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
  105. })
  106. // HOOKS -------------------------------
  107. .createTable('hooks', table => {
  108. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  109. table.string('name').notNullable()
  110. table.jsonb('events').notNullable().defaultTo('[]')
  111. table.string('url').notNullable()
  112. table.boolean('includeMetadata').notNullable().defaultTo(false)
  113. table.boolean('includeContent').notNullable().defaultTo(false)
  114. table.boolean('acceptUntrusted').notNullable().defaultTo(false)
  115. table.string('authHeader')
  116. table.enum('state', ['pending', 'error', 'success']).notNullable().defaultTo('pending')
  117. table.string('lastErrorMessage')
  118. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  119. table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
  120. })
  121. // LOCALES -----------------------------
  122. .createTable('locales', table => {
  123. table.string('code', 5).notNullable().primary()
  124. table.jsonb('strings')
  125. table.boolean('isRTL').notNullable().defaultTo(false)
  126. table.string('name').notNullable()
  127. table.string('nativeName').notNullable()
  128. table.integer('availability').notNullable().defaultTo(0)
  129. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  130. table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
  131. })
  132. // NAVIGATION ----------------------------
  133. .createTable('navigation', table => {
  134. table.string('key').notNullable().primary()
  135. table.jsonb('config')
  136. })
  137. // PAGE HISTORY ------------------------
  138. .createTable('pageHistory', table => {
  139. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  140. table.uuid('pageId').notNullable().index()
  141. table.string('path').notNullable()
  142. table.string('hash').notNullable()
  143. table.string('title').notNullable()
  144. table.string('description')
  145. table.enu('publishState', ['draft', 'published', 'scheduled']).notNullable().defaultTo('draft')
  146. table.timestamp('publishStartDate')
  147. table.timestamp('publishEndDate')
  148. table.string('action').defaultTo('updated')
  149. table.text('content')
  150. table.string('editor').notNullable()
  151. table.string('contentType').notNullable()
  152. table.jsonb('extra').notNullable().defaultTo('{}')
  153. table.jsonb('tags').defaultTo('[]')
  154. table.timestamp('versionDate').notNullable().defaultTo(knex.fn.now())
  155. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  156. })
  157. // PAGE LINKS --------------------------
  158. .createTable('pageLinks', table => {
  159. table.increments('id').primary()
  160. table.string('path').notNullable()
  161. table.string('localeCode', 5).notNullable()
  162. })
  163. // PAGES -------------------------------
  164. .createTable('pages', table => {
  165. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  166. table.string('slug')
  167. table.string('path').notNullable()
  168. table.string('hash').notNullable()
  169. table.string('title').notNullable()
  170. table.string('description')
  171. table.enu('publishState', ['draft', 'published', 'scheduled']).notNullable().defaultTo('draft')
  172. table.timestamp('publishStartDate')
  173. table.timestamp('publishEndDate')
  174. table.text('content')
  175. table.text('render')
  176. table.jsonb('toc')
  177. table.string('editor').notNullable()
  178. table.string('contentType').notNullable()
  179. table.jsonb('extra').notNullable().defaultTo('{}')
  180. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  181. table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
  182. })
  183. // PAGE TREE ---------------------------
  184. .createTable('pageTree', table => {
  185. table.integer('id').unsigned().primary()
  186. table.string('path').notNullable()
  187. table.integer('depth').unsigned().notNullable()
  188. table.string('title').notNullable()
  189. table.boolean('isFolder').notNullable().defaultTo(false)
  190. table.jsonb('ancestors')
  191. })
  192. // RENDERERS ---------------------------
  193. .createTable('renderers', table => {
  194. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  195. table.string('module').notNullable()
  196. table.boolean('isEnabled').notNullable().defaultTo(false)
  197. table.jsonb('config')
  198. })
  199. // SETTINGS ----------------------------
  200. .createTable('settings', table => {
  201. table.string('key').notNullable().primary()
  202. table.jsonb('value')
  203. })
  204. // SITES -------------------------------
  205. .createTable('sites', table => {
  206. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  207. table.string('hostname').notNullable()
  208. table.boolean('isEnabled').notNullable().defaultTo(false)
  209. table.jsonb('config').notNullable()
  210. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  211. })
  212. // STORAGE -----------------------------
  213. .createTable('storage', table => {
  214. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  215. table.string('module').notNullable()
  216. table.boolean('isEnabled').notNullable().defaultTo(false)
  217. table.jsonb('contentTypes')
  218. table.jsonb('assetDelivery')
  219. table.jsonb('versioning')
  220. table.jsonb('schedule')
  221. table.jsonb('config')
  222. table.jsonb('state')
  223. })
  224. // TAGS --------------------------------
  225. .createTable('tags', table => {
  226. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  227. table.string('tag').notNullable()
  228. table.jsonb('display').notNullable().defaultTo('{}')
  229. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  230. table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
  231. })
  232. // USER AVATARS ------------------------
  233. .createTable('userAvatars', table => {
  234. table.uuid('id').notNullable().primary()
  235. table.binary('data').notNullable()
  236. })
  237. // USER KEYS ---------------------------
  238. .createTable('userKeys', table => {
  239. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  240. table.string('kind').notNullable()
  241. table.string('token').notNullable()
  242. table.jsonb('meta').notNullable().defaultTo('{}')
  243. table.timestamp('validUntil').notNullable()
  244. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  245. })
  246. // USERS -------------------------------
  247. .createTable('users', table => {
  248. table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
  249. table.string('email').notNullable()
  250. table.string('name').notNullable()
  251. table.jsonb('auth').notNullable().defaultTo('{}')
  252. table.jsonb('meta').notNullable().defaultTo('{}')
  253. table.jsonb('prefs').notNullable().defaultTo('{}')
  254. table.string('pictureUrl')
  255. table.boolean('isSystem').notNullable().defaultTo(false)
  256. table.boolean('isActive').notNullable().defaultTo(false)
  257. table.boolean('isVerified').notNullable().defaultTo(false)
  258. table.timestamp('lastLoginAt').index()
  259. table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
  260. table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
  261. })
  262. // =====================================
  263. // RELATION TABLES
  264. // =====================================
  265. // PAGE TAGS ---------------------------
  266. .createTable('pageTags', table => {
  267. table.increments('id').primary()
  268. table.uuid('pageId').references('id').inTable('pages').onDelete('CASCADE')
  269. table.uuid('tagId').references('id').inTable('tags').onDelete('CASCADE')
  270. })
  271. // USER GROUPS -------------------------
  272. .createTable('userGroups', table => {
  273. table.increments('id').primary()
  274. table.uuid('userId').references('id').inTable('users').onDelete('CASCADE')
  275. table.uuid('groupId').references('id').inTable('groups').onDelete('CASCADE')
  276. })
  277. // =====================================
  278. // REFERENCES
  279. // =====================================
  280. .table('activityLogs', table => {
  281. table.uuid('userId').notNullable().references('id').inTable('users')
  282. })
  283. .table('analytics', table => {
  284. table.uuid('siteId').notNullable().references('id').inTable('sites')
  285. })
  286. .table('assets', table => {
  287. table.uuid('folderId').notNullable().references('id').inTable('assetFolders').index()
  288. table.uuid('authorId').notNullable().references('id').inTable('users')
  289. table.uuid('siteId').notNullable().references('id').inTable('sites').index()
  290. })
  291. .table('assetFolders', table => {
  292. table.uuid('parentId').references('id').inTable('assetFolders').index()
  293. })
  294. .table('commentProviders', table => {
  295. table.uuid('siteId').notNullable().references('id').inTable('sites')
  296. })
  297. .table('comments', table => {
  298. table.uuid('pageId').notNullable().references('id').inTable('pages').index()
  299. table.uuid('authorId').notNullable().references('id').inTable('users').index()
  300. })
  301. .table('navigation', table => {
  302. table.uuid('siteId').notNullable().references('id').inTable('sites').index()
  303. })
  304. .table('pageHistory', table => {
  305. table.string('localeCode', 5).references('code').inTable('locales')
  306. table.uuid('authorId').notNullable().references('id').inTable('users')
  307. table.uuid('siteId').notNullable().references('id').inTable('sites').index()
  308. })
  309. .table('pageLinks', table => {
  310. table.uuid('pageId').notNullable().references('id').inTable('pages').onDelete('CASCADE')
  311. table.index(['path', 'localeCode'])
  312. })
  313. .table('pages', table => {
  314. table.string('localeCode', 5).references('code').inTable('locales').index()
  315. table.uuid('authorId').notNullable().references('id').inTable('users').index()
  316. table.uuid('creatorId').notNullable().references('id').inTable('users').index()
  317. table.uuid('siteId').notNullable().references('id').inTable('sites').index()
  318. })
  319. .table('pageTree', table => {
  320. table.integer('parent').unsigned().references('id').inTable('pageTree').onDelete('CASCADE')
  321. table.uuid('pageId').notNullable().references('id').inTable('pages').onDelete('CASCADE')
  322. table.string('localeCode', 5).references('code').inTable('locales')
  323. })
  324. .table('renderers', table => {
  325. table.uuid('siteId').notNullable().references('id').inTable('sites')
  326. })
  327. .table('storage', table => {
  328. table.uuid('siteId').notNullable().references('id').inTable('sites')
  329. })
  330. .table('tags', table => {
  331. table.uuid('siteId').notNullable().references('id').inTable('sites')
  332. table.unique(['siteId', 'tag'])
  333. })
  334. .table('userKeys', table => {
  335. table.uuid('userId').notNullable().references('id').inTable('users')
  336. })
  337. .table('users', table => {
  338. table.string('localeCode', 5).references('code').inTable('locales').notNullable().defaultTo('en')
  339. })
  340. // =====================================
  341. // DEFAULT DATA
  342. // =====================================
  343. // -> GENERATE IDS
  344. const groupAdminId = uuid()
  345. const groupGuestId = '10000000-0000-4000-8000-000000000001'
  346. const siteId = uuid()
  347. const authModuleId = uuid()
  348. const userAdminId = uuid()
  349. const userGuestId = uuid()
  350. // -> SYSTEM CONFIG
  351. WIKI.logger.info('Generating certificates...')
  352. const secret = crypto.randomBytes(32).toString('hex')
  353. const certs = crypto.generateKeyPairSync('rsa', {
  354. modulusLength: 2048,
  355. publicKeyEncoding: {
  356. type: 'pkcs1',
  357. format: 'pem'
  358. },
  359. privateKeyEncoding: {
  360. type: 'pkcs1',
  361. format: 'pem',
  362. cipher: 'aes-256-cbc',
  363. passphrase: secret
  364. }
  365. })
  366. await knex('settings').insert([
  367. {
  368. key: 'auth',
  369. value: {
  370. audience: 'urn:wiki.js',
  371. tokenExpiration: '30m',
  372. tokenRenewal: '14d',
  373. certs: {
  374. jwk: pem2jwk(certs.publicKey),
  375. public: certs.publicKey,
  376. private: certs.privateKey
  377. },
  378. secret,
  379. rootAdminUserId: userAdminId,
  380. guestUserId: userGuestId
  381. }
  382. },
  383. {
  384. key: 'mail',
  385. value: {
  386. senderName: '',
  387. senderEmail: '',
  388. host: '',
  389. port: 465,
  390. name: '',
  391. secure: true,
  392. verifySSL: true,
  393. user: '',
  394. pass: '',
  395. useDKIM: false,
  396. dkimDomainName: '',
  397. dkimKeySelector: '',
  398. dkimPrivateKey: ''
  399. }
  400. },
  401. {
  402. key: 'security',
  403. value: {
  404. corsConfig: '',
  405. corsMode: 'OFF',
  406. cspDirectives: '',
  407. disallowFloc: true,
  408. disallowIframe: true,
  409. disallowOpenRedirect: true,
  410. enforceCsp: false,
  411. enforceHsts: false,
  412. enforceSameOriginReferrerPolicy: true,
  413. forceAssetDownload: true,
  414. hstsDuration: 0,
  415. trustProxy: false,
  416. authJwtAudience: 'urn:wiki.js',
  417. authJwtExpiration: '30m',
  418. authJwtRenewablePeriod: '14d',
  419. uploadMaxFileSize: 10485760,
  420. uploadMaxFiles: 20,
  421. uploadScanSVG: true
  422. }
  423. },
  424. {
  425. key: 'update',
  426. value: {
  427. locales: true
  428. }
  429. }
  430. ])
  431. // -> DEFAULT LOCALE
  432. await knex('locales').insert({
  433. code: 'en',
  434. strings: {},
  435. isRTL: false,
  436. name: 'English',
  437. nativeName: 'English'
  438. })
  439. // -> DEFAULT SITE
  440. await knex('sites').insert({
  441. id: siteId,
  442. hostname: '*',
  443. isEnabled: true,
  444. config: {
  445. title: 'My Wiki Site',
  446. description: '',
  447. company: '',
  448. contentLicense: '',
  449. footerExtra: '',
  450. pageExtensions: ['md', 'html', 'txt'],
  451. defaults: {
  452. timezone: 'America/New_York',
  453. dateFormat: 'YYYY-MM-DD',
  454. timeFormat: '12h'
  455. },
  456. features: {
  457. ratings: false,
  458. ratingsMode: 'off',
  459. comments: false,
  460. contributions: false,
  461. profile: true,
  462. search: true
  463. },
  464. logoText: true,
  465. sitemap: true,
  466. robots: {
  467. index: true,
  468. follow: true
  469. },
  470. authStrategies: [{ id: authModuleId, order: 0, isVisible: true }],
  471. locale: 'en',
  472. localeNamespacing: false,
  473. localeNamespaces: [],
  474. assets: {
  475. logo: false,
  476. logoExt: 'svg',
  477. favicon: false,
  478. faviconExt: 'svg',
  479. loginBg: false
  480. },
  481. theme: {
  482. dark: false,
  483. colorPrimary: '#1976D2',
  484. colorSecondary: '#02C39A',
  485. colorAccent: '#FF9800',
  486. colorHeader: '#000000',
  487. colorSidebar: '#1976D2',
  488. injectCSS: '',
  489. injectHead: '',
  490. injectBody: '',
  491. contentWidth: 'full',
  492. sidebarPosition: 'left',
  493. tocPosition: 'right',
  494. showSharingMenu: true,
  495. showPrintBtn: true,
  496. baseFont: 'roboto',
  497. contentFont: 'roboto'
  498. }
  499. }
  500. })
  501. // -> DEFAULT GROUPS
  502. await knex('groups').insert([
  503. {
  504. id: groupAdminId,
  505. name: 'Administrators',
  506. permissions: JSON.stringify(['manage:system']),
  507. rules: JSON.stringify([]),
  508. isSystem: true
  509. },
  510. {
  511. id: groupGuestId,
  512. name: 'Guests',
  513. permissions: JSON.stringify(['read:pages', 'read:assets', 'read:comments']),
  514. rules: JSON.stringify([
  515. {
  516. id: uuid(),
  517. name: 'Default Rule',
  518. roles: ['read:pages', 'read:assets', 'read:comments'],
  519. match: 'START',
  520. mode: 'DENY',
  521. path: '',
  522. locales: [],
  523. sites: []
  524. }
  525. ]),
  526. isSystem: true
  527. }
  528. ])
  529. // -> AUTHENTICATION MODULE
  530. await knex('authentication').insert({
  531. id: authModuleId,
  532. module: 'local',
  533. isEnabled: true,
  534. displayName: 'Local Authentication'
  535. })
  536. // -> USERS
  537. await knex('users').insert([
  538. {
  539. id: userAdminId,
  540. email: process.env.ADMIN_EMAIL ?? 'admin@example.com',
  541. auth: {
  542. [authModuleId]: {
  543. password: await bcrypt.hash(process.env.ADMIN_PASS || '12345678', 12),
  544. mustChangePwd: !process.env.ADMIN_PASS,
  545. restrictLogin: false,
  546. tfaRequired: false,
  547. tfaSecret: ''
  548. }
  549. },
  550. name: 'Administrator',
  551. isSystem: false,
  552. isActive: true,
  553. isVerified: true,
  554. meta: {
  555. location: '',
  556. jobTitle: '',
  557. pronouns: ''
  558. },
  559. prefs: {
  560. timezone: 'America/New_York',
  561. dateFormat: 'YYYY-MM-DD',
  562. timeFormat: '12h',
  563. appearance: 'site'
  564. },
  565. localeCode: 'en'
  566. },
  567. {
  568. id: userGuestId,
  569. email: 'guest@example.com',
  570. auth: {},
  571. name: 'Guest',
  572. isSystem: true,
  573. isActive: true,
  574. isVerified: true,
  575. meta: {},
  576. prefs: {
  577. timezone: 'America/New_York',
  578. dateFormat: 'YYYY-MM-DD',
  579. timeFormat: '12h',
  580. appearance: 'site'
  581. },
  582. localeCode: 'en'
  583. }
  584. ])
  585. await knex('userGroups').insert([
  586. {
  587. userId: userAdminId,
  588. groupId: groupAdminId
  589. },
  590. {
  591. userId: userGuestId,
  592. groupId: groupGuestId
  593. }
  594. ])
  595. // -> STORAGE MODULE
  596. await knex('storage').insert({
  597. module: 'db',
  598. siteId,
  599. isEnabled: true,
  600. contentTypes: {
  601. activeTypes: ['pages', 'images', 'documents', 'others', 'large'],
  602. largeThreshold: '5MB'
  603. },
  604. assetDelivery: {
  605. streaming: true,
  606. directAccess: false
  607. },
  608. versioning: {
  609. enabled: false
  610. },
  611. state: {
  612. current: 'ok'
  613. }
  614. })
  615. WIKI.logger.info('Completed 3.0.0 database migration.')
  616. }
  617. exports.down = knex => { }