page.js 12 KB

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