chore: update api v1 docs (#2117)

* chore: update apiv1 docs

* chore: update
pull/2118/head
boojack 2 years ago committed by GitHub
parent 4491c75135
commit 35f2d399e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -32,13 +32,13 @@ type SignUp struct {
} }
func (s *APIV1Service) registerAuthRoutes(g *echo.Group) { func (s *APIV1Service) registerAuthRoutes(g *echo.Group) {
g.POST("/auth/signin", s.signIn) g.POST("/auth/signin", s.SignIn)
g.POST("/auth/signin/sso", s.signInSSO) g.POST("/auth/signin/sso", s.SignInSSO)
g.POST("/auth/signout", s.signOut) g.POST("/auth/signout", s.SignOut)
g.POST("/auth/signup", s.signUp) g.POST("/auth/signup", s.SignUp)
} }
// signIn godoc // SignIn godoc
// //
// @Summary Sign-in to memos. // @Summary Sign-in to memos.
// @Tags auth // @Tags auth
@ -51,7 +51,7 @@ func (s *APIV1Service) registerAuthRoutes(g *echo.Group) {
// @Failure 403 {object} nil "User has been archived with username %s" // @Failure 403 {object} nil "User has been archived with username %s"
// @Failure 500 {object} nil "Failed to find system setting | Failed to unmarshal system setting | Incorrect login credentials, please try again | Failed to generate tokens | Failed to create activity" // @Failure 500 {object} nil "Failed to find system setting | Failed to unmarshal system setting | Incorrect login credentials, please try again | Failed to generate tokens | Failed to create activity"
// @Router /api/v1/auth/signin [POST] // @Router /api/v1/auth/signin [POST]
func (s *APIV1Service) signIn(c echo.Context) error { func (s *APIV1Service) SignIn(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
signin := &SignIn{} signin := &SignIn{}
@ -104,7 +104,7 @@ func (s *APIV1Service) signIn(c echo.Context) error {
return c.JSON(http.StatusOK, userMessage) return c.JSON(http.StatusOK, userMessage)
} }
// signInSSO godoc // SignInSSO godoc
// //
// @Summary Sign-in to memos using SSO. // @Summary Sign-in to memos using SSO.
// @Tags auth // @Tags auth
@ -118,7 +118,7 @@ func (s *APIV1Service) signIn(c echo.Context) error {
// @Failure 404 {object} nil "Identity provider not found" // @Failure 404 {object} nil "Identity provider not found"
// @Failure 500 {object} nil "Failed to find identity provider | Failed to create identity provider instance | Failed to exchange token | Failed to get user info | Failed to compile identifier filter | Incorrect login credentials, please try again | Failed to generate random password | Failed to generate password hash | Failed to create user | Failed to generate tokens | Failed to create activity" // @Failure 500 {object} nil "Failed to find identity provider | Failed to create identity provider instance | Failed to exchange token | Failed to get user info | Failed to compile identifier filter | Incorrect login credentials, please try again | Failed to generate random password | Failed to generate password hash | Failed to create user | Failed to generate tokens | Failed to create activity"
// @Router /api/v1/auth/signin/sso [POST] // @Router /api/v1/auth/signin/sso [POST]
func (s *APIV1Service) signInSSO(c echo.Context) error { func (s *APIV1Service) SignInSSO(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
signin := &SSOSignIn{} signin := &SSOSignIn{}
if err := json.NewDecoder(c.Request().Body).Decode(signin); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(signin); err != nil {
@ -205,19 +205,19 @@ func (s *APIV1Service) signInSSO(c echo.Context) error {
return c.JSON(http.StatusOK, userMessage) return c.JSON(http.StatusOK, userMessage)
} }
// signOut godoc // SignOut godoc
// //
// @Summary Sign-out from memos. // @Summary Sign-out from memos.
// @Tags auth // @Tags auth
// @Produce json // @Produce json
// @Success 200 {boolean} true "Sign-out success" // @Success 200 {boolean} true "Sign-out success"
// @Router /api/v1/auth/signout [POST] // @Router /api/v1/auth/signout [POST]
func (*APIV1Service) signOut(c echo.Context) error { func (*APIV1Service) SignOut(c echo.Context) error {
RemoveTokensAndCookies(c) RemoveTokensAndCookies(c)
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
} }
// signUp godoc // SignUp godoc
// //
// @Summary Sign-up to memos. // @Summary Sign-up to memos.
// @Tags auth // @Tags auth
@ -231,7 +231,7 @@ func (*APIV1Service) signOut(c echo.Context) error {
// @Failure 404 {object} nil "Not found" // @Failure 404 {object} nil "Not found"
// @Failure 500 {object} nil "Failed to find system setting | Failed to unmarshal system setting allow signup | Failed to generate password hash | Failed to create user | Failed to generate tokens | Failed to create activity" // @Failure 500 {object} nil "Failed to find system setting | Failed to unmarshal system setting allow signup | Failed to generate password hash | Failed to create user | Failed to generate tokens | Failed to create activity"
// @Router /api/v1/auth/signup [POST] // @Router /api/v1/auth/signup [POST]
func (s *APIV1Service) signUp(c echo.Context) error { func (s *APIV1Service) SignUp(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
signup := &SignUp{} signup := &SignUp{}
if err := json.NewDecoder(c.Request().Body).Decode(signup); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(signup); err != nil {

@ -1,6 +1,6 @@
// Code generated by swaggo/swag. DO NOT EDIT. // Code generated by swaggo/swag. DO NOT EDIT.
package api package v1
import "github.com/swaggo/swag" import "github.com/swaggo/swag"
@ -23,6 +23,50 @@ const docTemplate = `{
"host": "{{.Host}}", "host": "{{.Host}}",
"basePath": "{{.BasePath}}", "basePath": "{{.BasePath}}",
"paths": { "paths": {
"/api/v1/GetSystemStatus": {
"get": {
"produces": [
"application/json"
],
"tags": [
"system"
],
"summary": "Get system GetSystemStatus",
"responses": {
"200": {
"description": "System GetSystemStatus",
"schema": {
"$ref": "#/definitions/v1.SystemStatus"
}
},
"401": {
"description": "Missing user in session | Unauthorized"
},
"500": {
"description": "Failed to find host user | Failed to find system setting list | Failed to unmarshal system setting customized profile value"
}
}
}
},
"/api/v1/PingSystem": {
"get": {
"produces": [
"application/json"
],
"tags": [
"system"
],
"summary": "Ping the system",
"responses": {
"200": {
"description": "System profile",
"schema": {
"$ref": "#/definitions/profile.Profile"
}
}
}
}
},
"/api/v1/auth/signin": { "/api/v1/auth/signin": {
"post": { "post": {
"consumes": [ "consumes": [
@ -1108,25 +1152,6 @@ const docTemplate = `{
} }
} }
}, },
"/api/v1/ping": {
"get": {
"produces": [
"application/json"
],
"tags": [
"system"
],
"summary": "Ping the system",
"responses": {
"200": {
"description": "System profile",
"schema": {
"$ref": "#/definitions/profile.Profile"
}
}
}
}
},
"/api/v1/resource": { "/api/v1/resource": {
"get": { "get": {
"security": [ "security": [
@ -1361,31 +1386,6 @@ const docTemplate = `{
} }
} }
}, },
"/api/v1/status": {
"get": {
"produces": [
"application/json"
],
"tags": [
"system"
],
"summary": "Get system status",
"responses": {
"200": {
"description": "System status",
"schema": {
"$ref": "#/definitions/v1.SystemStatus"
}
},
"401": {
"description": "Missing user in session | Unauthorized"
},
"500": {
"description": "Failed to find host user | Failed to find system setting list | Failed to unmarshal system setting customized profile value"
}
}
}
},
"/api/v1/storage": { "/api/v1/storage": {
"get": { "get": {
"security": [ "security": [
@ -1555,6 +1555,36 @@ const docTemplate = `{
} }
} }
}, },
"/api/v1/system/ExecVacuum": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"produces": [
"application/json"
],
"tags": [
"system"
],
"summary": "Vacuum the database",
"responses": {
"200": {
"description": "Database vacuumed",
"schema": {
"type": "boolean"
}
},
"401": {
"description": "Missing user in session | Unauthorized"
},
"500": {
"description": "Failed to find user | Failed to ExecVacuum database"
}
}
}
},
"/api/v1/system/setting": { "/api/v1/system/setting": {
"get": { "get": {
"security": [ "security": [
@ -1636,36 +1666,6 @@ const docTemplate = `{
} }
} }
}, },
"/api/v1/system/vacuum": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"produces": [
"application/json"
],
"tags": [
"system"
],
"summary": "Vacuum the database",
"responses": {
"200": {
"description": "Database vacuumed",
"schema": {
"type": "boolean"
}
},
"401": {
"description": "Missing user in session | Unauthorized"
},
"500": {
"description": "Failed to find user | Failed to vacuum database"
}
}
}
},
"/api/v1/tag": { "/api/v1/tag": {
"get": { "get": {
"security": [ "security": [
@ -1972,7 +1972,7 @@ const docTemplate = `{
"tags": [ "tags": [
"user-setting" "user-setting"
], ],
"summary": "Create user setting", "summary": "Upsert user setting",
"parameters": [ "parameters": [
{ {
"description": "Request object.", "description": "Request object.",
@ -2144,19 +2144,19 @@ const docTemplate = `{
} }
} }
}, },
"/o/get/httpmeta": { "/o/get/GetImage": {
"get": { "get": {
"produces": [ "produces": [
"application/json" "GetImage/*"
], ],
"tags": [ "tags": [
"get" "get"
], ],
"summary": "Get website metadata", "summary": "Get GetImage from URL",
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"description": "Website URL", "description": "Image url",
"name": "url", "name": "url",
"in": "query", "in": "query",
"required": true "required": true
@ -2164,33 +2164,30 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"200": { "200": {
"description": "Extracted metadata", "description": "Image"
"schema": {
"$ref": "#/definitions/getter.HTMLMeta"
}
}, },
"400": { "400": {
"description": "Missing website url | Wrong url" "description": "Missing GetImage url | Wrong url | Failed to get GetImage url: %s"
}, },
"406": { "500": {
"description": "Failed to get website meta with url: %s" "description": "Failed to write GetImage blob"
} }
} }
} }
}, },
"/o/get/image": { "/o/get/GetWebsiteMetadata": {
"get": { "get": {
"produces": [ "produces": [
"image/*" "application/json"
], ],
"tags": [ "tags": [
"get" "get"
], ],
"summary": "Get image from URL", "summary": "Get website metadata",
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"description": "Image url", "description": "Website URL",
"name": "url", "name": "url",
"in": "query", "in": "query",
"required": true "required": true
@ -2198,13 +2195,16 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"200": { "200": {
"description": "Image" "description": "Extracted metadata",
"schema": {
"$ref": "#/definitions/getter.HTMLMeta"
}
}, },
"400": { "400": {
"description": "Missing image url | Wrong url | Failed to get image url: %s" "description": "Missing website url | Wrong url"
}, },
"500": { "406": {
"description": "Failed to write image blob" "description": "Failed to get website meta with url: %s"
} }
} }
} }

@ -11,13 +11,13 @@ import (
func (*APIV1Service) registerGetterPublicRoutes(g *echo.Group) { func (*APIV1Service) registerGetterPublicRoutes(g *echo.Group) {
// GET /get/httpmeta?url={url} - Get website meta. // GET /get/httpmeta?url={url} - Get website meta.
g.GET("/get/httpmeta", httpmeta) g.GET("/get/httpmeta", GetWebsiteMetadata)
// GET /get/image?url={url} - Get image. // GET /get/image?url={url} - Get image.
g.GET("/get/image", image) g.GET("/get/image", GetImage)
} }
// httpmeta godoc // GetWebsiteMetadata godoc
// //
// @Summary Get website metadata // @Summary Get website metadata
// @Tags get // @Tags get
@ -26,8 +26,8 @@ func (*APIV1Service) registerGetterPublicRoutes(g *echo.Group) {
// @Success 200 {object} getter.HTMLMeta "Extracted metadata" // @Success 200 {object} getter.HTMLMeta "Extracted metadata"
// @Failure 400 {object} nil "Missing website url | Wrong url" // @Failure 400 {object} nil "Missing website url | Wrong url"
// @Failure 406 {object} nil "Failed to get website meta with url: %s" // @Failure 406 {object} nil "Failed to get website meta with url: %s"
// @Router /o/get/httpmeta [GET] // @Router /o/get/GetWebsiteMetadata [GET]
func httpmeta(c echo.Context) error { func GetWebsiteMetadata(c echo.Context) error {
urlStr := c.QueryParam("url") urlStr := c.QueryParam("url")
if urlStr == "" { if urlStr == "" {
return echo.NewHTTPError(http.StatusBadRequest, "Missing website url") return echo.NewHTTPError(http.StatusBadRequest, "Missing website url")
@ -43,17 +43,17 @@ func httpmeta(c echo.Context) error {
return c.JSON(http.StatusOK, htmlMeta) return c.JSON(http.StatusOK, htmlMeta)
} }
// image godoc // GetImage godoc
// //
// @Summary Get image from URL // @Summary Get GetImage from URL
// @Tags get // @Tags get
// @Produce image/* // @Produce GetImage/*
// @Param url query string true "Image url" // @Param url query string true "Image url"
// @Success 200 {object} nil "Image" // @Success 200 {object} nil "Image"
// @Failure 400 {object} nil "Missing image url | Wrong url | Failed to get image url: %s" // @Failure 400 {object} nil "Missing GetImage url | Wrong url | Failed to get GetImage url: %s"
// @Failure 500 {object} nil "Failed to write image blob" // @Failure 500 {object} nil "Failed to write GetImage blob"
// @Router /o/get/image [GET] // @Router /o/get/GetImage [GET]
func image(c echo.Context) error { func GetImage(c echo.Context) error {
urlStr := c.QueryParam("url") urlStr := c.QueryParam("url")
if urlStr == "" { if urlStr == "" {
return echo.NewHTTPError(http.StatusBadRequest, "Missing image url") return echo.NewHTTPError(http.StatusBadRequest, "Missing image url")

@ -65,15 +65,14 @@ type UpdateIdentityProviderRequest struct {
} }
func (s *APIV1Service) registerIdentityProviderRoutes(g *echo.Group) { func (s *APIV1Service) registerIdentityProviderRoutes(g *echo.Group) {
g.GET("/idp", s.getIdentityProviderList) g.GET("/idp", s.GetIdentityProviderList)
g.POST("/idp", s.createIdentityProvider) g.POST("/idp", s.CreateIdentityProvider)
g.GET("/idp/:idpId", s.GetIdentityProvider)
g.GET("/idp/:idpId", s.getIdentityProvider) g.PATCH("/idp/:idpId", s.UpdateIdentityProvider)
g.DELETE("/idp/:idpId", s.deleteIdentityProvider) g.DELETE("/idp/:idpId", s.DeleteIdentityProvider)
g.PATCH("/idp/:idpId", s.updateIdentityProvider)
} }
// getIdentityProviderList godoc // GetIdentityProviderList godoc
// //
// @Summary Get a list of identity providers // @Summary Get a list of identity providers
// @Description *clientSecret is only available for host user // @Description *clientSecret is only available for host user
@ -82,7 +81,7 @@ func (s *APIV1Service) registerIdentityProviderRoutes(g *echo.Group) {
// @Success 200 {object} []IdentityProvider "List of available identity providers" // @Success 200 {object} []IdentityProvider "List of available identity providers"
// @Failure 500 {object} nil "Failed to find identity provider list | Failed to find user" // @Failure 500 {object} nil "Failed to find identity provider list | Failed to find user"
// @Router /api/v1/idp [GET] // @Router /api/v1/idp [GET]
func (s *APIV1Service) getIdentityProviderList(c echo.Context) error { func (s *APIV1Service) GetIdentityProviderList(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
list, err := s.Store.ListIdentityProviders(ctx, &store.FindIdentityProvider{}) list, err := s.Store.ListIdentityProviders(ctx, &store.FindIdentityProvider{})
if err != nil { if err != nil {
@ -115,7 +114,7 @@ func (s *APIV1Service) getIdentityProviderList(c echo.Context) error {
return c.JSON(http.StatusOK, identityProviderList) return c.JSON(http.StatusOK, identityProviderList)
} }
// createIdentityProvider godoc // CreateIdentityProvider godoc
// //
// @Summary Create Identity Provider // @Summary Create Identity Provider
// @Tags idp // @Tags idp
@ -128,7 +127,7 @@ func (s *APIV1Service) getIdentityProviderList(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find user | Failed to create identity provider" // @Failure 500 {object} nil "Failed to find user | Failed to create identity provider"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/idp [POST] // @Router /api/v1/idp [POST]
func (s *APIV1Service) createIdentityProvider(c echo.Context) error { func (s *APIV1Service) CreateIdentityProvider(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -162,7 +161,7 @@ func (s *APIV1Service) createIdentityProvider(c echo.Context) error {
return c.JSON(http.StatusOK, convertIdentityProviderFromStore(identityProvider)) return c.JSON(http.StatusOK, convertIdentityProviderFromStore(identityProvider))
} }
// getIdentityProvider godoc // GetIdentityProvider godoc
// //
// @Summary Get an identity provider by ID // @Summary Get an identity provider by ID
// @Tags idp // @Tags idp
@ -176,7 +175,7 @@ func (s *APIV1Service) createIdentityProvider(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find identity provider list | Failed to find user" // @Failure 500 {object} nil "Failed to find identity provider list | Failed to find user"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/idp/{idpId} [GET] // @Router /api/v1/idp/{idpId} [GET]
func (s *APIV1Service) getIdentityProvider(c echo.Context) error { func (s *APIV1Service) GetIdentityProvider(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -210,7 +209,7 @@ func (s *APIV1Service) getIdentityProvider(c echo.Context) error {
return c.JSON(http.StatusOK, convertIdentityProviderFromStore(identityProvider)) return c.JSON(http.StatusOK, convertIdentityProviderFromStore(identityProvider))
} }
// deleteIdentityProvider godoc // DeleteIdentityProvider godoc
// //
// @Summary Delete an identity provider by ID // @Summary Delete an identity provider by ID
// @Tags idp // @Tags idp
@ -223,7 +222,7 @@ func (s *APIV1Service) getIdentityProvider(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find user | Failed to patch identity provider" // @Failure 500 {object} nil "Failed to find user | Failed to patch identity provider"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/idp/{idpId} [DELETE] // @Router /api/v1/idp/{idpId} [DELETE]
func (s *APIV1Service) deleteIdentityProvider(c echo.Context) error { func (s *APIV1Service) DeleteIdentityProvider(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -251,7 +250,7 @@ func (s *APIV1Service) deleteIdentityProvider(c echo.Context) error {
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
} }
// updateIdentityProvider godoc // UpdateIdentityProvider godoc
// //
// @Summary Update an identity provider by ID // @Summary Update an identity provider by ID
// @Tags idp // @Tags idp
@ -265,7 +264,7 @@ func (s *APIV1Service) deleteIdentityProvider(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find user | Failed to patch identity provider" // @Failure 500 {object} nil "Failed to find user | Failed to patch identity provider"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/idp/{idpId} [PATCH] // @Router /api/v1/idp/{idpId} [PATCH]
func (s *APIV1Service) updateIdentityProvider(c echo.Context) error { func (s *APIV1Service) UpdateIdentityProvider(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {

@ -113,17 +113,16 @@ type FindMemoRequest struct {
const maxContentLength = 1 << 30 const maxContentLength = 1 << 30
func (s *APIV1Service) registerMemoRoutes(g *echo.Group) { func (s *APIV1Service) registerMemoRoutes(g *echo.Group) {
g.GET("/memo", s.getMemoList) g.GET("/memo", s.GetMemoList)
g.POST("/memo", s.createMemo) g.POST("/memo", s.CreateMemo)
g.GET("/memo/all", s.getAllMemos) g.GET("/memo/all", s.GetAllMemos)
g.GET("/memo/stats", s.getMemoStats) g.GET("/memo/stats", s.GetMemoStats)
g.GET("/memo/:memoId", s.GetMemo)
g.GET("/memo/:memoId", s.getMemo) g.PATCH("/memo/:memoId", s.UpdateMemo)
g.DELETE("/memo/:memoId", s.deleteMemo) g.DELETE("/memo/:memoId", s.DeleteMemo)
g.PATCH("/memo/:memoId", s.updateMemo)
} }
// getMemoList godoc // GetMemoList godoc
// //
// @Summary Get a list of memos matching optional filters // @Summary Get a list of memos matching optional filters
// @Tags memo // @Tags memo
@ -141,7 +140,7 @@ func (s *APIV1Service) registerMemoRoutes(g *echo.Group) {
// @Failure 500 {object} nil "Failed to get memo display with updated ts setting value | Failed to fetch memo list | Failed to compose memo response" // @Failure 500 {object} nil "Failed to get memo display with updated ts setting value | Failed to fetch memo list | Failed to compose memo response"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/memo [GET] // @Router /api/v1/memo [GET]
func (s *APIV1Service) getMemoList(c echo.Context) error { func (s *APIV1Service) GetMemoList(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
findMemoMessage := &store.FindMemo{} findMemoMessage := &store.FindMemo{}
if userID, err := util.ConvertStringToInt32(c.QueryParam("creatorId")); err == nil { if userID, err := util.ConvertStringToInt32(c.QueryParam("creatorId")); err == nil {
@ -225,7 +224,7 @@ func (s *APIV1Service) getMemoList(c echo.Context) error {
return c.JSON(http.StatusOK, memoResponseList) return c.JSON(http.StatusOK, memoResponseList)
} }
// createMemo godoc // CreateMemo godoc
// //
// @Summary Create a memo // @Summary Create a memo
// @Description Visibility can be PUBLIC, PROTECTED or PRIVATE // @Description Visibility can be PUBLIC, PROTECTED or PRIVATE
@ -244,7 +243,7 @@ func (s *APIV1Service) getMemoList(c echo.Context) error {
// //
// NOTES: // NOTES:
// - It's currently possible to create phantom resources and relations. Phantom relations will trigger backend 404's when fetching memo. // - It's currently possible to create phantom resources and relations. Phantom relations will trigger backend 404's when fetching memo.
func (s *APIV1Service) createMemo(c echo.Context) error { func (s *APIV1Service) CreateMemo(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -355,7 +354,7 @@ func (s *APIV1Service) createMemo(c echo.Context) error {
return c.JSON(http.StatusOK, memoResponse) return c.JSON(http.StatusOK, memoResponse)
} }
// getAllMemos godoc // GetAllMemos godoc
// //
// @Summary Get a list of public memos matching optional filters // @Summary Get a list of public memos matching optional filters
// @Description This should also list protected memos if the user is logged in // @Description This should also list protected memos if the user is logged in
@ -371,7 +370,7 @@ func (s *APIV1Service) createMemo(c echo.Context) error {
// //
// NOTES: // NOTES:
// - creatorUsername is listed at ./web/src/helpers/api.ts:82, but it's not present here // - creatorUsername is listed at ./web/src/helpers/api.ts:82, but it's not present here
func (s *APIV1Service) getAllMemos(c echo.Context) error { func (s *APIV1Service) GetAllMemos(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
findMemoMessage := &store.FindMemo{} findMemoMessage := &store.FindMemo{}
_, ok := c.Get(auth.UserIDContextKey).(int32) _, ok := c.Get(auth.UserIDContextKey).(int32)
@ -415,7 +414,7 @@ func (s *APIV1Service) getAllMemos(c echo.Context) error {
return c.JSON(http.StatusOK, memoResponseList) return c.JSON(http.StatusOK, memoResponseList)
} }
// getMemoStats godoc // GetMemoStats godoc
// //
// @Summary Get memo stats by creator ID or username // @Summary Get memo stats by creator ID or username
// @Description Used to generate the heatmap // @Description Used to generate the heatmap
@ -427,7 +426,7 @@ func (s *APIV1Service) getAllMemos(c echo.Context) error {
// @Failure 400 {object} nil "Missing user id to find memo" // @Failure 400 {object} nil "Missing user id to find memo"
// @Failure 500 {object} nil "Failed to get memo display with updated ts setting value | Failed to find memo list | Failed to compose memo response" // @Failure 500 {object} nil "Failed to get memo display with updated ts setting value | Failed to find memo list | Failed to compose memo response"
// @Router /api/v1/memo/stats [GET] // @Router /api/v1/memo/stats [GET]
func (s *APIV1Service) getMemoStats(c echo.Context) error { func (s *APIV1Service) GetMemoStats(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
normalStatus := store.Normal normalStatus := store.Normal
findMemoMessage := &store.FindMemo{ findMemoMessage := &store.FindMemo{
@ -487,7 +486,7 @@ func (s *APIV1Service) getMemoStats(c echo.Context) error {
return c.JSON(http.StatusOK, displayTsList) return c.JSON(http.StatusOK, displayTsList)
} }
// getMemo godoc // GetMemo godoc
// //
// @Summary Get memo by ID // @Summary Get memo by ID
// @Tags memo // @Tags memo
@ -500,7 +499,7 @@ func (s *APIV1Service) getMemoStats(c echo.Context) error {
// @Failure 404 {object} nil "Memo not found: %d" // @Failure 404 {object} nil "Memo not found: %d"
// @Failure 500 {object} nil "Failed to find memo by ID: %v | Failed to compose memo response" // @Failure 500 {object} nil "Failed to find memo by ID: %v | Failed to compose memo response"
// @Router /api/v1/memo/{memoId} [GET] // @Router /api/v1/memo/{memoId} [GET]
func (s *APIV1Service) getMemo(c echo.Context) error { func (s *APIV1Service) GetMemo(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
memoID, err := util.ConvertStringToInt32(c.Param("memoId")) memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
if err != nil { if err != nil {
@ -534,7 +533,7 @@ func (s *APIV1Service) getMemo(c echo.Context) error {
return c.JSON(http.StatusOK, memoResponse) return c.JSON(http.StatusOK, memoResponse)
} }
// deleteMemo godoc // DeleteMemo godoc
// //
// @Summary Delete memo by ID // @Summary Delete memo by ID
// @Tags memo // @Tags memo
@ -547,7 +546,7 @@ func (s *APIV1Service) getMemo(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find memo | Failed to delete memo ID: %v" // @Failure 500 {object} nil "Failed to find memo | Failed to delete memo ID: %v"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/memo/{memoId} [DELETE] // @Router /api/v1/memo/{memoId} [DELETE]
func (s *APIV1Service) deleteMemo(c echo.Context) error { func (s *APIV1Service) DeleteMemo(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -579,7 +578,7 @@ func (s *APIV1Service) deleteMemo(c echo.Context) error {
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
} }
// updateMemo godoc // UpdateMemo godoc
// //
// @Summary Update a memo // @Summary Update a memo
// @Description Visibility can be PUBLIC, PROTECTED or PRIVATE // @Description Visibility can be PUBLIC, PROTECTED or PRIVATE
@ -600,7 +599,7 @@ func (s *APIV1Service) deleteMemo(c echo.Context) error {
// NOTES: // NOTES:
// - It's currently possible to create phantom resources and relations. Phantom relations will trigger backend 404's when fetching memo. // - It's currently possible to create phantom resources and relations. Phantom relations will trigger backend 404's when fetching memo.
// - Passing 0 to createdTs and updatedTs will set them to 0 in the database, which is probably unwanted. // - Passing 0 to createdTs and updatedTs will set them to 0 in the database, which is probably unwanted.
func (s *APIV1Service) updateMemo(c echo.Context) error { func (s *APIV1Service) UpdateMemo(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {

@ -22,10 +22,10 @@ type UpsertMemoOrganizerRequest struct {
} }
func (s *APIV1Service) registerMemoOrganizerRoutes(g *echo.Group) { func (s *APIV1Service) registerMemoOrganizerRoutes(g *echo.Group) {
g.POST("/memo/:memoId/organizer", s.organizeMemo) g.POST("/memo/:memoId/organizer", s.CreateMemoOrganizer)
} }
// organizeMemo godoc // CreateMemoOrganizer godoc
// //
// @Summary Organize memo (pin/unpin) // @Summary Organize memo (pin/unpin)
// @Tags memo-organizer // @Tags memo-organizer
@ -40,7 +40,7 @@ func (s *APIV1Service) registerMemoOrganizerRoutes(g *echo.Group) {
// @Failure 500 {object} nil "Failed to find memo | Failed to upsert memo organizer | Failed to find memo by ID: %v | Failed to compose memo response" // @Failure 500 {object} nil "Failed to find memo | Failed to upsert memo organizer | Failed to find memo by ID: %v | Failed to compose memo response"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/memo/{memoId}/organizer [POST] // @Router /api/v1/memo/{memoId}/organizer [POST]
func (s *APIV1Service) organizeMemo(c echo.Context) error { func (s *APIV1Service) CreateMemoOrganizer(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
memoID, err := util.ConvertStringToInt32(c.Param("memoId")) memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
if err != nil { if err != nil {

@ -29,12 +29,12 @@ type UpsertMemoRelationRequest struct {
} }
func (s *APIV1Service) registerMemoRelationRoutes(g *echo.Group) { func (s *APIV1Service) registerMemoRelationRoutes(g *echo.Group) {
g.GET("/memo/:memoId/relation", s.getMemoRelationList) g.GET("/memo/:memoId/relation", s.GetMemoRelationList)
g.POST("/memo/:memoId/relation", s.createMemoRelation) g.POST("/memo/:memoId/relation", s.CreateMemoRelation)
g.DELETE("/memo/:memoId/relation/:relatedMemoId/type/:relationType", s.deleteMemoRelation) g.DELETE("/memo/:memoId/relation/:relatedMemoId/type/:relationType", s.DeleteMemoRelation)
} }
// getMemoRelationList godoc // GetMemoRelationList godoc
// //
// @Summary Get a list of Memo Relations // @Summary Get a list of Memo Relations
// @Tags memo-relation // @Tags memo-relation
@ -45,7 +45,7 @@ func (s *APIV1Service) registerMemoRelationRoutes(g *echo.Group) {
// @Failure 400 {object} nil "ID is not a number: %s" // @Failure 400 {object} nil "ID is not a number: %s"
// @Failure 500 {object} nil "Failed to list memo relations" // @Failure 500 {object} nil "Failed to list memo relations"
// @Router /api/v1/memo/{memoId}/relation [GET] // @Router /api/v1/memo/{memoId}/relation [GET]
func (s *APIV1Service) getMemoRelationList(c echo.Context) error { func (s *APIV1Service) GetMemoRelationList(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
memoID, err := util.ConvertStringToInt32(c.Param("memoId")) memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
if err != nil { if err != nil {
@ -61,7 +61,7 @@ func (s *APIV1Service) getMemoRelationList(c echo.Context) error {
return c.JSON(http.StatusOK, memoRelationList) return c.JSON(http.StatusOK, memoRelationList)
} }
// createMemoRelation godoc // CreateMemoRelation godoc
// //
// @Summary Create Memo Relation // @Summary Create Memo Relation
// @Description Create a relation between two memos // @Description Create a relation between two memos
@ -79,7 +79,7 @@ func (s *APIV1Service) getMemoRelationList(c echo.Context) error {
// - Currently not secured // - Currently not secured
// - It's possible to create relations to memos that doesn't exist, which will trigger 404 errors when the frontend tries to load them. // - It's possible to create relations to memos that doesn't exist, which will trigger 404 errors when the frontend tries to load them.
// - It's possible to create multiple relations, though the interface only shows first. // - It's possible to create multiple relations, though the interface only shows first.
func (s *APIV1Service) createMemoRelation(c echo.Context) error { func (s *APIV1Service) CreateMemoRelation(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
memoID, err := util.ConvertStringToInt32(c.Param("memoId")) memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
if err != nil { if err != nil {
@ -102,7 +102,7 @@ func (s *APIV1Service) createMemoRelation(c echo.Context) error {
return c.JSON(http.StatusOK, memoRelation) return c.JSON(http.StatusOK, memoRelation)
} }
// deleteMemoRelation godoc // DeleteMemoRelation godoc
// //
// @Summary Delete a Memo Relation // @Summary Delete a Memo Relation
// @Description Removes a relation between two memos // @Description Removes a relation between two memos
@ -120,7 +120,7 @@ func (s *APIV1Service) createMemoRelation(c echo.Context) error {
// NOTES: // NOTES:
// - Currently not secured. // - Currently not secured.
// - Will always return true, even if the relation doesn't exist. // - Will always return true, even if the relation doesn't exist.
func (s *APIV1Service) deleteMemoRelation(c echo.Context) error { func (s *APIV1Service) DeleteMemoRelation(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
memoID, err := util.ConvertStringToInt32(c.Param("memoId")) memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
if err != nil { if err != nil {

@ -35,12 +35,12 @@ type MemoResourceDelete struct {
} }
func (s *APIV1Service) registerMemoResourceRoutes(g *echo.Group) { func (s *APIV1Service) registerMemoResourceRoutes(g *echo.Group) {
g.GET("/memo/:memoId/resource", s.getMemoResourceList) g.GET("/memo/:memoId/resource", s.GetMemoResourceList)
g.POST("/memo/:memoId/resource", s.bindMemoResource) g.POST("/memo/:memoId/resource", s.BindMemoResource)
g.DELETE("/memo/:memoId/resource/:resourceId", s.unbindMemoResource) g.DELETE("/memo/:memoId/resource/:resourceId", s.UnbindMemoResource)
} }
// getMemoResourceList godoc // GetMemoResourceList godoc
// //
// @Summary Get resource list of a memo // @Summary Get resource list of a memo
// @Tags memo-resource // @Tags memo-resource
@ -51,7 +51,7 @@ func (s *APIV1Service) registerMemoResourceRoutes(g *echo.Group) {
// @Failure 400 {object} nil "ID is not a number: %s" // @Failure 400 {object} nil "ID is not a number: %s"
// @Failure 500 {object} nil "Failed to fetch resource list" // @Failure 500 {object} nil "Failed to fetch resource list"
// @Router /api/v1/memo/{memoId}/resource [GET] // @Router /api/v1/memo/{memoId}/resource [GET]
func (s *APIV1Service) getMemoResourceList(c echo.Context) error { func (s *APIV1Service) GetMemoResourceList(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
memoID, err := util.ConvertStringToInt32(c.Param("memoId")) memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
if err != nil { if err != nil {
@ -71,7 +71,7 @@ func (s *APIV1Service) getMemoResourceList(c echo.Context) error {
return c.JSON(http.StatusOK, resourceList) return c.JSON(http.StatusOK, resourceList)
} }
// bindMemoResource godoc // BindMemoResource godoc
// //
// @Summary Bind resource to memo // @Summary Bind resource to memo
// @Tags memo-resource // @Tags memo-resource
@ -88,7 +88,7 @@ func (s *APIV1Service) getMemoResourceList(c echo.Context) error {
// //
// NOTES: // NOTES:
// - Passing 0 to updatedTs will set it to 0 in the database, which is probably unwanted. // - Passing 0 to updatedTs will set it to 0 in the database, which is probably unwanted.
func (s *APIV1Service) bindMemoResource(c echo.Context) error { func (s *APIV1Service) BindMemoResource(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
memoID, err := util.ConvertStringToInt32(c.Param("memoId")) memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
if err != nil { if err != nil {
@ -129,7 +129,7 @@ func (s *APIV1Service) bindMemoResource(c echo.Context) error {
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
} }
// unbindMemoResource godoc // UnbindMemoResource godoc
// //
// @Summary Unbind resource from memo // @Summary Unbind resource from memo
// @Tags memo-resource // @Tags memo-resource
@ -143,7 +143,7 @@ func (s *APIV1Service) bindMemoResource(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find memo | Failed to fetch resource list" // @Failure 500 {object} nil "Failed to find memo | Failed to fetch resource list"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/memo/{memoId}/resource/{resourceId} [DELETE] // @Router /api/v1/memo/{memoId}/resource/{resourceId} [DELETE]
func (s *APIV1Service) unbindMemoResource(c echo.Context) error { func (s *APIV1Service) UnbindMemoResource(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {

@ -81,11 +81,11 @@ const (
var fileKeyPattern = regexp.MustCompile(`\{[a-z]{1,9}\}`) var fileKeyPattern = regexp.MustCompile(`\{[a-z]{1,9}\}`)
func (s *APIV1Service) registerResourceRoutes(g *echo.Group) { func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
g.GET("/resource", s.getResourceList) g.GET("/resource", s.GetResourceList)
g.POST("/resource", s.createResource) g.POST("/resource", s.CreateResource)
g.POST("/resource/blob", s.uploadResource) g.POST("/resource/blob", s.UploadResource)
g.DELETE("/resource/:resourceId", s.deleteResource) g.PATCH("/resource/:resourceId", s.UpdateResource)
g.PATCH("/resource/:resourceId", s.updateResource) g.DELETE("/resource/:resourceId", s.DeleteResource)
} }
func (s *APIV1Service) registerResourcePublicRoutes(g *echo.Group) { func (s *APIV1Service) registerResourcePublicRoutes(g *echo.Group) {
@ -93,7 +93,7 @@ func (s *APIV1Service) registerResourcePublicRoutes(g *echo.Group) {
g.GET("/r/:resourceId/*", s.streamResource) g.GET("/r/:resourceId/*", s.streamResource)
} }
// getResourceList godoc // GetResourceList godoc
// //
// @Summary Get a list of resources // @Summary Get a list of resources
// @Tags resource // @Tags resource
@ -105,7 +105,7 @@ func (s *APIV1Service) registerResourcePublicRoutes(g *echo.Group) {
// @Failure 500 {object} nil "Failed to fetch resource list" // @Failure 500 {object} nil "Failed to fetch resource list"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/resource [GET] // @Router /api/v1/resource [GET]
func (s *APIV1Service) getResourceList(c echo.Context) error { func (s *APIV1Service) GetResourceList(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -132,7 +132,7 @@ func (s *APIV1Service) getResourceList(c echo.Context) error {
return c.JSON(http.StatusOK, resourceMessageList) return c.JSON(http.StatusOK, resourceMessageList)
} }
// createResource godoc // CreateResource godoc
// //
// @Summary Create resource // @Summary Create resource
// @Tags resource // @Tags resource
@ -145,7 +145,7 @@ func (s *APIV1Service) getResourceList(c echo.Context) error {
// @Failure 500 {object} nil "Failed to save resource | Failed to create resource | Failed to create activity" // @Failure 500 {object} nil "Failed to save resource | Failed to create resource | Failed to create activity"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/resource [POST] // @Router /api/v1/resource [POST]
func (s *APIV1Service) createResource(c echo.Context) error { func (s *APIV1Service) CreateResource(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -219,7 +219,7 @@ func (s *APIV1Service) createResource(c echo.Context) error {
return c.JSON(http.StatusOK, convertResourceFromStore(resource)) return c.JSON(http.StatusOK, convertResourceFromStore(resource))
} }
// uploadResource godoc // UploadResource godoc
// //
// @Summary Upload resource // @Summary Upload resource
// @Tags resource // @Tags resource
@ -232,7 +232,7 @@ func (s *APIV1Service) createResource(c echo.Context) error {
// @Failure 500 {object} nil "Failed to get uploading file | Failed to open file | Failed to save resource | Failed to create resource | Failed to create activity" // @Failure 500 {object} nil "Failed to get uploading file | Failed to open file | Failed to save resource | Failed to create resource | Failed to create activity"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/resource/blob [POST] // @Router /api/v1/resource/blob [POST]
func (s *APIV1Service) uploadResource(c echo.Context) error { func (s *APIV1Service) UploadResource(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -292,7 +292,7 @@ func (s *APIV1Service) uploadResource(c echo.Context) error {
return c.JSON(http.StatusOK, convertResourceFromStore(resource)) return c.JSON(http.StatusOK, convertResourceFromStore(resource))
} }
// deleteResource godoc // DeleteResource godoc
// //
// @Summary Delete a resource // @Summary Delete a resource
// @Tags resource // @Tags resource
@ -305,7 +305,7 @@ func (s *APIV1Service) uploadResource(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find resource | Failed to delete resource" // @Failure 500 {object} nil "Failed to find resource | Failed to delete resource"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/resource/{resourceId} [DELETE] // @Router /api/v1/resource/{resourceId} [DELETE]
func (s *APIV1Service) deleteResource(c echo.Context) error { func (s *APIV1Service) DeleteResource(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -348,7 +348,7 @@ func (s *APIV1Service) deleteResource(c echo.Context) error {
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
} }
// updateResource godoc // UpdateResource godoc
// //
// @Summary Update a resource // @Summary Update a resource
// @Tags resource // @Tags resource
@ -362,7 +362,7 @@ func (s *APIV1Service) deleteResource(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find resource | Failed to patch resource" // @Failure 500 {object} nil "Failed to find resource | Failed to patch resource"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/resource/{resourceId} [PATCH] // @Router /api/v1/resource/{resourceId} [PATCH]
func (s *APIV1Service) updateResource(c echo.Context) error { func (s *APIV1Service) UpdateResource(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {

@ -21,11 +21,11 @@ const maxRSSItemCount = 100
const maxRSSItemTitleLength = 100 const maxRSSItemTitleLength = 100
func (s *APIV1Service) registerRSSRoutes(g *echo.Group) { func (s *APIV1Service) registerRSSRoutes(g *echo.Group) {
g.GET("/explore/rss.xml", s.getRSS) g.GET("/explore/rss.xml", s.GetExploreRSS)
g.GET("/u/:id/rss.xml", s.getUserRSS) g.GET("/u/:id/rss.xml", s.GetUserRSS)
} }
// getRSS godoc // GetExploreRSS godoc
// //
// @Summary Get RSS // @Summary Get RSS
// @Tags rss // @Tags rss
@ -33,7 +33,7 @@ func (s *APIV1Service) registerRSSRoutes(g *echo.Group) {
// @Success 200 {object} nil "RSS" // @Success 200 {object} nil "RSS"
// @Failure 500 {object} nil "Failed to get system customized profile | Failed to find memo list | Failed to generate rss" // @Failure 500 {object} nil "Failed to get system customized profile | Failed to find memo list | Failed to generate rss"
// @Router /explore/rss.xml [GET] // @Router /explore/rss.xml [GET]
func (s *APIV1Service) getRSS(c echo.Context) error { func (s *APIV1Service) GetExploreRSS(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
systemCustomizedProfile, err := s.getSystemCustomizedProfile(ctx) systemCustomizedProfile, err := s.getSystemCustomizedProfile(ctx)
if err != nil { if err != nil {
@ -59,7 +59,7 @@ func (s *APIV1Service) getRSS(c echo.Context) error {
return c.String(http.StatusOK, rss) return c.String(http.StatusOK, rss)
} }
// getUserRSS godoc // GetUserRSS godoc
// //
// @Summary Get RSS for a user // @Summary Get RSS for a user
// @Tags rss // @Tags rss
@ -69,7 +69,7 @@ func (s *APIV1Service) getRSS(c echo.Context) error {
// @Failure 400 {object} nil "User id is not a number" // @Failure 400 {object} nil "User id is not a number"
// @Failure 500 {object} nil "Failed to get system customized profile | Failed to find memo list | Failed to generate rss" // @Failure 500 {object} nil "Failed to get system customized profile | Failed to find memo list | Failed to generate rss"
// @Router /u/{id}/rss.xml [GET] // @Router /u/{id}/rss.xml [GET]
func (s *APIV1Service) getUserRSS(c echo.Context) error { func (s *APIV1Service) GetUserRSS(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
id, err := util.ConvertStringToInt32(c.Param("id")) id, err := util.ConvertStringToInt32(c.Param("id"))
if err != nil { if err != nil {

@ -63,13 +63,13 @@ type UpdateStorageRequest struct {
} }
func (s *APIV1Service) registerStorageRoutes(g *echo.Group) { func (s *APIV1Service) registerStorageRoutes(g *echo.Group) {
g.GET("/storage", s.getStorageList) g.GET("/storage", s.GetStorageList)
g.POST("/storage", s.createStorage) g.POST("/storage", s.CreateStorage)
g.DELETE("/storage/:storageId", s.deleteStorage) g.PATCH("/storage/:storageId", s.UpdateStorage)
g.PATCH("/storage/:storageId", s.updateStorage) g.DELETE("/storage/:storageId", s.DeleteStorage)
} }
// getStorageList godoc // GetStorageList godoc
// //
// @Summary Get a list of storages // @Summary Get a list of storages
// @Tags storage // @Tags storage
@ -79,7 +79,7 @@ func (s *APIV1Service) registerStorageRoutes(g *echo.Group) {
// @Failure 500 {object} nil "Failed to find user | Failed to convert storage" // @Failure 500 {object} nil "Failed to find user | Failed to convert storage"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/storage [GET] // @Router /api/v1/storage [GET]
func (s *APIV1Service) getStorageList(c echo.Context) error { func (s *APIV1Service) GetStorageList(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -113,7 +113,7 @@ func (s *APIV1Service) getStorageList(c echo.Context) error {
return c.JSON(http.StatusOK, storageList) return c.JSON(http.StatusOK, storageList)
} }
// createStorage godoc // CreateStorage godoc
// //
// @Summary Create storage // @Summary Create storage
// @Tags storage // @Tags storage
@ -126,7 +126,7 @@ func (s *APIV1Service) getStorageList(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find user | Failed to create storage | Failed to convert storage" // @Failure 500 {object} nil "Failed to find user | Failed to create storage | Failed to convert storage"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/storage [POST] // @Router /api/v1/storage [POST]
func (s *APIV1Service) createStorage(c echo.Context) error { func (s *APIV1Service) CreateStorage(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -172,7 +172,7 @@ func (s *APIV1Service) createStorage(c echo.Context) error {
return c.JSON(http.StatusOK, storageMessage) return c.JSON(http.StatusOK, storageMessage)
} }
// deleteStorage godoc // DeleteStorage godoc
// //
// @Summary Delete a storage // @Summary Delete a storage
// @Tags storage // @Tags storage
@ -187,7 +187,7 @@ func (s *APIV1Service) createStorage(c echo.Context) error {
// //
// NOTES: // NOTES:
// - error message "Storage service %d is using" probably should be "Storage service %d is in use". // - error message "Storage service %d is using" probably should be "Storage service %d is in use".
func (s *APIV1Service) deleteStorage(c echo.Context) error { func (s *APIV1Service) DeleteStorage(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -230,7 +230,7 @@ func (s *APIV1Service) deleteStorage(c echo.Context) error {
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
} }
// updateStorage godoc // UpdateStorage godoc
// //
// @Summary Update a storage // @Summary Update a storage
// @Tags storage // @Tags storage
@ -243,7 +243,7 @@ func (s *APIV1Service) deleteStorage(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find user | Failed to patch storage | Failed to convert storage" // @Failure 500 {object} nil "Failed to find user | Failed to patch storage | Failed to convert storage"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/storage/{storageId} [PATCH] // @Router /api/v1/storage/{storageId} [PATCH]
func (s *APIV1Service) updateStorage(c echo.Context) error { func (s *APIV1Service) UpdateStorage(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {

@ -748,6 +748,35 @@ info:
title: memos API title: memos API
version: "1.0" version: "1.0"
paths: paths:
/api/v1/GetSystemStatus:
get:
produces:
- application/json
responses:
"200":
description: System GetSystemStatus
schema:
$ref: '#/definitions/v1.SystemStatus'
"401":
description: Missing user in session | Unauthorized
"500":
description: Failed to find host user | Failed to find system setting list
| Failed to unmarshal system setting customized profile value
summary: Get system GetSystemStatus
tags:
- system
/api/v1/PingSystem:
get:
produces:
- application/json
responses:
"200":
description: System profile
schema:
$ref: '#/definitions/profile.Profile'
summary: Ping the system
tags:
- system
/api/v1/auth/signin: /api/v1/auth/signin:
post: post:
consumes: consumes:
@ -1480,18 +1509,6 @@ paths:
summary: Get memo stats by creator ID or username summary: Get memo stats by creator ID or username
tags: tags:
- memo - memo
/api/v1/ping:
get:
produces:
- application/json
responses:
"200":
description: System profile
schema:
$ref: '#/definitions/profile.Profile'
summary: Ping the system
tags:
- system
/api/v1/resource: /api/v1/resource:
get: get:
parameters: parameters:
@ -1643,23 +1660,6 @@ paths:
summary: Upload resource summary: Upload resource
tags: tags:
- resource - resource
/api/v1/status:
get:
produces:
- application/json
responses:
"200":
description: System status
schema:
$ref: '#/definitions/v1.SystemStatus'
"401":
description: Missing user in session | Unauthorized
"500":
description: Failed to find host user | Failed to find system setting list
| Failed to unmarshal system setting customized profile value
summary: Get system status
tags:
- system
/api/v1/storage: /api/v1/storage:
get: get:
produces: produces:
@ -1769,6 +1769,24 @@ paths:
summary: Update a storage summary: Update a storage
tags: tags:
- storage - storage
/api/v1/system/ExecVacuum:
post:
produces:
- application/json
responses:
"200":
description: Database vacuumed
schema:
type: boolean
"401":
description: Missing user in session | Unauthorized
"500":
description: Failed to find user | Failed to ExecVacuum database
security:
- ApiKeyAuth: []
summary: Vacuum the database
tags:
- system
/api/v1/system/setting: /api/v1/system/setting:
get: get:
produces: produces:
@ -1819,24 +1837,6 @@ paths:
summary: Create system setting summary: Create system setting
tags: tags:
- system-setting - system-setting
/api/v1/system/vacuum:
post:
produces:
- application/json
responses:
"200":
description: Database vacuumed
schema:
type: boolean
"401":
description: Missing user in session | Unauthorized
"500":
description: Failed to find user | Failed to vacuum database
security:
- ApiKeyAuth: []
summary: Vacuum the database
tags:
- system
/api/v1/tag: /api/v1/tag:
get: get:
produces: produces:
@ -2129,7 +2129,7 @@ paths:
description: Failed to upsert user setting description: Failed to upsert user setting
security: security:
- ApiKeyAuth: [] - ApiKeyAuth: []
summary: Create user setting summary: Upsert user setting
tags: tags:
- user-setting - user-setting
/explore/rss.xml: /explore/rss.xml:
@ -2145,46 +2145,47 @@ paths:
summary: Get RSS summary: Get RSS
tags: tags:
- rss - rss
/o/get/httpmeta: /o/get/GetImage:
get: get:
parameters: parameters:
- description: Website URL - description: Image url
in: query in: query
name: url name: url
required: true required: true
type: string type: string
produces: produces:
- application/json - GetImage/*
responses: responses:
"200": "200":
description: Extracted metadata description: Image
schema:
$ref: '#/definitions/getter.HTMLMeta'
"400": "400":
description: Missing website url | Wrong url description: 'Missing GetImage url | Wrong url | Failed to get GetImage
"406": url: %s'
description: 'Failed to get website meta with url: %s' "500":
summary: Get website metadata description: Failed to write GetImage blob
summary: Get GetImage from URL
tags: tags:
- get - get
/o/get/image: /o/get/GetWebsiteMetadata:
get: get:
parameters: parameters:
- description: Image url - description: Website URL
in: query in: query
name: url name: url
required: true required: true
type: string type: string
produces: produces:
- image/* - application/json
responses: responses:
"200": "200":
description: Image description: Extracted metadata
schema:
$ref: '#/definitions/getter.HTMLMeta'
"400": "400":
description: 'Missing image url | Wrong url | Failed to get image url: %s' description: Missing website url | Wrong url
"500": "406":
description: Failed to write image blob description: 'Failed to get website meta with url: %s'
summary: Get image from URL summary: Get website metadata
tags: tags:
- get - get
/o/r/{resourceId}: /o/r/{resourceId}:

@ -43,32 +43,32 @@ type SystemStatus struct {
} }
func (s *APIV1Service) registerSystemRoutes(g *echo.Group) { func (s *APIV1Service) registerSystemRoutes(g *echo.Group) {
g.GET("/ping", s.ping) g.GET("/ping", s.PingSystem)
g.GET("/status", s.status) g.GET("/status", s.GetSystemStatus)
g.POST("/system/vacuum", s.vacuum) g.POST("/system/vacuum", s.ExecVacuum)
} }
// ping godoc // PingSystem godoc
// //
// @Summary Ping the system // @Summary Ping the system
// @Tags system // @Tags system
// @Produce json // @Produce json
// @Success 200 {object} profile.Profile "System profile" // @Success 200 {object} profile.Profile "System profile"
// @Router /api/v1/ping [GET] // @Router /api/v1/PingSystem [GET]
func (s *APIV1Service) ping(c echo.Context) error { func (s *APIV1Service) PingSystem(c echo.Context) error {
return c.JSON(http.StatusOK, s.Profile) return c.JSON(http.StatusOK, s.Profile)
} }
// status godoc // GetSystemStatus godoc
// //
// @Summary Get system status // @Summary Get system GetSystemStatus
// @Tags system // @Tags system
// @Produce json // @Produce json
// @Success 200 {object} SystemStatus "System status" // @Success 200 {object} SystemStatus "System GetSystemStatus"
// @Failure 401 {object} nil "Missing user in session | Unauthorized" // @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" // @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] // @Router /api/v1/GetSystemStatus [GET]
func (s *APIV1Service) status(c echo.Context) error { func (s *APIV1Service) GetSystemStatus(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
systemStatus := SystemStatus{ systemStatus := SystemStatus{
@ -156,17 +156,17 @@ func (s *APIV1Service) status(c echo.Context) error {
return c.JSON(http.StatusOK, systemStatus) return c.JSON(http.StatusOK, systemStatus)
} }
// vacuum godoc // ExecVacuum godoc
// //
// @Summary Vacuum the database // @Summary Vacuum the database
// @Tags system // @Tags system
// @Produce json // @Produce json
// @Success 200 {boolean} true "Database vacuumed" // @Success 200 {boolean} true "Database vacuumed"
// @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 401 {object} nil "Missing user in session | Unauthorized"
// @Failure 500 {object} nil "Failed to find user | Failed to vacuum database" // @Failure 500 {object} nil "Failed to find user | Failed to ExecVacuum database"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/system/vacuum [POST] // @Router /api/v1/system/ExecVacuum [POST]
func (s *APIV1Service) vacuum(c echo.Context) error { func (s *APIV1Service) ExecVacuum(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {

@ -79,11 +79,11 @@ type UpsertSystemSettingRequest struct {
} }
func (s *APIV1Service) registerSystemSettingRoutes(g *echo.Group) { func (s *APIV1Service) registerSystemSettingRoutes(g *echo.Group) {
g.GET("/system/setting", s.getSystemSettingList) g.GET("/system/setting", s.GetSystemSettingList)
g.POST("/system/setting", s.createSystemSetting) g.POST("/system/setting", s.CreateSystemSetting)
} }
// getSystemSettingList godoc // GetSystemSettingList godoc
// //
// @Summary Get a list of system settings // @Summary Get a list of system settings
// @Tags system-setting // @Tags system-setting
@ -93,7 +93,7 @@ func (s *APIV1Service) registerSystemSettingRoutes(g *echo.Group) {
// @Failure 500 {object} nil "Failed to find user | Failed to find system setting list" // @Failure 500 {object} nil "Failed to find user | Failed to find system setting list"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/system/setting [GET] // @Router /api/v1/system/setting [GET]
func (s *APIV1Service) getSystemSettingList(c echo.Context) error { func (s *APIV1Service) GetSystemSettingList(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -122,7 +122,7 @@ func (s *APIV1Service) getSystemSettingList(c echo.Context) error {
return c.JSON(http.StatusOK, systemSettingList) return c.JSON(http.StatusOK, systemSettingList)
} }
// createSystemSetting godoc // CreateSystemSetting godoc
// //
// @Summary Create system setting // @Summary Create system setting
// @Tags system-setting // @Tags system-setting
@ -136,7 +136,7 @@ func (s *APIV1Service) getSystemSettingList(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find user | Failed to upsert system setting" // @Failure 500 {object} nil "Failed to find user | Failed to upsert system setting"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/system/setting [POST] // @Router /api/v1/system/setting [POST]
func (s *APIV1Service) createSystemSetting(c echo.Context) error { func (s *APIV1Service) CreateSystemSetting(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {

@ -28,13 +28,13 @@ type DeleteTagRequest struct {
} }
func (s *APIV1Service) registerTagRoutes(g *echo.Group) { func (s *APIV1Service) registerTagRoutes(g *echo.Group) {
g.GET("/tag", s.getTagList) g.GET("/tag", s.GetTagList)
g.POST("/tag", s.createTag) g.POST("/tag", s.CreateTag)
g.POST("/tag/delete", s.deleteTag) g.GET("/tag/suggestion", s.GetTagSuggestion)
g.GET("/tag/suggestion", s.getTagSuggestion) g.POST("/tag/delete", s.DeleteTag)
} }
// getTagList godoc // GetTagList godoc
// //
// @Summary Get a list of tags // @Summary Get a list of tags
// @Tags tag // @Tags tag
@ -44,7 +44,7 @@ func (s *APIV1Service) registerTagRoutes(g *echo.Group) {
// @Failure 500 {object} nil "Failed to find tag list" // @Failure 500 {object} nil "Failed to find tag list"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/tag [GET] // @Router /api/v1/tag [GET]
func (s *APIV1Service) getTagList(c echo.Context) error { func (s *APIV1Service) GetTagList(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -65,7 +65,7 @@ func (s *APIV1Service) getTagList(c echo.Context) error {
return c.JSON(http.StatusOK, tagNameList) return c.JSON(http.StatusOK, tagNameList)
} }
// createTag godoc // CreateTag godoc
// //
// @Summary Create a tag // @Summary Create a tag
// @Tags tag // @Tags tag
@ -78,7 +78,7 @@ func (s *APIV1Service) getTagList(c echo.Context) error {
// @Failure 500 {object} nil "Failed to upsert tag | Failed to create activity" // @Failure 500 {object} nil "Failed to upsert tag | Failed to create activity"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/tag [POST] // @Router /api/v1/tag [POST]
func (s *APIV1Service) createTag(c echo.Context) error { func (s *APIV1Service) CreateTag(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -107,7 +107,7 @@ func (s *APIV1Service) createTag(c echo.Context) error {
return c.JSON(http.StatusOK, tagMessage.Name) return c.JSON(http.StatusOK, tagMessage.Name)
} }
// deleteTag godoc // DeleteTag godoc
// //
// @Summary Delete a tag // @Summary Delete a tag
// @Tags tag // @Tags tag
@ -120,7 +120,7 @@ func (s *APIV1Service) createTag(c echo.Context) error {
// @Failure 500 {object} nil "Failed to delete tag name: %v" // @Failure 500 {object} nil "Failed to delete tag name: %v"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/tag/delete [POST] // @Router /api/v1/tag/delete [POST]
func (s *APIV1Service) deleteTag(c echo.Context) error { func (s *APIV1Service) DeleteTag(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -145,7 +145,7 @@ func (s *APIV1Service) deleteTag(c echo.Context) error {
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
} }
// getTagSuggestion godoc // GetTagSuggestion godoc
// //
// @Summary Get a list of tags suggested from other memos contents // @Summary Get a list of tags suggested from other memos contents
// @Tags tag // @Tags tag
@ -155,7 +155,7 @@ func (s *APIV1Service) deleteTag(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find memo list | Failed to find tag list" // @Failure 500 {object} nil "Failed to find memo list | Failed to find tag list"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/tag/suggestion [GET] // @Router /api/v1/tag/suggestion [GET]
func (s *APIV1Service) getTagSuggestion(c echo.Context) error { func (s *APIV1Service) GetTagSuggestion(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {

@ -68,17 +68,17 @@ type UpdateUserRequest struct {
} }
func (s *APIV1Service) registerUserRoutes(g *echo.Group) { func (s *APIV1Service) registerUserRoutes(g *echo.Group) {
g.GET("/user", s.getUserList) g.GET("/user", s.GetUserList)
g.POST("/user", s.createUser) g.POST("/user", s.CreateUser)
g.GET("/user/me", s.getCurrentUser) g.GET("/user/me", s.GetCurrentUser)
// NOTE: This should be moved to /api/v2/user/:username // NOTE: This should be moved to /api/v2/user/:username
g.GET("/user/name/:username", s.getUserByUsername) g.GET("/user/name/:username", s.GetUserByUsername)
g.GET("/user/:id", s.getUserByID) g.GET("/user/:id", s.GetUserByID)
g.DELETE("/user/:id", s.deleteUser) g.PATCH("/user/:id", s.UpdateUser)
g.PATCH("/user/:id", s.updateUser) g.DELETE("/user/:id", s.DeleteUser)
} }
// getUserList godoc // GetUserList godoc
// //
// @Summary Get a list of users // @Summary Get a list of users
// @Tags user // @Tags user
@ -86,7 +86,7 @@ func (s *APIV1Service) registerUserRoutes(g *echo.Group) {
// @Success 200 {object} []store.User "User list" // @Success 200 {object} []store.User "User list"
// @Failure 500 {object} nil "Failed to fetch user list" // @Failure 500 {object} nil "Failed to fetch user list"
// @Router /api/v1/user [GET] // @Router /api/v1/user [GET]
func (s *APIV1Service) getUserList(c echo.Context) error { func (s *APIV1Service) GetUserList(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
list, err := s.Store.ListUsers(ctx, &store.FindUser{}) list, err := s.Store.ListUsers(ctx, &store.FindUser{})
if err != nil { if err != nil {
@ -104,7 +104,7 @@ func (s *APIV1Service) getUserList(c echo.Context) error {
return c.JSON(http.StatusOK, userMessageList) return c.JSON(http.StatusOK, userMessageList)
} }
// createUser godoc // CreateUser godoc
// //
// @Summary Create a user // @Summary Create a user
// @Tags user // @Tags user
@ -117,7 +117,7 @@ func (s *APIV1Service) getUserList(c echo.Context) error {
// @Failure 403 {object} nil "Could not create host user" // @Failure 403 {object} nil "Could not create host user"
// @Failure 500 {object} nil "Failed to find user by id | Failed to generate password hash | Failed to create user | Failed to create activity" // @Failure 500 {object} nil "Failed to find user by id | Failed to generate password hash | Failed to create user | Failed to create activity"
// @Router /api/v1/user [POST] // @Router /api/v1/user [POST]
func (s *APIV1Service) createUser(c echo.Context) error { func (s *APIV1Service) CreateUser(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -172,7 +172,7 @@ func (s *APIV1Service) createUser(c echo.Context) error {
return c.JSON(http.StatusOK, userMessage) return c.JSON(http.StatusOK, userMessage)
} }
// getCurrentUser godoc // GetCurrentUser godoc
// //
// @Summary Get current user // @Summary Get current user
// @Tags user // @Tags user
@ -182,7 +182,7 @@ func (s *APIV1Service) createUser(c echo.Context) error {
// @Failure 500 {object} nil "Failed to find user | Failed to find userSettingList" // @Failure 500 {object} nil "Failed to find user | Failed to find userSettingList"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/user/me [GET] // @Router /api/v1/user/me [GET]
func (s *APIV1Service) getCurrentUser(c echo.Context) error { func (s *APIV1Service) GetCurrentUser(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -212,7 +212,7 @@ func (s *APIV1Service) getCurrentUser(c echo.Context) error {
return c.JSON(http.StatusOK, userMessage) return c.JSON(http.StatusOK, userMessage)
} }
// getUserByUsername godoc // GetUserByUsername godoc
// //
// @Summary Get user by username // @Summary Get user by username
// @Tags user // @Tags user
@ -222,7 +222,7 @@ func (s *APIV1Service) getCurrentUser(c echo.Context) error {
// @Failure 404 {object} nil "User not found" // @Failure 404 {object} nil "User not found"
// @Failure 500 {object} nil "Failed to find user" // @Failure 500 {object} nil "Failed to find user"
// @Router /api/v1/user/name/{username} [GET] // @Router /api/v1/user/name/{username} [GET]
func (s *APIV1Service) getUserByUsername(c echo.Context) error { func (s *APIV1Service) GetUserByUsername(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
username := c.Param("username") username := c.Param("username")
user, err := s.Store.GetUser(ctx, &store.FindUser{Username: &username}) user, err := s.Store.GetUser(ctx, &store.FindUser{Username: &username})
@ -240,7 +240,7 @@ func (s *APIV1Service) getUserByUsername(c echo.Context) error {
return c.JSON(http.StatusOK, userMessage) return c.JSON(http.StatusOK, userMessage)
} }
// getUserByID godoc // GetUserByID godoc
// //
// @Summary Get user by id // @Summary Get user by id
// @Tags user // @Tags user
@ -251,7 +251,7 @@ func (s *APIV1Service) getUserByUsername(c echo.Context) error {
// @Failure 404 {object} nil "User not found" // @Failure 404 {object} nil "User not found"
// @Failure 500 {object} nil "Failed to find user" // @Failure 500 {object} nil "Failed to find user"
// @Router /api/v1/user/{id} [GET] // @Router /api/v1/user/{id} [GET]
func (s *APIV1Service) getUserByID(c echo.Context) error { func (s *APIV1Service) GetUserByID(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
id, err := util.ConvertStringToInt32(c.Param("id")) id, err := util.ConvertStringToInt32(c.Param("id"))
if err != nil { if err != nil {
@ -273,7 +273,7 @@ func (s *APIV1Service) getUserByID(c echo.Context) error {
return c.JSON(http.StatusOK, userMessage) return c.JSON(http.StatusOK, userMessage)
} }
// deleteUser godoc // DeleteUser godoc
// //
// @Summary Delete a user // @Summary Delete a user
// @Tags user // @Tags user
@ -285,7 +285,7 @@ func (s *APIV1Service) getUserByID(c echo.Context) error {
// @Failure 403 {object} nil "Unauthorized to delete user" // @Failure 403 {object} nil "Unauthorized to delete user"
// @Failure 500 {object} nil "Failed to find user | Failed to delete user" // @Failure 500 {object} nil "Failed to find user | Failed to delete user"
// @Router /api/v1/user/{id} [DELETE] // @Router /api/v1/user/{id} [DELETE]
func (s *APIV1Service) deleteUser(c echo.Context) error { func (s *APIV1Service) DeleteUser(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
currentUserID, ok := c.Get(auth.UserIDContextKey).(int32) currentUserID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {
@ -317,7 +317,7 @@ func (s *APIV1Service) deleteUser(c echo.Context) error {
return c.JSON(http.StatusOK, true) return c.JSON(http.StatusOK, true)
} }
// updateUser godoc // UpdateUser godoc
// //
// @Summary Update a user // @Summary Update a user
// @Tags user // @Tags user
@ -330,7 +330,7 @@ func (s *APIV1Service) deleteUser(c echo.Context) error {
// @Failure 403 {object} nil "Unauthorized to update user" // @Failure 403 {object} nil "Unauthorized to update user"
// @Failure 500 {object} nil "Failed to find user | Failed to generate password hash | Failed to patch user | Failed to find userSettingList" // @Failure 500 {object} nil "Failed to find user | Failed to generate password hash | Failed to patch user | Failed to find userSettingList"
// @Router /api/v1/user/{id} [PATCH] // @Router /api/v1/user/{id} [PATCH]
func (s *APIV1Service) updateUser(c echo.Context) error { func (s *APIV1Service) UpdateUser(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, err := util.ConvertStringToInt32(c.Param("id")) userID, err := util.ConvertStringToInt32(c.Param("id"))
if err != nil { if err != nil {

@ -79,12 +79,12 @@ type UpsertUserSettingRequest struct {
} }
func (s *APIV1Service) registerUserSettingRoutes(g *echo.Group) { func (s *APIV1Service) registerUserSettingRoutes(g *echo.Group) {
g.POST("/user/setting", s.createUserSetting) g.POST("/user/setting", s.UpsertUserSetting)
} }
// createUserSetting godoc // UpsertUserSetting godoc
// //
// @Summary Create user setting // @Summary Upsert user setting
// @Tags user-setting // @Tags user-setting
// @Accept json // @Accept json
// @Produce json // @Produce json
@ -95,7 +95,7 @@ func (s *APIV1Service) registerUserSettingRoutes(g *echo.Group) {
// @Failure 500 {object} nil "Failed to upsert user setting" // @Failure 500 {object} nil "Failed to upsert user setting"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /api/v1/user/setting [POST] // @Router /api/v1/user/setting [POST]
func (s *APIV1Service) createUserSetting(c echo.Context) error { func (s *APIV1Service) UpsertUserSetting(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
userID, ok := c.Get(auth.UserIDContextKey).(int32) userID, ok := c.Get(auth.UserIDContextKey).(int32)
if !ok { if !ok {

@ -1,107 +0,0 @@
# Authentication APIs
## Sign In
```
POST /api/v1/auth/signin
```
**Request Body**
```json
{
"username": "john",
"password": "password123"
}
```
**Response**
```json
{
"id": 123,
"username": "john",
"nickname": "John"
// other user fields
}
```
**Status Codes**
- 200: Sign in success
- 400: Invalid request
- 401: Incorrect credentials
- 403: User banned
- 500: Internal server error
## SSO Sign In
```
POST /api/v1/auth/signin/sso
```
**Request Body**
```json
{
"identityProviderId": 123,
"code": "abc123",
"redirectUri": "https://example.com/callback"
}
```
**Response**
Same as **Sign In**
**Status Codes**
- 200: Success
- 400: Invalid request
- 401: Authentication failed
- 403: User banned
- 404: Identity provider not found
- 500: Internal server error
## Sign Up
```
POST /api/v1/auth/signup
```
**Request Body**
```json
{
"username": "mary",
"password": "password456"
}
```
**Response**
Same as **Sign In**
**Status Codes**
- 200: Sign up success
- 400: Invalid request
- 401: Sign up disabled
- 500: Internal server error
## Sign Out
```
POST /api/v1/auth/signout
```
**Response**
```
true
```
**Status Codes**
- 200: Success
- 500: Internal server error

@ -1,44 +0,0 @@
# Guide to Access Memos API with OpenID
Memos API supports using OpenID as the user identifier to access the API.
## What is OpenID
OpenID is a unique identifier assigned by Memos system to each user.
When a user registers or logs in via third-party OAuth through Memos system, the OpenID will be generated automatically.
## How to Get User's OpenID
You can get a user's OpenID through:
- User checks the personal profile page in Memos system
- Calling Memos API to get user details
- Retrieving from login API response after successful login
Example:
```
// GET /api/v1/user/me
{
"id": 123,
"username": "john",
"openId": "8613E04B4FA6603883F05A5E0A5E2517",
...
}
```
## How to Use OpenID to Access API
You can access the API on behalf of the user by appending `?openId=xxx` parameter to the API URL.
For example:
```
curl 'https://demo.usememos.com/api/v1/memo?openId=8613E04B4FA6603883F05A5E0A5E2517' -H 'Content-Type: application/json' --data-raw '{"content":"Hello world!"}'
```
The above request will create a Memo under the user with OpenID `8613E04B4FA6603883F05A5E0A5E2517`.
OpenID can be used in any API that requires user identity.

@ -1,67 +0,0 @@
# Memo Relation APIs
## Create Memo Relation
```
POST /api/v1/memo/:memoId/relation
```
**Request Body**
```json
{
"relatedMemoId": 456,
"type": "REFERENCE"
}
```
**Response**
```json
{
"memoId": 123,
"relatedMemoId": 456,
"type": "REFERENCE"
}
```
**Status Codes**
- 200: OK
- 400: Invalid request
- 500: Internal server error
## Get Memo Relations
```
GET /api/v1/memo/:memoId/relation
```
**Response**
```json
[
{
"memoId": 123,
"relatedMemoId": 456,
"type": "REFERENCE"
}
]
```
**Status Codes**
- 200: OK
- 500: Internal server error
## Delete Memo Relation
```
DELETE /api/v1/memo/:memoId/relation/:relatedMemoId/type/:relationType
```
**Status Codes**
- 200: Deleted
- 400: Invalid request
- 500: Internal server error

@ -1,65 +0,0 @@
# Memo Resource APIs
## Bind Resource to Memo
```
POST /api/v1/memo/:memoId/resource
```
**Request Body**
```json
{
"resourceId": 123
}
```
**Response**
```
true
```
**Status Codes**
- 200: OK
- 400: Invalid request
- 401: Unauthorized
- 404: Memo/Resource not found
- 500: Internal server error
## Get Memo Resources
```
GET /api/v1/memo/:memoId/resource
```
**Response**
```json
[
{
"id": 123,
"filename": "example.png"
// other resource fields
}
]
```
**Status Codes**
- 200: OK
- 500: Internal server error
## Unbind Resource from Memo
```
DELETE /api/v1/memo/:memoId/resource/:resourceId
```
**Status Codes**
- 200: OK
- 401: Unauthorized
- 404: Memo/Resource not found
- 500: Internal server error

@ -1,136 +0,0 @@
# Memo APIs
## Create Memo
```
POST /api/v1/memo
```
**Request Body**
```json
{
"content": "Memo content",
"visibility": "PUBLIC",
"resourceIdList": [123, 456],
"relationList": [{ "relatedMemoId": 789, "type": "REFERENCE" }]
}
```
**Response**
```json
{
"id": 1234,
"content": "Memo content",
"visibility": "PUBLIC"
// other fields
}
```
**Status Codes**
- 200: Created
- 400: Invalid request
- 401: Unauthorized
- 403: Forbidden to create public memo
- 500: Internal server error
## Get Memo List
```
GET /api/v1/memo
```
**Parameters**
- `creatorId` (optional): Filter by creator ID
- `visibility` (optional): Filter visibility, `PUBLIC`, `PROTECTED` or `PRIVATE`
- `rowStatus` (optional): Filter Status, `ARCHIVE`, `NORMAL`, Default `NORMAL`
- `pinned` (optional): Filter pinned memo, `true` or `false`
- `tag` (optional): Filter memo with tag
- `content` (optional): Search in content
- `limit` (optional): Limit number of results
- `offset` (optional): Offset of first result
**Response**
```json
[
{
"id": 1234,
"content": "Memo 1"
// other fields
},
{
"id": 5678,
"content": "Memo 2"
// other fields
}
]
```
## Get Memo By ID
```
GET /api/v1/memo/:memoId
```
**Response**
```json
{
"id": 1234,
"content": "Memo content"
// other fields
}
```
**Status Codes**
- 200: Success
- 403: Forbidden for private memo
- 404: Not found
- 500: Internal server error
## Update Memo
```
PATCH /api/v1/memo/:memoId
```
**Request Body**
```json
{
"content": "Updated content",
"visibility": "PRIVATE"
}
```
**Response**
Same as **Get Memo By ID**
**Status Codes**
- 200: Updated
- 400: Invalid request
- 401: Unauthorized
- 403: Forbidden
- 404: Not found
- 500: Internal server error
## Delete Memo
```
DELETE /api/v1/memo/:memoId
```
**Status Codes**
- 200: Deleted
- 401: Unauthorized
- 403: Forbidden
- 404: Not found
- 500: Internal server error

@ -1,130 +0,0 @@
# Resource APIs
## Upload Resource
### Upload File
```
POST /api/v1/resource/blob
```
**Request Form**
- `file`: Upload file
**Response**
```json
{
"id": 123,
"filename": "example.png"
// other fields
}
```
**Status Codes**
- 200: OK
- 400: Invalid request
- 401: Unauthorized
- 413: File too large
- 500: Internal server error
### Create Resource
```
POST /api/v1/resource
```
**Request Body**
```json
{
"filename": "example.png",
"externalLink": "https://example.com/image.png"
}
```
**Response**
Same as **Upload File**
**Status Codes**
- 200: OK
- 400: Invalid request
- 401: Unauthorized
- 500: Internal server error
## Get Resource List
```
GET /api/v1/resource
```
**Parameters**
- `limit` (optional): Limit number of results
- `offset` (optional): Offset of first result
**Response**
```json
[
{
"id": 123,
"filename": "example.png"
// other fields
},
{
"id": 456,
"filename": "doc.pdf"
// other fields
}
]
```
**Status Codes**
- 200: OK
- 401: Unauthorized
- 500: Internal server error
## Update Resource
```
PATCH /api/v1/resource/:resourceId
```
**Request Body**
```json
{
"filename": "new_name.png"
}
```
**Response**
Same as **Get Resource List**
**Status Codes**
- 200: OK
- 400: Invalid request
- 401: Unauthorized
- 404: Not found
- 500: Internal server error
## Delete Resource
```
DELETE /api/v1/resource/:resourceId
```
**Status Codes**
- 200: Deleted
- 401: Unauthorized
- 404: Not found
- 500: Internal server error

@ -1,84 +0,0 @@
# Tag APIs
## Create Tag
```
POST /api/v1/tag
```
**Request Body**
```json
{
"name": "python"
}
```
**Response**
```
"python"
```
**Status Codes**
- 200: Created
- 400: Invalid request
- 500: Internal server error
## Get Tag List
```
GET /api/v1/tag
```
**Response**
```json
["python", "golang", "javascript"]
```
**Status Codes**
- 200: OK
- 401: Unauthorized
- 500: Internal server error
## Suggest Tags
```
GET /api/v1/tag/suggestion
```
**Response**
```json
["django", "flask", "numpy"]
```
**Status Codes**
- 200: OK
- 401: Unauthorized
- 500: Internal server error
## Delete Tag
```
POST /api/v1/tag/delete
```
**Request Body**
```json
{
"name": "outdated_tag"
}
```
**Status Codes**
- 200: Deleted
- 400: Invalid request
- 401: Unauthorized
- 500: Internal server error

@ -1,164 +0,0 @@
# User APIs
## Create User
```
POST /api/v1/user
```
**Request Body**
```json
{
"username": "john",
"role": "USER",
"email": "john@example.com",
"nickname": "John",
"password": "password123"
}
```
**Response**
```json
{
"id": 123,
"username": "john",
"role": "USER",
"email": "john@example.com",
"nickname": "John",
"avatarUrl": "",
"createdTs": 1596647800,
"updatedTs": 1596647800
}
```
**Status Codes**
- 200: Success
- 400: Validation error
- 401: Unauthorized
- 403: Forbidden to create host user
- 500: Internal server error
## Get User List
```
GET /api/v1/user
```
**Response**
```json
[
{
"id": 123,
"username": "john",
"role": "USER"
// other fields
},
{
"id": 456,
"username": "mary",
"role": "ADMIN"
// other fields
}
]
```
**Status Codes**
- 200: Success
- 500: Internal server error
## Get User By ID
```
GET /api/v1/user/:id
```
**Response**
```json
{
"id": 123,
"username": "john",
"role": "USER"
// other fields
}
```
**Status Codes**
- 200: Success
- 404: Not found
- 500: Internal server error
## Update User
```
PATCH /api/v1/user/:id
```
**Request Body**
```json
{
"username": "johnny",
"email": "johnny@example.com",
"nickname": "Johnny",
"avatarUrl": "https://avatars.example.com/u=123"
}
```
**Response**
```json
{
"id": 123,
"username": "johnny",
"role": "USER",
"email": "johnny@example.com",
"nickname": "Johnny",
"avatarUrl": "https://avatars.example.com/u=123",
"createdTs": 1596647800,
"updatedTs": 1596647900
}
```
**Status Codes**
- 200: Success
- 400: Validation error
- 403: Forbidden
- 404: Not found
- 500: Internal server error
## Delete User
```
DELETE /api/v1/user/:id
```
**Status Codes**
- 200: Success
- 403: Forbidden
- 404: Not found
- 500: Internal server error
## Get Current User
```
GET /api/v1/user/me
```
**Response**
Same as **Get User By ID**
**Status Codes**
- 200: Success
- 401: Unauthorized
- 500: Internal server error

@ -37,8 +37,8 @@
2. Run one of the following provided scripts: 2. Run one of the following provided scripts:
- Linux: `./scripts/generate-api-documentation.sh` (remember to `chmod +x` the script first) - Linux: `./scripts/gen-api-v1-docs.sh` (remember to `chmod +x` the script first)
- Windows: `./scripts/generate-api-documentation.ps1` - Windows: `./scripts/gen-api-v1-docs.ps1`
> The scripts will install swag if needed (via go install), then run `swag fmt` and `swag init` commands. > The scripts will install swag if needed (via go install), then run `swag fmt` and `swag init` commands.
@ -48,7 +48,7 @@
- If you reference a custom Go struct from outside the API file, use a relative definition, like `store.IdentityProvider`. This works because `./` is passed to swag at `--dir` argument. If swag can't resolve the reference, it will fail. - If you reference a custom Go struct from outside the API file, use a relative definition, like `store.IdentityProvider`. This works because `./` is passed to swag at `--dir` argument. If swag can't resolve the reference, it will fail.
- If the API grows or you need to reference some type from another location, remember to update ./scripts/generate-api-documentation.cfg file with the new paths. - If the API grows or you need to reference some type from another location, remember to update ./scripts/gen-api-v1-docs.cfg file with the new paths.
- It's possible to list multiple errors for the same code using enum-like structs, that will show a proper, spec-conformant model with all entries at Swagger-UI. The drawback is that this approach requires a major refactoring and will add a lot of boilerplate code, as there are inconsistencies between API methods error responses. - It's possible to list multiple errors for the same code using enum-like structs, that will show a proper, spec-conformant model with all entries at Swagger-UI. The drawback is that this approach requires a major refactoring and will add a lot of boilerplate code, as there are inconsistencies between API methods error responses.

@ -1,4 +1,4 @@
# This file is used by generate-api-documentation.ps1 and generate-api-documentation.sh # This file is used by gen-api-v1-docs.ps1 and gen-api-v1-docs.sh
# You should list aditional dirs here if the API grows # You should list aditional dirs here if the API grows
SWAG_API_DIRS=./api/v1 SWAG_API_DIRS=./api/v1
@ -10,4 +10,4 @@ SWAG_GENERAL_INFO=./server/server.go
SWAG_OUTPUT_TYPES=go,yaml SWAG_OUTPUT_TYPES=go,yaml
# Where generated files are outputted # Where generated files are outputted
SWAG_OUTPUT=./api SWAG_OUTPUT=./api/v1

@ -7,10 +7,10 @@
# Requirements: # Requirements:
# * go # * go
# swag is configured mainly via generate-api-documentation.cfg file. # swag is configured mainly via gen-api-v1-docs.cfg file.
# Usage: # Usage:
# ./scripts/generate-api-documentation.ps1 # ./scripts/gen-api-v1-docs.ps1
foreach ($dir in @(".", "../")) { foreach ($dir in @(".", "../")) {
if (Test-Path (Join-Path $dir ".gitignore")) { if (Test-Path (Join-Path $dir ".gitignore")) {
@ -20,8 +20,8 @@ foreach ($dir in @(".", "../")) {
} }
Set-Location $repoRoot Set-Location $repoRoot
Write-Host "Parsing generate-api-documentation.cfg..." Write-Host "Parsing gen-api-v1-docs.cfg..."
foreach ($line in (Get-Content "$repoRoot\scripts\generate-api-documentation.cfg" )) { foreach ($line in (Get-Content "$repoRoot\scripts\gen-api-v1-docs.cfg" )) {
if ($line.Trim().StartsWith('#')) { if ($line.Trim().StartsWith('#')) {
continue continue
} }

@ -9,11 +9,11 @@
# Requirements: # Requirements:
# * go # * go
# swag is configured via generate-api-documentation.cfg file. # swag is configured via gen-api-v1-docs.cfg file.
# Usage: # Usage:
# chmod +x ./scripts/generate-api-documentation.sh # chmod +x ./scripts/gen-api-v1-docs.sh
# ./scripts/generate-api-documentation.sh # ./scripts/gen-api-v1-docs.sh
find_repo_root() { find_repo_root() {
# Usage: find_repo_root <file_at_root> <dir1> <dir2> ... # Usage: find_repo_root <file_at_root> <dir1> <dir2> ...
@ -59,8 +59,8 @@ else
fi fi
cd $repo_root cd $repo_root
echo "Parsing generate-api-documentation.cfg..." echo "Parsing gen-api-v1-docs.cfg..."
source "$repo_root/scripts/generate-api-documentation.cfg" source "$repo_root/scripts/gen-api-v1-docs.cfg"
echo -e "API directories: \033[0;34m$SWAG_API_DIRS\033[0m" echo -e "API directories: \033[0;34m$SWAG_API_DIRS\033[0m"
echo -e "Output directory: \033[0;34m$SWAG_OUTPUT\033[0m" echo -e "Output directory: \033[0;34m$SWAG_OUTPUT\033[0m"

@ -13,7 +13,6 @@ import (
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
"github.com/pkg/errors" "github.com/pkg/errors"
echoSwagger "github.com/swaggo/echo-swagger" echoSwagger "github.com/swaggo/echo-swagger"
api "github.com/usememos/memos/api"
apiv1 "github.com/usememos/memos/api/v1" apiv1 "github.com/usememos/memos/api/v1"
apiv2 "github.com/usememos/memos/api/v2" apiv2 "github.com/usememos/memos/api/v2"
"github.com/usememos/memos/common/log" "github.com/usememos/memos/common/log"
@ -60,9 +59,6 @@ type Server struct {
// @name openId // @name openId
// @description Insert your Open ID API Key here. // @description Insert your Open ID API Key here.
func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) { func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) {
// programmatically set API version same as the server version
api.SwaggerInfo.Version = profile.Version
e := echo.New() e := echo.New()
e.Debug = true e.Debug = true
e.HideBanner = true e.HideBanner = true
@ -153,6 +149,9 @@ func (s *Server) Start(ctx context.Context) error {
} }
}() }()
// programmatically set API version same as the server version
apiv1.SwaggerInfo.Version = s.Profile.Version
return s.e.Start(fmt.Sprintf(":%d", s.Profile.Port)) return s.e.Start(fmt.Sprintf(":%d", s.Profile.Port))
} }

Loading…
Cancel
Save