2023-07-02 18:56:25 +08:00
package v1
import (
"encoding/json"
"net/http"
"github.com/labstack/echo/v4"
2023-09-17 22:55:13 +08:00
"go.uber.org/zap"
2023-10-26 09:02:50 +08:00
"github.com/usememos/memos/internal/log"
2023-07-02 18:56:25 +08:00
"github.com/usememos/memos/server/profile"
"github.com/usememos/memos/store"
)
type SystemStatus struct {
Host * User ` json:"host" `
Profile profile . Profile ` json:"profile" `
DBSize int64 ` json:"dbSize" `
// System settings
// Allow sign up.
AllowSignUp bool ` json:"allowSignUp" `
2023-07-30 21:22:02 +08:00
// Disable password login.
DisablePasswordLogin bool ` json:"disablePasswordLogin" `
2023-07-02 18:56:25 +08:00
// Disable public memos.
DisablePublicMemos bool ` json:"disablePublicMemos" `
// Max upload size.
MaxUploadSizeMiB int ` json:"maxUploadSizeMiB" `
// Additional style.
AdditionalStyle string ` json:"additionalStyle" `
// Additional script.
AdditionalScript string ` json:"additionalScript" `
// Customized server profile, including server name and external url.
CustomizedProfile CustomizedProfile ` json:"customizedProfile" `
// Storage service ID.
2023-08-04 21:55:07 +08:00
StorageServiceID int32 ` json:"storageServiceId" `
2023-07-02 18:56:25 +08:00
// Local storage path.
LocalStoragePath string ` json:"localStoragePath" `
// Memo display with updated timestamp.
MemoDisplayWithUpdatedTs bool ` json:"memoDisplayWithUpdatedTs" `
}
func ( s * APIV1Service ) registerSystemRoutes ( g * echo . Group ) {
2023-08-09 22:30:27 +08:00
g . GET ( "/ping" , s . PingSystem )
g . GET ( "/status" , s . GetSystemStatus )
g . POST ( "/system/vacuum" , s . ExecVacuum )
2023-08-09 21:53:06 +08:00
}
2023-07-02 18:56:25 +08:00
2023-08-09 22:30:27 +08:00
// PingSystem godoc
2023-08-09 21:53:06 +08:00
//
// @Summary Ping the system
// @Tags system
// @Produce json
2023-08-10 09:01:38 +08:00
// @Success 200 {boolean} true "If succeed to ping the system"
// @Router /api/v1/ping [GET]
func ( * APIV1Service ) PingSystem ( c echo . Context ) error {
return c . JSON ( http . StatusOK , true )
2023-08-09 21:53:06 +08:00
}
2023-07-02 18:56:25 +08:00
2023-08-09 22:30:27 +08:00
// GetSystemStatus godoc
2023-08-09 21:53:06 +08:00
//
2023-08-09 22:30:27 +08:00
// @Summary Get system GetSystemStatus
2023-08-09 21:53:06 +08:00
// @Tags system
// @Produce json
2023-08-09 22:30:27 +08:00
// @Success 200 {object} SystemStatus "System GetSystemStatus"
2023-08-09 21:53:06 +08:00
// @Failure 401 {object} nil "Missing user in session | Unauthorized"
// @Failure 500 {object} nil "Failed to find host user | Failed to find system setting list | Failed to unmarshal system setting customized profile value"
2023-08-10 09:01:38 +08:00
// @Router /api/v1/status [GET]
2023-08-09 22:30:27 +08:00
func ( s * APIV1Service ) GetSystemStatus ( c echo . Context ) error {
2023-08-09 21:53:06 +08:00
ctx := c . Request ( ) . Context ( )
2023-07-02 18:56:25 +08:00
2023-08-09 21:53:06 +08:00
systemStatus := SystemStatus {
2023-10-20 17:41:21 +08:00
Profile : profile . Profile {
Mode : s . Profile . Mode ,
Version : s . Profile . Version ,
} ,
2023-10-05 15:50:16 +08:00
// Allow sign up by default.
AllowSignUp : true ,
MaxUploadSizeMiB : 32 ,
2023-08-09 21:53:06 +08:00
CustomizedProfile : CustomizedProfile {
2023-12-15 22:57:53 +08:00
Name : "Memos" ,
2023-10-05 15:50:16 +08:00
Locale : "en" ,
Appearance : "system" ,
2023-08-09 21:53:06 +08:00
} ,
2023-10-05 15:50:16 +08:00
StorageServiceID : DefaultStorage ,
LocalStoragePath : "assets/{timestamp}_{filename}" ,
2023-08-09 21:53:06 +08:00
}
2023-07-02 18:56:25 +08:00
2023-08-09 21:53:06 +08:00
hostUserType := store . RoleHost
hostUser , err := s . Store . GetUser ( ctx , & store . FindUser {
Role : & hostUserType ,
2023-07-02 18:56:25 +08:00
} )
2023-08-09 21:53:06 +08:00
if err != nil {
return echo . NewHTTPError ( http . StatusInternalServerError , "Failed to find host user" ) . SetInternal ( err )
}
if hostUser != nil {
systemStatus . Host = & User { ID : hostUser . ID }
}
2023-07-02 18:56:25 +08:00
2023-08-09 21:53:06 +08:00
systemSettingList , err := s . Store . ListSystemSettings ( ctx , & store . FindSystemSetting { } )
if err != nil {
return echo . NewHTTPError ( http . StatusInternalServerError , "Failed to find system setting list" ) . SetInternal ( err )
}
for _ , systemSetting := range systemSettingList {
2023-12-15 19:39:37 +08:00
if systemSetting . Name == SystemSettingServerIDName . String ( ) || systemSetting . Name == SystemSettingSecretSessionName . String ( ) || systemSetting . Name == SystemSettingTelegramBotTokenName . String ( ) || systemSetting . Name == SystemSettingInstanceURLName . String ( ) {
2023-08-09 21:53:06 +08:00
continue
2023-07-02 18:56:25 +08:00
}
2023-08-09 21:53:06 +08:00
var baseValue any
err := json . Unmarshal ( [ ] byte ( systemSetting . Value ) , & baseValue )
2023-07-02 18:56:25 +08:00
if err != nil {
2023-12-23 08:55:23 +08:00
// Skip invalid value.
2023-08-09 21:53:06 +08:00
continue
2023-07-02 18:56:25 +08:00
}
2023-08-09 21:53:06 +08:00
switch systemSetting . Name {
case SystemSettingAllowSignUpName . String ( ) :
systemStatus . AllowSignUp = baseValue . ( bool )
case SystemSettingDisablePasswordLoginName . String ( ) :
systemStatus . DisablePasswordLogin = baseValue . ( bool )
case SystemSettingDisablePublicMemosName . String ( ) :
systemStatus . DisablePublicMemos = baseValue . ( bool )
case SystemSettingMaxUploadSizeMiBName . String ( ) :
systemStatus . MaxUploadSizeMiB = int ( baseValue . ( float64 ) )
case SystemSettingAdditionalStyleName . String ( ) :
systemStatus . AdditionalStyle = baseValue . ( string )
case SystemSettingAdditionalScriptName . String ( ) :
systemStatus . AdditionalScript = baseValue . ( string )
case SystemSettingCustomizedProfileName . String ( ) :
customizedProfile := CustomizedProfile { }
if err := json . Unmarshal ( [ ] byte ( systemSetting . Value ) , & customizedProfile ) ; err != nil {
return echo . NewHTTPError ( http . StatusInternalServerError , "Failed to unmarshal system setting customized profile value" ) . SetInternal ( err )
}
systemStatus . CustomizedProfile = customizedProfile
case SystemSettingStorageServiceIDName . String ( ) :
systemStatus . StorageServiceID = int32 ( baseValue . ( float64 ) )
case SystemSettingLocalStoragePathName . String ( ) :
systemStatus . LocalStoragePath = baseValue . ( string )
case SystemSettingMemoDisplayWithUpdatedTsName . String ( ) :
systemStatus . MemoDisplayWithUpdatedTs = baseValue . ( bool )
default :
log . Warn ( "Unknown system setting name" , zap . String ( "setting name" , systemSetting . Name ) )
2023-07-02 18:56:25 +08:00
}
2023-08-09 21:53:06 +08:00
}
return c . JSON ( http . StatusOK , systemStatus )
}
2023-08-09 22:30:27 +08:00
// ExecVacuum godoc
2023-08-09 21:53:06 +08:00
//
// @Summary Vacuum the database
// @Tags system
// @Produce json
// @Success 200 {boolean} true "Database vacuumed"
// @Failure 401 {object} nil "Missing user in session | Unauthorized"
2023-08-09 22:30:27 +08:00
// @Failure 500 {object} nil "Failed to find user | Failed to ExecVacuum database"
2023-08-10 09:01:38 +08:00
// @Router /api/v1/system/vacuum [POST]
2023-08-09 22:30:27 +08:00
func ( s * APIV1Service ) ExecVacuum ( c echo . Context ) error {
2023-08-09 21:53:06 +08:00
ctx := c . Request ( ) . Context ( )
2023-09-14 20:16:17 +08:00
userID , ok := c . Get ( userIDContextKey ) . ( int32 )
2023-08-09 21:53:06 +08:00
if ! ok {
return echo . NewHTTPError ( http . StatusUnauthorized , "Missing user in session" )
}
user , err := s . Store . GetUser ( ctx , & store . FindUser {
ID : & userID ,
2023-07-02 18:56:25 +08:00
} )
2023-08-09 21:53:06 +08:00
if err != nil {
return echo . NewHTTPError ( http . StatusInternalServerError , "Failed to find user" ) . SetInternal ( err )
}
if user == nil || user . Role != store . RoleHost {
return echo . NewHTTPError ( http . StatusUnauthorized , "Unauthorized" )
}
if err := s . Store . Vacuum ( ctx ) ; err != nil {
return echo . NewHTTPError ( http . StatusInternalServerError , "Failed to vacuum database" ) . SetInternal ( err )
}
return c . JSON ( http . StatusOK , true )
2023-07-02 18:56:25 +08:00
}