page.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. const _ = require('lodash')
  2. const graphHelper = require('../../helpers/graph')
  3. /* global WIKI */
  4. module.exports = {
  5. Query: {
  6. async pages() { return {} }
  7. },
  8. Mutation: {
  9. async pages() { return {} }
  10. },
  11. PageQuery: {
  12. /**
  13. * PAGE HISTORY
  14. */
  15. async history(obj, args, context, info) {
  16. const page = await WIKI.models.pages.query().select('path', 'localeCode').findById(args.id)
  17. if (WIKI.auth.checkAccess(context.req.user, ['read:history'], {
  18. path: page.path,
  19. locale: page.localeCode
  20. })) {
  21. return WIKI.models.pageHistory.getHistory({
  22. pageId: args.id,
  23. offsetPage: args.offsetPage || 0,
  24. offsetSize: args.offsetSize || 100
  25. })
  26. } else {
  27. throw new WIKI.Error.PageHistoryForbidden()
  28. }
  29. },
  30. /**
  31. * PAGE VERSION
  32. */
  33. async version(obj, args, context, info) {
  34. const page = await WIKI.models.pages.query().select('path', 'localeCode').findById(args.pageId)
  35. if (WIKI.auth.checkAccess(context.req.user, ['read:history'], {
  36. path: page.path,
  37. locale: page.localeCode
  38. })) {
  39. return WIKI.models.pageHistory.getVersion({
  40. pageId: args.pageId,
  41. versionId: args.versionId
  42. })
  43. } else {
  44. throw new WIKI.Error.PageHistoryForbidden()
  45. }
  46. },
  47. /**
  48. * SEARCH PAGES
  49. */
  50. async search (obj, args, context) {
  51. if (WIKI.data.searchEngine) {
  52. const resp = await WIKI.data.searchEngine.query(args.query, args)
  53. return {
  54. ...resp,
  55. results: _.filter(resp.results, r => {
  56. return WIKI.auth.checkAccess(context.req.user, ['read:pages'], {
  57. path: r.path,
  58. locale: r.locale
  59. })
  60. })
  61. }
  62. } else {
  63. return {
  64. results: [],
  65. suggestions: [],
  66. totalHits: 0
  67. }
  68. }
  69. },
  70. /**
  71. * LIST PAGES
  72. */
  73. async list (obj, args, context, info) {
  74. let results = await WIKI.models.pages.query().column([
  75. 'pages.id',
  76. 'path',
  77. { locale: 'localeCode' },
  78. 'title',
  79. 'description',
  80. 'isPublished',
  81. 'isPrivate',
  82. 'privateNS',
  83. 'contentType',
  84. 'createdAt',
  85. 'updatedAt'
  86. ])
  87. .withGraphJoined('tags')
  88. .modifyGraph('tags', builder => {
  89. builder.select('tag')
  90. })
  91. .modify(queryBuilder => {
  92. if (args.limit) {
  93. queryBuilder.limit(args.limit)
  94. }
  95. if (args.locale) {
  96. queryBuilder.where('localeCode', args.locale)
  97. }
  98. if (args.tags && args.tags.length > 0) {
  99. queryBuilder.whereIn('tags.tag', args.tags)
  100. }
  101. const orderDir = args.orderByDirection === 'DESC' ? 'desc' : 'asc'
  102. switch (args.orderBy) {
  103. case 'CREATED':
  104. queryBuilder.orderBy('createdAt', orderDir)
  105. break
  106. case 'PATH':
  107. queryBuilder.orderBy('path', orderDir)
  108. break
  109. case 'TITLE':
  110. queryBuilder.orderBy('title', orderDir)
  111. break
  112. case 'UPDATED':
  113. queryBuilder.orderBy('updatedAt', orderDir)
  114. break
  115. default:
  116. queryBuilder.orderBy('pages.id', orderDir)
  117. break
  118. }
  119. })
  120. results = _.filter(results, r => {
  121. return WIKI.auth.checkAccess(context.req.user, ['read:pages'], {
  122. path: r.path,
  123. locale: r.locale
  124. })
  125. }).map(r => ({
  126. ...r,
  127. tags: _.map(r.tags, 'tag')
  128. }))
  129. if (args.tags && args.tags.length > 0) {
  130. results = _.filter(results, r => _.every(args.tags, t => _.includes(r.tags, t)))
  131. }
  132. return results
  133. },
  134. /**
  135. * FETCH SINGLE PAGE
  136. */
  137. async single (obj, args, context, info) {
  138. let page = await WIKI.models.pages.getPageFromDb(args.id)
  139. if (page) {
  140. if (WIKI.auth.checkAccess(context.req.user, ['manage:pages', 'delete:pages'], {
  141. path: page.path,
  142. locale: page.localeCode
  143. })) {
  144. return {
  145. ...page,
  146. locale: page.localeCode,
  147. editor: page.editorKey
  148. }
  149. } else {
  150. throw new WIKI.Error.PageViewForbidden()
  151. }
  152. } else {
  153. throw new WIKI.Error.PageNotFound()
  154. }
  155. },
  156. /**
  157. * FETCH TAGS
  158. */
  159. async tags (obj, args, context, info) {
  160. return WIKI.models.tags.query().orderBy('tag', 'asc')
  161. },
  162. /**
  163. * SEARCH TAGS
  164. */
  165. async searchTags (obj, args, context, info) {
  166. const results = await WIKI.models.tags.query()
  167. .column('tag')
  168. .where(builder => {
  169. builder.andWhere(builderSub => {
  170. if (WIKI.config.db.type === 'postgres') {
  171. builderSub.where('tag', 'ILIKE', `%${args.query}%`)
  172. } else {
  173. builderSub.where('tag', 'LIKE', `%${args.query}%`)
  174. }
  175. })
  176. })
  177. .limit(5)
  178. return results.map(r => r.tag)
  179. },
  180. /**
  181. * FETCH PAGE TREE
  182. */
  183. async tree (obj, args, context, info) {
  184. let results = []
  185. let conds = {
  186. localeCode: args.locale
  187. }
  188. if (args.parent) {
  189. conds.parent = (args.parent < 1) ? null : args.parent
  190. } else if (args.path) {
  191. // conds.parent = (args.parent < 1) ? null : args.parent
  192. }
  193. switch (args.mode) {
  194. case 'FOLDERS':
  195. conds.isFolder = true
  196. results = await WIKI.models.knex('pageTree').where(conds)
  197. break
  198. case 'PAGES':
  199. await WIKI.models.knex('pageTree').where(conds).andWhereNotNull('pageId')
  200. break
  201. default:
  202. results = await WIKI.models.knex('pageTree').where(conds)
  203. break
  204. }
  205. return results.filter(r => {
  206. return WIKI.auth.checkAccess(context.req.user, ['read:pages'], {
  207. path: r.path,
  208. locale: r.localeCode
  209. })
  210. }).map(r => ({
  211. ...r,
  212. parent: r.parent || 0,
  213. locale: r.localeCode
  214. }))
  215. },
  216. /**
  217. * FETCH PAGE LINKS
  218. */
  219. async links (obj, args, context, info) {
  220. let results = []
  221. results = await WIKI.models.knex('pages')
  222. .column({ id: 'pages.id' }, { path: 'pages.path' }, 'title', { link: 'pageLinks.path' }, { locale: 'pageLinks.localeCode' })
  223. .fullOuterJoin('pageLinks', 'pages.id', 'pageLinks.pageId')
  224. .where({
  225. 'pages.localeCode': args.locale
  226. })
  227. return _.reduce(results, (result, val) => {
  228. // -> Check if user has access to source and linked page
  229. if (
  230. !WIKI.auth.checkAccess(context.req.user, ['read:pages'], { path: val.path, locale: args.locale }) ||
  231. !WIKI.auth.checkAccess(context.req.user, ['read:pages'], { path: val.link, locale: val.locale })
  232. ) {
  233. return result
  234. }
  235. const existingEntry = _.findIndex(result, ['id', val.id])
  236. if (existingEntry >= 0) {
  237. if (val.link) {
  238. result[existingEntry].links.push(`${val.locale}/${val.link}`)
  239. }
  240. } else {
  241. result.push({
  242. id: val.id,
  243. title: val.title,
  244. path: `${args.locale}/${val.path}`,
  245. links: val.link ? [`${val.locale}/${val.link}`] : []
  246. })
  247. }
  248. return result
  249. }, [])
  250. },
  251. /**
  252. * CHECK FOR EDITING CONFLICT
  253. */
  254. async checkConflicts (obj, args, context, info) {
  255. let page = await WIKI.models.pages.query().select('path', 'localeCode', 'updatedAt').findById(args.id)
  256. if (page) {
  257. if (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], {
  258. path: page.path,
  259. locale: page.localeCode
  260. })) {
  261. return page.updatedAt > args.checkoutDate
  262. } else {
  263. throw new WIKI.Error.PageUpdateForbidden()
  264. }
  265. } else {
  266. throw new WIKI.Error.PageNotFound()
  267. }
  268. },
  269. /**
  270. * FETCH LATEST VERSION FOR CONFLICT COMPARISON
  271. */
  272. async conflictLatest (obj, args, context, info) {
  273. let page = await WIKI.models.pages.getPageFromDb(args.id)
  274. if (page) {
  275. if (WIKI.auth.checkAccess(context.req.user, ['write:pages', 'manage:pages'], {
  276. path: page.path,
  277. locale: page.localeCode
  278. })) {
  279. return {
  280. ...page,
  281. tags: page.tags.map(t => t.tag),
  282. locale: page.localeCode
  283. }
  284. } else {
  285. throw new WIKI.Error.PageViewForbidden()
  286. }
  287. } else {
  288. throw new WIKI.Error.PageNotFound()
  289. }
  290. }
  291. },
  292. PageMutation: {
  293. /**
  294. * CREATE PAGE
  295. */
  296. async create(obj, args, context) {
  297. try {
  298. const page = await WIKI.models.pages.createPage({
  299. ...args,
  300. user: context.req.user
  301. })
  302. return {
  303. responseResult: graphHelper.generateSuccess('Page created successfully.'),
  304. page
  305. }
  306. } catch (err) {
  307. return graphHelper.generateError(err)
  308. }
  309. },
  310. /**
  311. * UPDATE PAGE
  312. */
  313. async update(obj, args, context) {
  314. try {
  315. const page = await WIKI.models.pages.updatePage({
  316. ...args,
  317. user: context.req.user
  318. })
  319. return {
  320. responseResult: graphHelper.generateSuccess('Page has been updated.'),
  321. page
  322. }
  323. } catch (err) {
  324. return graphHelper.generateError(err)
  325. }
  326. },
  327. /**
  328. * MOVE PAGE
  329. */
  330. async move(obj, args, context) {
  331. try {
  332. await WIKI.models.pages.movePage({
  333. ...args,
  334. user: context.req.user
  335. })
  336. return {
  337. responseResult: graphHelper.generateSuccess('Page has been moved.')
  338. }
  339. } catch (err) {
  340. return graphHelper.generateError(err)
  341. }
  342. },
  343. /**
  344. * DELETE PAGE
  345. */
  346. async delete(obj, args, context) {
  347. try {
  348. await WIKI.models.pages.deletePage({
  349. ...args,
  350. user: context.req.user
  351. })
  352. return {
  353. responseResult: graphHelper.generateSuccess('Page has been deleted.')
  354. }
  355. } catch (err) {
  356. return graphHelper.generateError(err)
  357. }
  358. },
  359. /**
  360. * DELETE TAG
  361. */
  362. async deleteTag (obj, args, context) {
  363. try {
  364. const tagToDel = await WIKI.models.tags.query().findById(args.id)
  365. if (tagToDel) {
  366. await tagToDel.$relatedQuery('pages').unrelate()
  367. await WIKI.models.tags.query().deleteById(args.id)
  368. } else {
  369. throw new Error('This tag does not exist.')
  370. }
  371. return {
  372. responseResult: graphHelper.generateSuccess('Tag has been deleted.')
  373. }
  374. } catch (err) {
  375. return graphHelper.generateError(err)
  376. }
  377. },
  378. /**
  379. * UPDATE TAG
  380. */
  381. async updateTag (obj, args, context) {
  382. try {
  383. const affectedRows = await WIKI.models.tags.query()
  384. .findById(args.id)
  385. .patch({
  386. tag: args.tag,
  387. title: args.title
  388. })
  389. if (affectedRows < 1) {
  390. throw new Error('This tag does not exist.')
  391. }
  392. return {
  393. responseResult: graphHelper.generateSuccess('Tag has been updated successfully.')
  394. }
  395. } catch (err) {
  396. return graphHelper.generateError(err)
  397. }
  398. },
  399. /**
  400. * FLUSH PAGE CACHE
  401. */
  402. async flushCache(obj, args, context) {
  403. try {
  404. await WIKI.models.pages.flushCache()
  405. return {
  406. responseResult: graphHelper.generateSuccess('Pages Cache has been flushed successfully.')
  407. }
  408. } catch (err) {
  409. return graphHelper.generateError(err)
  410. }
  411. },
  412. /**
  413. * MIGRATE ALL PAGES FROM SOURCE LOCALE TO TARGET LOCALE
  414. */
  415. async migrateToLocale(obj, args, context) {
  416. try {
  417. const count = await WIKI.models.pages.migrateToLocale(args)
  418. return {
  419. responseResult: graphHelper.generateSuccess('Migrated content to target locale successfully.'),
  420. count
  421. }
  422. } catch (err) {
  423. return graphHelper.generateError(err)
  424. }
  425. },
  426. /**
  427. * REBUILD TREE
  428. */
  429. async rebuildTree(obj, args, context) {
  430. try {
  431. await WIKI.models.pages.rebuildTree()
  432. return {
  433. responseResult: graphHelper.generateSuccess('Page tree rebuilt successfully.')
  434. }
  435. } catch (err) {
  436. return graphHelper.generateError(err)
  437. }
  438. },
  439. /**
  440. * RENDER PAGE
  441. */
  442. async render (obj, args, context) {
  443. try {
  444. const page = await WIKI.models.pages.query().findById(args.id)
  445. if (!page) {
  446. throw new WIKI.Error.PageNotFound()
  447. }
  448. await WIKI.models.pages.renderPage(page)
  449. return {
  450. responseResult: graphHelper.generateSuccess('Page rendered successfully.')
  451. }
  452. } catch (err) {
  453. return graphHelper.generateError(err)
  454. }
  455. },
  456. /**
  457. * RESTORE PAGE VERSION
  458. */
  459. async restore (obj, args, context) {
  460. try {
  461. const page = await WIKI.models.pages.query().select('path', 'localeCode').findById(args.pageId)
  462. if (!page) {
  463. throw new WIKI.Error.PageNotFound()
  464. }
  465. if (!WIKI.auth.checkAccess(context.req.user, ['write:pages'], {
  466. path: page.path,
  467. locale: page.localeCode
  468. })) {
  469. throw new WIKI.Error.PageRestoreForbidden()
  470. }
  471. const targetVersion = await WIKI.models.pageHistory.getVersion({ pageId: args.pageId, versionId: args.versionId })
  472. if (!targetVersion) {
  473. throw new WIKI.Error.PageNotFound()
  474. }
  475. await WIKI.models.pages.updatePage({
  476. ...targetVersion,
  477. id: targetVersion.pageId,
  478. user: context.req.user,
  479. action: 'restored'
  480. })
  481. return {
  482. responseResult: graphHelper.generateSuccess('Page version restored successfully.')
  483. }
  484. } catch (err) {
  485. return graphHelper.generateError(err)
  486. }
  487. }
  488. },
  489. Page: {
  490. // comments(pg) {
  491. // return pg.$relatedQuery('comments')
  492. // }
  493. }
  494. }