customize-setting.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /* eslint-disable no-unused-vars */
  2. const loggerFactory = require('@alias/logger');
  3. const logger = loggerFactory('growi:routes:apiv3:customize-setting');
  4. const express = require('express');
  5. const router = express.Router();
  6. const { body, query } = require('express-validator');
  7. const ErrorV3 = require('../../models/vo/error-apiv3');
  8. /**
  9. * @swagger
  10. * tags:
  11. * name: CustomizeSetting
  12. */
  13. /**
  14. * @swagger
  15. *
  16. * components:
  17. * schemas:
  18. * CustomizeTheme:
  19. * description: CustomizeTheme
  20. * type: object
  21. * properties:
  22. * themeType:
  23. * type: string
  24. * CustomizeFunction:
  25. * description: CustomizeFunction
  26. * type: object
  27. * properties:
  28. * isEnabledTimeline:
  29. * type: boolean
  30. * isSavedStatesOfTabChanges:
  31. * type: boolean
  32. * isEnabledAttachTitleHeader:
  33. * type: boolean
  34. * pageLimitationS:
  35. * type: number
  36. * pageLimitationM:
  37. * type: number
  38. * isEnabledStaleNotification:
  39. * type: boolean
  40. * isAllReplyShown:
  41. * type: boolean
  42. * CustomizeHighlight:
  43. * description: CustomizeHighlight
  44. * type: object
  45. * properties:
  46. * styleName:
  47. * type: string
  48. * styleBorder:
  49. * type: boolean
  50. * CustomizeTitle:
  51. * description: CustomizeTitle
  52. * type: object
  53. * properties:
  54. * customizeTitle:
  55. * type: string
  56. * CustomizeHeader:
  57. * description: CustomizeHeader
  58. * type: object
  59. * properties:
  60. * customizeHeader:
  61. * type: string
  62. * CustomizeCss:
  63. * description: CustomizeCss
  64. * type: object
  65. * properties:
  66. * customizeCss:
  67. * type: string
  68. * CustomizeScript:
  69. * description: CustomizeScript
  70. * type: object
  71. * properties:
  72. * customizeScript:
  73. * type: string
  74. */
  75. module.exports = (crowi) => {
  76. const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
  77. const adminRequired = require('../../middlewares/admin-required')(crowi);
  78. const csrf = require('../../middlewares/csrf')(crowi);
  79. const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
  80. const { customizeService } = crowi;
  81. const validator = {
  82. themeAssetPath: [
  83. query('themeName').isString().isIn([
  84. 'default', 'nature', 'mono-blue', 'wood', 'island', 'christmas', 'antarctic', 'future', 'halloween', 'spring',
  85. ]),
  86. ],
  87. theme: [
  88. body('themeType').isString().isIn([
  89. 'default', 'nature', 'mono-blue', 'wood', 'island', 'christmas', 'antarctic', 'future', 'halloween', 'spring', 'kibela',
  90. ]),
  91. ],
  92. function: [
  93. body('isEnabledTimeline').isBoolean(),
  94. body('isSavedStatesOfTabChanges').isBoolean(),
  95. body('isEnabledAttachTitleHeader').isBoolean(),
  96. <<<<<<< HEAD
  97. body('pageLimitationS').isInt({ min: 1, max: 1000 }),
  98. body('pageLimitationM').isInt({ min: 1, max: 1000 }),
  99. =======
  100. body('pageLimitationS').isInt().isInt({ min: 1, max: 1000 }),
  101. body('pageLimitationM').isInt().isInt({ min: 1, max: 1000 }),
  102. body('pageLimitationL').isInt().isInt({ min: 1, max: 1000 }),
  103. body('pageLimitationXL').isInt().isInt({ min: 1, max: 1000 }),
  104. >>>>>>> feat/display-BookMarkList-including-pagination-as-component
  105. body('isEnabledStaleNotification').isBoolean(),
  106. body('isAllReplyShown').isBoolean(),
  107. ],
  108. customizeTitle: [
  109. body('customizeTitle').isString(),
  110. ],
  111. customizeHeader: [
  112. body('customizeHeader').isString(),
  113. ],
  114. highlight: [
  115. body('highlightJsStyle').isString().isIn([
  116. 'github', 'github-gist', 'atom-one-light', 'xcode', 'vs', 'atom-one-dark', 'hybrid', 'monokai', 'tomorrow-night', 'vs2015',
  117. ]),
  118. body('highlightJsStyleBorder').isBoolean(),
  119. ],
  120. customizeCss: [
  121. body('customizeCss').isString(),
  122. ],
  123. customizeScript: [
  124. body('customizeScript').isString(),
  125. ],
  126. };
  127. /**
  128. * @swagger
  129. *
  130. * /customize-setting:
  131. * get:
  132. * tags: [CustomizeSetting]
  133. * operationId: getCustomizeSetting
  134. * summary: /customize-setting
  135. * description: Get customize parameters
  136. * responses:
  137. * 200:
  138. * description: params of customize
  139. * content:
  140. * application/json:
  141. * schema:
  142. * properties:
  143. * customizeParams:
  144. * type: object
  145. * description: customize params
  146. */
  147. router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
  148. const customizeParams = {
  149. layoutType: await crowi.configManager.getConfig('crowi', 'customize:layout'),
  150. themeType: await crowi.configManager.getConfig('crowi', 'customize:theme'),
  151. isEnabledTimeline: await crowi.configManager.getConfig('crowi', 'customize:isEnabledTimeline'),
  152. isSavedStatesOfTabChanges: await crowi.configManager.getConfig('crowi', 'customize:isSavedStatesOfTabChanges'),
  153. isEnabledAttachTitleHeader: await crowi.configManager.getConfig('crowi', 'customize:isEnabledAttachTitleHeader'),
  154. pageLimitationS: await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationS'),
  155. pageLimitationM: await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationM'),
  156. <<<<<<< HEAD
  157. =======
  158. pageLimitationL: await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationL'),
  159. pageLimitationXL: await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationXL'),
  160. >>>>>>> feat/display-BookMarkList-including-pagination-as-component
  161. isEnabledStaleNotification: await crowi.configManager.getConfig('crowi', 'customize:isEnabledStaleNotification'),
  162. isAllReplyShown: await crowi.configManager.getConfig('crowi', 'customize:isAllReplyShown'),
  163. styleName: await crowi.configManager.getConfig('crowi', 'customize:highlightJsStyle'),
  164. styleBorder: await crowi.configManager.getConfig('crowi', 'customize:highlightJsStyleBorder'),
  165. customizeTitle: await crowi.configManager.getConfig('crowi', 'customize:title'),
  166. customizeHeader: await crowi.configManager.getConfig('crowi', 'customize:header'),
  167. customizeCss: await crowi.configManager.getConfig('crowi', 'customize:css'),
  168. customizeScript: await crowi.configManager.getConfig('crowi', 'customize:script'),
  169. };
  170. return res.apiv3({ customizeParams });
  171. });
  172. /**
  173. * @swagger
  174. *
  175. * /customize-setting/theme/asset-path:
  176. * put:
  177. * tags: [CustomizeSetting]
  178. * operationId: getThemeAssetPath
  179. * summary: /customize-setting/theme/asset-path
  180. * description: Get theme asset path
  181. * parameters:
  182. * - name: themeName
  183. * in: query
  184. * required: true
  185. * schema:
  186. * type: string
  187. * responses:
  188. * 200:
  189. * description: Succeeded to get theme asset path
  190. * content:
  191. * application/json:
  192. * schema:
  193. * properties:
  194. * assetPath:
  195. * type: string
  196. */
  197. router.get('/theme/asset-path', loginRequiredStrictly, adminRequired, validator.themeAssetPath, apiV3FormValidator, async(req, res) => {
  198. const { themeName } = req.query;
  199. const webpackAssetKey = `styles/theme-${themeName}.css`;
  200. const assetPath = res.locals.webpack_asset(webpackAssetKey);
  201. if (assetPath == null) {
  202. return res.apiv3Err(new ErrorV3(`The asset for '${webpackAssetKey}' is undefined.`, 'invalid-asset'));
  203. }
  204. return res.apiv3({ assetPath });
  205. });
  206. /**
  207. * @swagger
  208. *
  209. * /customize-setting/theme:
  210. * put:
  211. * tags: [CustomizeSetting]
  212. * operationId: updateThemeCustomizeSetting
  213. * summary: /customize-setting/theme
  214. * description: Update theme
  215. * requestBody:
  216. * required: true
  217. * content:
  218. * application/json:
  219. * schema:
  220. * $ref: '#/components/schemas/CustomizeTheme'
  221. * responses:
  222. * 200:
  223. * description: Succeeded to update theme
  224. * content:
  225. * application/json:
  226. * schema:
  227. * $ref: '#/components/schemas/CustomizeTheme'
  228. */
  229. router.put('/theme', loginRequiredStrictly, adminRequired, csrf, validator.theme, apiV3FormValidator, async(req, res) => {
  230. const requestParams = {
  231. 'customize:theme': req.body.themeType,
  232. };
  233. try {
  234. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
  235. const customizedParams = {
  236. themeType: await crowi.configManager.getConfig('crowi', 'customize:theme'),
  237. };
  238. return res.apiv3({ customizedParams });
  239. }
  240. catch (err) {
  241. const msg = 'Error occurred in updating theme';
  242. logger.error('Error', err);
  243. return res.apiv3Err(new ErrorV3(msg, 'update-theme-failed'));
  244. }
  245. });
  246. /**
  247. * @swagger
  248. *
  249. * /customize-setting/function:
  250. * put:
  251. * tags: [CustomizeSetting]
  252. * operationId: updateFunctionCustomizeSetting
  253. * summary: /customize-setting/function
  254. * description: Update function
  255. * requestBody:
  256. * required: true
  257. * content:
  258. * application/json:
  259. * schema:
  260. * $ref: '#/components/schemas/CustomizeFunction'
  261. * responses:
  262. * 200:
  263. * description: Succeeded to update function
  264. * content:
  265. * application/json:
  266. * schema:
  267. * $ref: '#/components/schemas/CustomizeFunction'
  268. */
  269. router.put('/function', loginRequiredStrictly, adminRequired, csrf, validator.function, apiV3FormValidator, async(req, res) => {
  270. const requestParams = {
  271. 'customize:isEnabledTimeline': req.body.isEnabledTimeline,
  272. 'customize:isSavedStatesOfTabChanges': req.body.isSavedStatesOfTabChanges,
  273. 'customize:isEnabledAttachTitleHeader': req.body.isEnabledAttachTitleHeader,
  274. 'customize:showPageLimitationS': req.body.pageLimitationS,
  275. 'customize:showPageLimitationM': req.body.pageLimitationM,
  276. 'customize:showPageLimitationL': req.body.pageLimitationL,
  277. 'customize:showPageLimitationXL': req.body.pageLimitationXL,
  278. 'customize:isEnabledStaleNotification': req.body.isEnabledStaleNotification,
  279. 'customize:isAllReplyShown': req.body.isAllReplyShown,
  280. };
  281. try {
  282. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
  283. const customizedParams = {
  284. isEnabledTimeline: await crowi.configManager.getConfig('crowi', 'customize:isEnabledTimeline'),
  285. isSavedStatesOfTabChanges: await crowi.configManager.getConfig('crowi', 'customize:isSavedStatesOfTabChanges'),
  286. isEnabledAttachTitleHeader: await crowi.configManager.getConfig('crowi', 'customize:isEnabledAttachTitleHeader'),
  287. pageLimitationS: await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationS'),
  288. pageLimitationM: await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationM'),
  289. pageLimitationL: await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationL'),
  290. pageLimitationXL: await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationXL'),
  291. isEnabledStaleNotification: await crowi.configManager.getConfig('crowi', 'customize:isEnabledStaleNotification'),
  292. isAllReplyShown: await crowi.configManager.getConfig('crowi', 'customize:isAllReplyShown'),
  293. };
  294. return res.apiv3({ customizedParams });
  295. }
  296. catch (err) {
  297. const msg = 'Error occurred in updating function';
  298. logger.error('Error', err);
  299. return res.apiv3Err(new ErrorV3(msg, 'update-function-failed'));
  300. }
  301. });
  302. /**
  303. * @swagger
  304. *
  305. * /customize-setting/highlight:
  306. * put:
  307. * tags: [CustomizeSetting]
  308. * operationId: updateHighlightCustomizeSetting
  309. * summary: /customize-setting/highlight
  310. * description: Update highlight
  311. * requestBody:
  312. * required: true
  313. * content:
  314. * application/json:
  315. * schema:
  316. * $ref: '#/components/schemas/CustomizeHighlight'
  317. * responses:
  318. * 200:
  319. * description: Succeeded to update highlight
  320. * content:
  321. * application/json:
  322. * schema:
  323. * $ref: '#/components/schemas/CustomizeHighlight'
  324. */
  325. router.put('/highlight', loginRequiredStrictly, adminRequired, csrf, validator.highlight, apiV3FormValidator, async(req, res) => {
  326. const requestParams = {
  327. 'customize:highlightJsStyle': req.body.highlightJsStyle,
  328. 'customize:highlightJsStyleBorder': req.body.highlightJsStyleBorder,
  329. };
  330. try {
  331. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
  332. const customizedParams = {
  333. styleName: await crowi.configManager.getConfig('crowi', 'customize:highlightJsStyle'),
  334. styleBorder: await crowi.configManager.getConfig('crowi', 'customize:highlightJsStyleBorder'),
  335. };
  336. return res.apiv3({ customizedParams });
  337. }
  338. catch (err) {
  339. const msg = 'Error occurred in updating highlight';
  340. logger.error('Error', err);
  341. return res.apiv3Err(new ErrorV3(msg, 'update-highlight-failed'));
  342. }
  343. });
  344. /**
  345. * @swagger
  346. *
  347. * /customize-setting/customizeTitle:
  348. * put:
  349. * tags: [CustomizeSetting]
  350. * operationId: updateCustomizeTitleCustomizeSetting
  351. * summary: /customize-setting/customizeTitle
  352. * description: Update customizeTitle
  353. * requestBody:
  354. * required: true
  355. * content:
  356. * application/json:
  357. * schema:
  358. * $ref: '#/components/schemas/CustomizeTitle'
  359. * responses:
  360. * 200:
  361. * description: Succeeded to update customizeTitle
  362. * content:
  363. * application/json:
  364. * schema:
  365. * $ref: '#/components/schemas/CustomizeTitle'
  366. */
  367. router.put('/customize-title', loginRequiredStrictly, adminRequired, csrf, validator.customizeTitle, apiV3FormValidator, async(req, res) => {
  368. const requestParams = {
  369. 'customize:title': req.body.customizeTitle,
  370. };
  371. try {
  372. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams, true);
  373. crowi.customizeService.publishUpdatedMessage();
  374. const customizedParams = {
  375. customizeTitle: await crowi.configManager.getConfig('crowi', 'customize:title'),
  376. };
  377. customizeService.initCustomTitle();
  378. return res.apiv3({ customizedParams });
  379. }
  380. catch (err) {
  381. const msg = 'Error occurred in updating customizeTitle';
  382. logger.error('Error', err);
  383. return res.apiv3Err(new ErrorV3(msg, 'update-customizeTitle-failed'));
  384. }
  385. });
  386. /**
  387. * @swagger
  388. *
  389. * /customize-setting/customizeHeader:
  390. * put:
  391. * tags: [CustomizeSetting]
  392. * operationId: updateCustomizeHeaderCustomizeSetting
  393. * summary: /customize-setting/customizeHeader
  394. * description: Update customizeHeader
  395. * requestBody:
  396. * required: true
  397. * content:
  398. * application/json:
  399. * schema:
  400. * $ref: '#/components/schemas/CustomizeHeader'
  401. * responses:
  402. * 200:
  403. * description: Succeeded to update customize header
  404. * content:
  405. * application/json:
  406. * schema:
  407. * $ref: '#/components/schemas/CustomizeHeader'
  408. */
  409. router.put('/customize-header', loginRequiredStrictly, adminRequired, csrf, validator.customizeHeader, apiV3FormValidator, async(req, res) => {
  410. const requestParams = {
  411. 'customize:header': req.body.customizeHeader,
  412. };
  413. try {
  414. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
  415. const customizedParams = {
  416. customizeHeader: await crowi.configManager.getConfig('crowi', 'customize:header'),
  417. };
  418. return res.apiv3({ customizedParams });
  419. }
  420. catch (err) {
  421. const msg = 'Error occurred in updating customizeHeader';
  422. logger.error('Error', err);
  423. return res.apiv3Err(new ErrorV3(msg, 'update-customizeHeader-failed'));
  424. }
  425. });
  426. /**
  427. * @swagger
  428. *
  429. * /customize-setting/customizeCss:
  430. * put:
  431. * tags: [CustomizeSetting]
  432. * operationId: updateCustomizeCssCustomizeSetting
  433. * summary: /customize-setting/customizeCss
  434. * description: Update customizeCss
  435. * requestBody:
  436. * required: true
  437. * content:
  438. * application/json:
  439. * schema:
  440. * $ref: '#/components/schemas/CustomizeCss'
  441. * responses:
  442. * 200:
  443. * description: Succeeded to update customize css
  444. * content:
  445. * application/json:
  446. * schema:
  447. * $ref: '#/components/schemas/CustomizeCss'
  448. */
  449. router.put('/customize-css', loginRequiredStrictly, adminRequired, csrf, validator.customizeCss, apiV3FormValidator, async(req, res) => {
  450. const requestParams = {
  451. 'customize:css': req.body.customizeCss,
  452. };
  453. try {
  454. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams, true);
  455. crowi.customizeService.publishUpdatedMessage();
  456. const customizedParams = {
  457. customizeCss: await crowi.configManager.getConfig('crowi', 'customize:css'),
  458. };
  459. customizeService.initCustomCss();
  460. return res.apiv3({ customizedParams });
  461. }
  462. catch (err) {
  463. const msg = 'Error occurred in updating customizeCss';
  464. logger.error('Error', err);
  465. return res.apiv3Err(new ErrorV3(msg, 'update-customizeCss-failed'));
  466. }
  467. });
  468. /**
  469. * @swagger
  470. *
  471. * /customize-setting/customizeScript:
  472. * put:
  473. * tags: [CustomizeSetting]
  474. * operationId: updateCustomizeScriptCustomizeSetting
  475. * summary: /customize-setting/customizeScript
  476. * description: Update customizeScript
  477. * requestBody:
  478. * required: true
  479. * content:
  480. * application/json:
  481. * schema:
  482. * $ref: '#/components/schemas/CustomizeScript'
  483. * responses:
  484. * 200:
  485. * description: Succeeded to update customize script
  486. * content:
  487. * application/json:
  488. * schema:
  489. * $ref: '#/components/schemas/CustomizeScript'
  490. */
  491. router.put('/customize-script', loginRequiredStrictly, adminRequired, csrf, validator.customizeScript, apiV3FormValidator, async(req, res) => {
  492. const requestParams = {
  493. 'customize:script': req.body.customizeScript,
  494. };
  495. try {
  496. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
  497. const customizedParams = {
  498. customizeScript: await crowi.configManager.getConfig('crowi', 'customize:script'),
  499. };
  500. return res.apiv3({ customizedParams });
  501. }
  502. catch (err) {
  503. const msg = 'Error occurred in updating customizeScript';
  504. logger.error('Error', err);
  505. return res.apiv3Err(new ErrorV3(msg, 'update-customizeScript-failed'));
  506. }
  507. });
  508. return router;
  509. };