2023-07-02 13:56:25 +03:00
package v1
import (
"encoding/json"
"net/http"
"github.com/labstack/echo/v4"
2023-07-31 15:55:40 +03:00
"github.com/usememos/memos/api/auth"
2023-07-02 13:56:25 +03:00
"github.com/usememos/memos/common/log"
"github.com/usememos/memos/server/profile"
"github.com/usememos/memos/store"
"go.uber.org/zap"
)
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 16:22:02 +03:00
// Disable password login.
DisablePasswordLogin bool ` json:"disablePasswordLogin" `
2023-07-02 13:56:25 +03:00
// Disable public memos.
DisablePublicMemos bool ` json:"disablePublicMemos" `
// Max upload size.
MaxUploadSizeMiB int ` json:"maxUploadSizeMiB" `
2023-07-19 16:39:21 +03:00
// Auto Backup Interval.
AutoBackupInterval int ` json:"autoBackupInterval" `
2023-07-02 13:56:25 +03:00
// 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 16:55:07 +03:00
StorageServiceID int32 ` json:"storageServiceId" `
2023-07-02 13:56:25 +03: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 16:53:06 +03:00
g . GET ( "/ping" , s . ping )
g . GET ( "/status" , s . status )
g . POST ( "/system/vacuum" , s . vacuum )
}
2023-07-02 13:56:25 +03:00
2023-08-09 16:53:06 +03:00
// ping godoc
//
// @Summary Ping the system
// @Tags system
// @Produce json
// @Success 200 {object} profile.Profile "System profile"
// @Router /api/v1/ping [GET]
func ( s * APIV1Service ) ping ( c echo . Context ) error {
return c . JSON ( http . StatusOK , s . Profile )
}
2023-07-02 13:56:25 +03:00
2023-08-09 16:53:06 +03:00
// status godoc
//
// @Summary Get system status
// @Tags system
// @Produce json
// @Success 200 {object} SystemStatus "System status"
// @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"
// @Router /api/v1/status [GET]
func ( s * APIV1Service ) status ( c echo . Context ) error {
ctx := c . Request ( ) . Context ( )
2023-07-02 13:56:25 +03:00
2023-08-09 16:53:06 +03:00
systemStatus := SystemStatus {
Profile : * s . Profile ,
DBSize : 0 ,
AllowSignUp : false ,
DisablePasswordLogin : false ,
DisablePublicMemos : false ,
MaxUploadSizeMiB : 32 ,
AutoBackupInterval : 0 ,
AdditionalStyle : "" ,
AdditionalScript : "" ,
CustomizedProfile : CustomizedProfile {
Name : "memos" ,
LogoURL : "" ,
Description : "" ,
Locale : "en" ,
Appearance : "system" ,
ExternalURL : "" ,
} ,
StorageServiceID : DatabaseStorage ,
LocalStoragePath : "assets/{timestamp}_{filename}" ,
MemoDisplayWithUpdatedTs : false ,
}
2023-07-02 13:56:25 +03:00
2023-08-09 16:53:06 +03:00
hostUserType := store . RoleHost
hostUser , err := s . Store . GetUser ( ctx , & store . FindUser {
Role : & hostUserType ,
2023-07-02 13:56:25 +03:00
} )
2023-08-09 16:53:06 +03: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 13:56:25 +03:00
2023-08-09 16:53:06 +03: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 {
if systemSetting . Name == SystemSettingServerIDName . String ( ) || systemSetting . Name == SystemSettingSecretSessionName . String ( ) || systemSetting . Name == SystemSettingTelegramBotTokenName . String ( ) {
continue
2023-07-02 13:56:25 +03:00
}
2023-08-09 16:53:06 +03:00
var baseValue any
err := json . Unmarshal ( [ ] byte ( systemSetting . Value ) , & baseValue )
2023-07-02 13:56:25 +03:00
if err != nil {
2023-08-09 16:53:06 +03:00
log . Warn ( "Failed to unmarshal system setting value" , zap . String ( "setting name" , systemSetting . Name ) )
continue
2023-07-02 13:56:25 +03:00
}
2023-08-09 16:53:06 +03: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 SystemSettingAutoBackupIntervalName . String ( ) :
systemStatus . AutoBackupInterval = 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 13:56:25 +03:00
}
2023-08-09 16:53:06 +03:00
}
return c . JSON ( http . StatusOK , systemStatus )
}
// vacuum godoc
//
// @Summary Vacuum the database
// @Tags system
// @Produce json
// @Success 200 {boolean} true "Database vacuumed"
// @Failure 401 {object} nil "Missing user in session | Unauthorized"
// @Failure 500 {object} nil "Failed to find user | Failed to vacuum database"
// @Security ApiKeyAuth
// @Router /api/v1/system/vacuum [POST]
func ( s * APIV1Service ) vacuum ( c echo . Context ) error {
ctx := c . Request ( ) . Context ( )
userID , ok := c . Get ( auth . UserIDContextKey ) . ( int32 )
if ! ok {
return echo . NewHTTPError ( http . StatusUnauthorized , "Missing user in session" )
}
user , err := s . Store . GetUser ( ctx , & store . FindUser {
ID : & userID ,
2023-07-02 13:56:25 +03:00
} )
2023-08-09 16:53:06 +03: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 13:56:25 +03:00
}