system.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. const _ = require('lodash')
  2. const util = require('node:util')
  3. const getos = util.promisify(require('getos'))
  4. const os = require('node:os')
  5. const filesize = require('filesize')
  6. const path = require('path')
  7. const fs = require('fs-extra')
  8. const { DateTime } = require('luxon')
  9. const graphHelper = require('../../helpers/graph')
  10. const cronParser = require('cron-parser')
  11. module.exports = {
  12. Query: {
  13. systemFlags () {
  14. return _.transform(WIKI.config.flags, (result, value, key) => {
  15. result.push({ key, value })
  16. }, [])
  17. },
  18. async systemInfo () { return {} },
  19. async systemExtensions () {
  20. const exts = Object.values(WIKI.extensions.ext).map(ext => _.pick(ext, ['key', 'title', 'description', 'isInstalled', 'isInstallable']))
  21. for (const ext of exts) {
  22. ext.isCompatible = await WIKI.extensions.ext[ext.key].isCompatible()
  23. }
  24. return exts
  25. },
  26. systemSecurity () {
  27. return WIKI.config.security
  28. },
  29. async systemJobs (obj, args) {
  30. switch (args.type) {
  31. case 'ACTIVE': {
  32. // const result = await WIKI.scheduler.boss.fetch('*', 25, { includeMeta: true })
  33. return []
  34. }
  35. case 'COMPLETED': {
  36. const result = await WIKI.scheduler.boss.fetchCompleted('*', 25, { includeMeta: true })
  37. console.info(result)
  38. return result ?? []
  39. }
  40. default: {
  41. WIKI.logger.warn('Invalid Job Type requested.')
  42. return []
  43. }
  44. }
  45. },
  46. async systemScheduledJobs (obj, args) {
  47. const jobs = await WIKI.scheduler.boss.getSchedules()
  48. return jobs.map(job => ({
  49. id: job.name,
  50. name: job.name,
  51. cron: job.cron,
  52. timezone: job.timezone,
  53. nextExecution: cronParser.parseExpression(job.cron, { tz: job.timezone }).next(),
  54. createdAt: job.created_on,
  55. updatedAt: job.updated_on
  56. }))
  57. }
  58. },
  59. Mutation: {
  60. async disconnectWS (obj, args, context) {
  61. WIKI.servers.ws.disconnectSockets(true)
  62. WIKI.logger.info('All active websocket connections have been terminated.')
  63. return {
  64. operation: graphHelper.generateSuccess('All websocket connections closed successfully.')
  65. }
  66. },
  67. async installExtension (obj, args, context) {
  68. try {
  69. await WIKI.extensions.ext[args.key].install()
  70. // TODO: broadcast ext install
  71. return {
  72. operation: graphHelper.generateSuccess('Extension installed successfully')
  73. }
  74. } catch (err) {
  75. return graphHelper.generateError(err)
  76. }
  77. },
  78. async updateSystemFlags (obj, args, context) {
  79. WIKI.config.flags = _.transform(args.flags, (result, row) => {
  80. _.set(result, row.key, row.value)
  81. }, {})
  82. await WIKI.configSvc.applyFlags()
  83. await WIKI.configSvc.saveToDb(['flags'])
  84. return {
  85. operation: graphHelper.generateSuccess('System Flags applied successfully')
  86. }
  87. },
  88. async updateSystemSecurity (obj, args, context) {
  89. WIKI.config.security = _.defaultsDeep(_.omit(args, ['__typename']), WIKI.config.security)
  90. // TODO: broadcast config update
  91. await WIKI.configSvc.saveToDb(['security'])
  92. return {
  93. status: graphHelper.generateSuccess('System Security configuration applied successfully')
  94. }
  95. }
  96. },
  97. SystemInfo: {
  98. configFile () {
  99. return path.join(process.cwd(), 'config.yml')
  100. },
  101. cpuCores () {
  102. return os.cpus().length
  103. },
  104. currentVersion () {
  105. return WIKI.version
  106. },
  107. dbHost () {
  108. return WIKI.config.db.host
  109. },
  110. dbVersion () {
  111. return _.get(WIKI.db, 'knex.client.version', 'Unknown Version')
  112. },
  113. hostname () {
  114. return os.hostname()
  115. },
  116. httpPort () {
  117. return WIKI.servers.servers.http ? _.get(WIKI.servers.servers.http.address(), 'port', 0) : 0
  118. },
  119. httpRedirection () {
  120. return _.get(WIKI.config, 'server.sslRedir', false)
  121. },
  122. httpsPort () {
  123. return WIKI.servers.servers.https ? _.get(WIKI.servers.servers.https.address(), 'port', 0) : 0
  124. },
  125. latestVersion () {
  126. return WIKI.system.updates.version
  127. },
  128. latestVersionReleaseDate () {
  129. return DateTime.fromISO(WIKI.system.updates.releaseDate).toJSDate()
  130. },
  131. mailConfigured () {
  132. return WIKI.config?.mail?.host?.length > 2
  133. },
  134. nodeVersion () {
  135. return process.version.substr(1)
  136. },
  137. async operatingSystem () {
  138. let osLabel = `${os.type()} (${os.platform()}) ${os.release()} ${os.arch()}`
  139. if (os.platform() === 'linux') {
  140. const osInfo = await getos()
  141. osLabel = `${os.type()} - ${osInfo.dist} (${osInfo.codename || os.platform()}) ${osInfo.release || os.release()} ${os.arch()}`
  142. }
  143. return osLabel
  144. },
  145. async platform () {
  146. const isDockerized = await fs.pathExists('/.dockerenv')
  147. if (isDockerized) {
  148. return 'docker'
  149. }
  150. return os.platform()
  151. },
  152. ramTotal () {
  153. return filesize(os.totalmem())
  154. },
  155. sslDomain () {
  156. return WIKI.config.ssl.enabled && WIKI.config.ssl.provider === 'letsencrypt' ? WIKI.config.ssl.domain : null
  157. },
  158. sslExpirationDate () {
  159. return WIKI.config.ssl.enabled && WIKI.config.ssl.provider === 'letsencrypt' ? _.get(WIKI.config.letsencrypt, 'payload.expires', null) : null
  160. },
  161. sslProvider () {
  162. return WIKI.config.ssl.enabled ? WIKI.config.ssl.provider : null
  163. },
  164. sslStatus () {
  165. return 'OK'
  166. },
  167. sslSubscriberEmail () {
  168. return WIKI.config.ssl.enabled && WIKI.config.ssl.provider === 'letsencrypt' ? WIKI.config.ssl.subscriberEmail : null
  169. },
  170. telemetry () {
  171. return WIKI.telemetry.enabled
  172. },
  173. telemetryClientId () {
  174. return WIKI.config.telemetry.clientId
  175. },
  176. async upgradeCapable () {
  177. return !_.isNil(process.env.UPGRADE_COMPANION)
  178. },
  179. workingDirectory () {
  180. return process.cwd()
  181. },
  182. async groupsTotal () {
  183. const total = await WIKI.db.groups.query().count('* as total').first()
  184. return _.toSafeInteger(total.total)
  185. },
  186. async pagesTotal () {
  187. const total = await WIKI.db.pages.query().count('* as total').first()
  188. return _.toSafeInteger(total.total)
  189. },
  190. async usersTotal () {
  191. const total = await WIKI.db.users.query().count('* as total').first()
  192. return _.toSafeInteger(total.total)
  193. },
  194. async tagsTotal () {
  195. const total = await WIKI.db.tags.query().count('* as total').first()
  196. return _.toSafeInteger(total.total)
  197. }
  198. }
  199. }