system.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package server
  2. import (
  3. "context"
  4. "encoding/json"
  5. "net/http"
  6. "os"
  7. "github.com/google/uuid"
  8. "github.com/usememos/memos/api"
  9. "github.com/usememos/memos/common"
  10. "github.com/usememos/memos/common/log"
  11. "go.uber.org/zap"
  12. "github.com/labstack/echo/v4"
  13. )
  14. func (s *Server) registerSystemRoutes(g *echo.Group) {
  15. g.GET("/ping", func(c echo.Context) error {
  16. return c.JSON(http.StatusOK, composeResponse(s.Profile))
  17. })
  18. g.GET("/status", func(c echo.Context) error {
  19. ctx := c.Request().Context()
  20. hostUserType := api.Host
  21. hostUserFind := api.UserFind{
  22. Role: &hostUserType,
  23. }
  24. hostUser, err := s.Store.FindUser(ctx, &hostUserFind)
  25. if err != nil && common.ErrorCode(err) != common.NotFound {
  26. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find host user").SetInternal(err)
  27. }
  28. if hostUser != nil {
  29. // data desensitize
  30. hostUser.OpenID = ""
  31. hostUser.Email = ""
  32. }
  33. systemStatus := api.SystemStatus{
  34. Host: hostUser,
  35. Profile: *s.Profile,
  36. DBSize: 0,
  37. AllowSignUp: false,
  38. DisablePublicMemos: false,
  39. MaxUploadSizeMiB: 32,
  40. AdditionalStyle: "",
  41. AdditionalScript: "",
  42. CustomizedProfile: api.CustomizedProfile{
  43. Name: "memos",
  44. LogoURL: "",
  45. Description: "",
  46. Locale: "en",
  47. Appearance: "system",
  48. ExternalURL: "",
  49. },
  50. StorageServiceID: api.DatabaseStorage,
  51. LocalStoragePath: "assets/{timestamp}_{filename}",
  52. MemoDisplayWithUpdatedTs: false,
  53. }
  54. systemSettingList, err := s.Store.FindSystemSettingList(ctx, &api.SystemSettingFind{})
  55. if err != nil {
  56. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find system setting list").SetInternal(err)
  57. }
  58. for _, systemSetting := range systemSettingList {
  59. if systemSetting.Name == api.SystemSettingServerIDName || systemSetting.Name == api.SystemSettingSecretSessionName || systemSetting.Name == api.SystemSettingOpenAIConfigName || systemSetting.Name == api.SystemSettingTelegramBotTokenName {
  60. continue
  61. }
  62. var baseValue any
  63. err := json.Unmarshal([]byte(systemSetting.Value), &baseValue)
  64. if err != nil {
  65. log.Warn("Failed to unmarshal system setting value", zap.String("setting name", systemSetting.Name.String()))
  66. continue
  67. }
  68. switch systemSetting.Name {
  69. case api.SystemSettingAllowSignUpName:
  70. systemStatus.AllowSignUp = baseValue.(bool)
  71. case api.SystemSettingDisablePublicMemosName:
  72. systemStatus.DisablePublicMemos = baseValue.(bool)
  73. case api.SystemSettingMaxUploadSizeMiBName:
  74. systemStatus.MaxUploadSizeMiB = int(baseValue.(float64))
  75. case api.SystemSettingAdditionalStyleName:
  76. systemStatus.AdditionalStyle = baseValue.(string)
  77. case api.SystemSettingAdditionalScriptName:
  78. systemStatus.AdditionalScript = baseValue.(string)
  79. case api.SystemSettingCustomizedProfileName:
  80. customizedProfile := api.CustomizedProfile{}
  81. if err := json.Unmarshal([]byte(systemSetting.Value), &customizedProfile); err != nil {
  82. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting customized profile value").SetInternal(err)
  83. }
  84. systemStatus.CustomizedProfile = customizedProfile
  85. case api.SystemSettingStorageServiceIDName:
  86. systemStatus.StorageServiceID = int(baseValue.(float64))
  87. case api.SystemSettingLocalStoragePathName:
  88. systemStatus.LocalStoragePath = baseValue.(string)
  89. case api.SystemSettingMemoDisplayWithUpdatedTsName:
  90. systemStatus.MemoDisplayWithUpdatedTs = baseValue.(bool)
  91. default:
  92. log.Warn("Unknown system setting name", zap.String("setting name", systemSetting.Name.String()))
  93. }
  94. }
  95. userID, ok := c.Get(getUserIDContextKey()).(int)
  96. // Get database size for host user.
  97. if ok {
  98. user, err := s.Store.FindUser(ctx, &api.UserFind{
  99. ID: &userID,
  100. })
  101. if err != nil {
  102. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
  103. }
  104. if user != nil && user.Role == api.Host {
  105. fi, err := os.Stat(s.Profile.DSN)
  106. if err != nil {
  107. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to read database fileinfo").SetInternal(err)
  108. }
  109. systemStatus.DBSize = fi.Size()
  110. }
  111. }
  112. return c.JSON(http.StatusOK, composeResponse(systemStatus))
  113. })
  114. g.POST("/system/setting", func(c echo.Context) error {
  115. ctx := c.Request().Context()
  116. userID, ok := c.Get(getUserIDContextKey()).(int)
  117. if !ok {
  118. return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
  119. }
  120. user, err := s.Store.FindUser(ctx, &api.UserFind{
  121. ID: &userID,
  122. })
  123. if err != nil {
  124. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
  125. }
  126. if user == nil || user.Role != api.Host {
  127. return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
  128. }
  129. systemSettingUpsert := &api.SystemSettingUpsert{}
  130. if err := json.NewDecoder(c.Request().Body).Decode(systemSettingUpsert); err != nil {
  131. return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post system setting request").SetInternal(err)
  132. }
  133. if err := systemSettingUpsert.Validate(); err != nil {
  134. return echo.NewHTTPError(http.StatusBadRequest, "system setting invalidate").SetInternal(err)
  135. }
  136. systemSetting, err := s.Store.UpsertSystemSetting(ctx, systemSettingUpsert)
  137. if err != nil {
  138. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert system setting").SetInternal(err)
  139. }
  140. return c.JSON(http.StatusOK, composeResponse(systemSetting))
  141. })
  142. g.GET("/system/setting", func(c echo.Context) error {
  143. ctx := c.Request().Context()
  144. userID, ok := c.Get(getUserIDContextKey()).(int)
  145. if !ok {
  146. return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
  147. }
  148. user, err := s.Store.FindUser(ctx, &api.UserFind{
  149. ID: &userID,
  150. })
  151. if err != nil {
  152. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
  153. }
  154. if user == nil || user.Role != api.Host {
  155. return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
  156. }
  157. systemSettingList, err := s.Store.FindSystemSettingList(ctx, &api.SystemSettingFind{})
  158. if err != nil {
  159. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find system setting list").SetInternal(err)
  160. }
  161. return c.JSON(http.StatusOK, composeResponse(systemSettingList))
  162. })
  163. g.POST("/system/vacuum", func(c echo.Context) error {
  164. ctx := c.Request().Context()
  165. userID, ok := c.Get(getUserIDContextKey()).(int)
  166. if !ok {
  167. return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
  168. }
  169. user, err := s.Store.FindUser(ctx, &api.UserFind{
  170. ID: &userID,
  171. })
  172. if err != nil {
  173. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
  174. }
  175. if user == nil || user.Role != api.Host {
  176. return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
  177. }
  178. if err := s.Store.Vacuum(ctx); err != nil {
  179. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to vacuum database").SetInternal(err)
  180. }
  181. return c.JSON(http.StatusOK, true)
  182. })
  183. }
  184. func (s *Server) getSystemServerID(ctx context.Context) (string, error) {
  185. serverIDValue, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
  186. Name: api.SystemSettingServerIDName,
  187. })
  188. if err != nil && common.ErrorCode(err) != common.NotFound {
  189. return "", err
  190. }
  191. if serverIDValue == nil || serverIDValue.Value == "" {
  192. serverIDValue, err = s.Store.UpsertSystemSetting(ctx, &api.SystemSettingUpsert{
  193. Name: api.SystemSettingServerIDName,
  194. Value: uuid.NewString(),
  195. })
  196. if err != nil {
  197. return "", err
  198. }
  199. }
  200. return serverIDValue.Value, nil
  201. }
  202. func (s *Server) getSystemSecretSessionName(ctx context.Context) (string, error) {
  203. secretSessionNameValue, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
  204. Name: api.SystemSettingSecretSessionName,
  205. })
  206. if err != nil && common.ErrorCode(err) != common.NotFound {
  207. return "", err
  208. }
  209. if secretSessionNameValue == nil || secretSessionNameValue.Value == "" {
  210. secretSessionNameValue, err = s.Store.UpsertSystemSetting(ctx, &api.SystemSettingUpsert{
  211. Name: api.SystemSettingSecretSessionName,
  212. Value: uuid.NewString(),
  213. })
  214. if err != nil {
  215. return "", err
  216. }
  217. }
  218. return secretSessionNameValue.Value, nil
  219. }