3.0.0.js 24 KB

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