system.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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. AdditionalStyle: "",
  40. AdditionalScript: "",
  41. CustomizedProfile: api.CustomizedProfile{
  42. Name: "memos",
  43. LogoURL: "",
  44. Description: "",
  45. Locale: "en",
  46. Appearance: "system",
  47. ExternalURL: "",
  48. },
  49. StorageServiceID: api.DatabaseStorage,
  50. LocalStoragePath: "",
  51. }
  52. systemSettingList, err := s.Store.FindSystemSettingList(ctx, &api.SystemSettingFind{})
  53. if err != nil {
  54. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find system setting list").SetInternal(err)
  55. }
  56. for _, systemSetting := range systemSettingList {
  57. if systemSetting.Name == api.SystemSettingServerIDName || systemSetting.Name == api.SystemSettingSecretSessionName || systemSetting.Name == api.SystemSettingOpenAIConfigName {
  58. continue
  59. }
  60. var baseValue any
  61. err := json.Unmarshal([]byte(systemSetting.Value), &baseValue)
  62. if err != nil {
  63. log.Warn("Failed to unmarshal system setting value", zap.String("setting name", systemSetting.Name.String()))
  64. continue
  65. }
  66. if systemSetting.Name == api.SystemSettingAllowSignUpName {
  67. systemStatus.AllowSignUp = baseValue.(bool)
  68. } else if systemSetting.Name == api.SystemSettingDisablePublicMemosName {
  69. systemStatus.DisablePublicMemos = baseValue.(bool)
  70. } else if systemSetting.Name == api.SystemSettingAdditionalStyleName {
  71. systemStatus.AdditionalStyle = baseValue.(string)
  72. } else if systemSetting.Name == api.SystemSettingAdditionalScriptName {
  73. systemStatus.AdditionalScript = baseValue.(string)
  74. } else if systemSetting.Name == api.SystemSettingCustomizedProfileName {
  75. customizedProfile := api.CustomizedProfile{}
  76. err := json.Unmarshal([]byte(systemSetting.Value), &customizedProfile)
  77. if err != nil {
  78. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting customized profile value").SetInternal(err)
  79. }
  80. systemStatus.CustomizedProfile = customizedProfile
  81. } else if systemSetting.Name == api.SystemSettingStorageServiceIDName {
  82. systemStatus.StorageServiceID = int(baseValue.(float64))
  83. } else if systemSetting.Name == api.SystemSettingLocalStoragePathName {
  84. systemStatus.LocalStoragePath = baseValue.(string)
  85. }
  86. }
  87. userID, ok := c.Get(getUserIDContextKey()).(int)
  88. // Get database size for host user.
  89. if ok {
  90. user, err := s.Store.FindUser(ctx, &api.UserFind{
  91. ID: &userID,
  92. })
  93. if err != nil {
  94. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
  95. }
  96. if user != nil && user.Role == api.Host {
  97. fi, err := os.Stat(s.Profile.DSN)
  98. if err != nil {
  99. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to read database fileinfo").SetInternal(err)
  100. }
  101. systemStatus.DBSize = fi.Size()
  102. }
  103. }
  104. return c.JSON(http.StatusOK, composeResponse(systemStatus))
  105. })
  106. g.POST("/system/setting", func(c echo.Context) error {
  107. ctx := c.Request().Context()
  108. userID, ok := c.Get(getUserIDContextKey()).(int)
  109. if !ok {
  110. return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
  111. }
  112. user, err := s.Store.FindUser(ctx, &api.UserFind{
  113. ID: &userID,
  114. })
  115. if err != nil {
  116. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
  117. }
  118. if user == nil || user.Role != api.Host {
  119. return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
  120. }
  121. systemSettingUpsert := &api.SystemSettingUpsert{}
  122. if err := json.NewDecoder(c.Request().Body).Decode(systemSettingUpsert); err != nil {
  123. return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post system setting request").SetInternal(err)
  124. }
  125. if err := systemSettingUpsert.Validate(); err != nil {
  126. return echo.NewHTTPError(http.StatusBadRequest, "system setting invalidate").SetInternal(err)
  127. }
  128. systemSetting, err := s.Store.UpsertSystemSetting(ctx, systemSettingUpsert)
  129. if err != nil {
  130. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert system setting").SetInternal(err)
  131. }
  132. return c.JSON(http.StatusOK, composeResponse(systemSetting))
  133. })
  134. g.GET("/system/setting", func(c echo.Context) error {
  135. ctx := c.Request().Context()
  136. userID, ok := c.Get(getUserIDContextKey()).(int)
  137. if !ok {
  138. return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
  139. }
  140. user, err := s.Store.FindUser(ctx, &api.UserFind{
  141. ID: &userID,
  142. })
  143. if err != nil {
  144. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
  145. }
  146. if user == nil || user.Role != api.Host {
  147. return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
  148. }
  149. systemSettingList, err := s.Store.FindSystemSettingList(ctx, &api.SystemSettingFind{})
  150. if err != nil {
  151. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find system setting list").SetInternal(err)
  152. }
  153. return c.JSON(http.StatusOK, composeResponse(systemSettingList))
  154. })
  155. g.POST("/system/vacuum", func(c echo.Context) error {
  156. ctx := c.Request().Context()
  157. userID, ok := c.Get(getUserIDContextKey()).(int)
  158. if !ok {
  159. return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
  160. }
  161. user, err := s.Store.FindUser(ctx, &api.UserFind{
  162. ID: &userID,
  163. })
  164. if err != nil {
  165. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user").SetInternal(err)
  166. }
  167. if user == nil || user.Role != api.Host {
  168. return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
  169. }
  170. if err := s.Store.Vacuum(ctx); err != nil {
  171. return echo.NewHTTPError(http.StatusInternalServerError, "Failed to vacuum database").SetInternal(err)
  172. }
  173. return c.JSON(http.StatusOK, true)
  174. })
  175. }
  176. func (s *Server) getSystemServerID(ctx context.Context) (string, error) {
  177. serverIDValue, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
  178. Name: api.SystemSettingServerIDName,
  179. })
  180. if err != nil && common.ErrorCode(err) != common.NotFound {
  181. return "", err
  182. }
  183. if serverIDValue == nil || serverIDValue.Value == "" {
  184. serverIDValue, err = s.Store.UpsertSystemSetting(ctx, &api.SystemSettingUpsert{
  185. Name: api.SystemSettingServerIDName,
  186. Value: uuid.NewString(),
  187. })
  188. if err != nil {
  189. return "", err
  190. }
  191. }
  192. return serverIDValue.Value, nil
  193. }
  194. func (s *Server) getSystemSecretSessionName(ctx context.Context) (string, error) {
  195. secretSessionNameValue, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
  196. Name: api.SystemSettingSecretSessionName,
  197. })
  198. if err != nil && common.ErrorCode(err) != common.NotFound {
  199. return "", err
  200. }
  201. if secretSessionNameValue == nil || secretSessionNameValue.Value == "" {
  202. secretSessionNameValue, err = s.Store.UpsertSystemSetting(ctx, &api.SystemSettingUpsert{
  203. Name: api.SystemSettingSecretSessionName,
  204. Value: uuid.NewString(),
  205. })
  206. if err != nil {
  207. return "", err
  208. }
  209. }
  210. return secretSessionNameValue.Value, nil
  211. }