mirror of
https://github.com/mattermost/focalboard.git
synced 2025-01-26 18:48:15 +02:00
Add Swagger / OpenAPI docs
This commit is contained in:
parent
13d48c5a8f
commit
1ad985232d
1
.gitignore
vendored
1
.gitignore
vendored
@ -59,3 +59,4 @@ win/temp
|
|||||||
win/dist
|
win/dist
|
||||||
webapp/cypress/screenshots
|
webapp/cypress/screenshots
|
||||||
webapp/cypress/videos
|
webapp/cypress/videos
|
||||||
|
server/swagger/clients
|
||||||
|
12
Makefile
12
Makefile
@ -133,6 +133,18 @@ linux-app: server-linux webapp
|
|||||||
cd linux/temp; tar -zcf ../dist/focalboard-linux.tar.gz focalboard-app
|
cd linux/temp; tar -zcf ../dist/focalboard-linux.tar.gz focalboard-app
|
||||||
rm -rf linux/temp
|
rm -rf linux/temp
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
mkdir -p server/swagger/docs
|
||||||
|
mkdir -p server/swagger/clients
|
||||||
|
cd server && swagger generate spec -m -o ./swagger/swagger.yml
|
||||||
|
|
||||||
|
cd server/swagger && openapi-generator generate -i swagger.yml -g html2 -o docs/html
|
||||||
|
cd server/swagger && openapi-generator generate -i swagger.yml -g go -o clients/go
|
||||||
|
cd server/swagger && openapi-generator generate -i swagger.yml -g javascript -o clients/javascript
|
||||||
|
cd server/swagger && openapi-generator generate -i swagger.yml -g typescript-fetch -o clients/typescript
|
||||||
|
cd server/swagger && openapi-generator generate -i swagger.yml -g swift5 -o clients/swift
|
||||||
|
cd server/swagger && openapi-generator generate -i swagger.yml -g python -o clients/python
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin
|
rm -rf bin
|
||||||
rm -rf dist
|
rm -rf dist
|
||||||
|
@ -20,29 +20,29 @@ func (a *API) handleAdminSetPassword(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
requestBody, err := ioutil.ReadAll(r.Body)
|
requestBody, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var requestData AdminSetPasswordData
|
var requestData AdminSetPasswordData
|
||||||
err = json.Unmarshal(requestBody, &requestData)
|
err = json.Unmarshal(requestBody, &requestData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(requestData.Password, "") {
|
if !strings.Contains(requestData.Password, "") {
|
||||||
errorResponse(w, http.StatusInternalServerError, map[string]string{"error": "password is required"}, err)
|
errorResponse(w, http.StatusBadRequest, "password is required", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.app().UpdateUserPassword(username, requestData.Password)
|
err = a.app().UpdateUserPassword(username, requestData.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("AdminSetPassword, username: %s", username)
|
log.Printf("AdminSetPassword, username: %s", username)
|
||||||
|
|
||||||
jsonBytesResponse(w, http.StatusOK, nil)
|
jsonStringResponse(w, http.StatusOK, "{}")
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ func (a *API) requireCSRFToken(next http.Handler) http.Handler {
|
|||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if !a.checkCSRFToken(r) {
|
if !a.checkCSRFToken(r) {
|
||||||
log.Println("checkCSRFToken FAILED")
|
log.Println("checkCSRFToken FAILED")
|
||||||
errorResponse(w, http.StatusBadRequest, nil, nil)
|
errorResponse(w, http.StatusBadRequest, "", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,13 +102,45 @@ func (a *API) checkCSRFToken(r *http.Request) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation GET /api/v1/blocks getBlocks
|
||||||
|
//
|
||||||
|
// Returns blocks
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: parent_id
|
||||||
|
// in: query
|
||||||
|
// description: ID of parent block, omit to specify all blocks
|
||||||
|
// required: false
|
||||||
|
// type: string
|
||||||
|
// - name: type
|
||||||
|
// in: query
|
||||||
|
// description: Type of blocks to return, omit to specify all types
|
||||||
|
// required: false
|
||||||
|
// type: string
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// schema:
|
||||||
|
// type: array
|
||||||
|
// items:
|
||||||
|
// "$ref": "#/definitions/Block"
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
parentID := query.Get("parent_id")
|
parentID := query.Get("parent_id")
|
||||||
blockType := query.Get("type")
|
blockType := query.Get("type")
|
||||||
|
|
||||||
blocks, err := a.app().GetBlocks(parentID, blockType)
|
blocks, err := a.app().GetBlocks(parentID, blockType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +148,7 @@ func (a *API) handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
json, err := json.Marshal(blocks)
|
json, err := json.Marshal(blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,9 +169,35 @@ func stampModifiedByUser(r *http.Request, blocks []model.Block) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation POST /api/v1/blocks updateBlocks
|
||||||
|
//
|
||||||
|
// Insert or update blocks
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: Body
|
||||||
|
// in: body
|
||||||
|
// description: array of blocks to insert or update
|
||||||
|
// required: true
|
||||||
|
// schema:
|
||||||
|
// type: array
|
||||||
|
// items:
|
||||||
|
// "$ref": "#/definitions/Block"
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
requestBody, err := ioutil.ReadAll(r.Body)
|
requestBody, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,27 +205,27 @@ func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
err = json.Unmarshal(requestBody, &blocks)
|
err = json.Unmarshal(requestBody, &blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, block := range blocks {
|
for _, block := range blocks {
|
||||||
// Error checking
|
// Error checking
|
||||||
if len(block.Type) < 1 {
|
if len(block.Type) < 1 {
|
||||||
errorData := map[string]string{"description": "missing type", "id": block.ID}
|
message := fmt.Sprintf("missing type for block id %s", block.ID)
|
||||||
errorResponse(w, http.StatusBadRequest, errorData, nil)
|
errorResponse(w, http.StatusBadRequest, message, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if block.CreateAt < 1 {
|
if block.CreateAt < 1 {
|
||||||
errorData := map[string]string{"description": "invalid createAt", "id": block.ID}
|
message := fmt.Sprintf("invalid createAt for block id %s", block.ID)
|
||||||
errorResponse(w, http.StatusBadRequest, errorData, nil)
|
errorResponse(w, http.StatusBadRequest, message, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if block.UpdateAt < 1 {
|
if block.UpdateAt < 1 {
|
||||||
errorData := map[string]string{"description": "invalid UpdateAt", "id": block.ID}
|
message := fmt.Sprintf("invalid UpdateAt for block id %s", block.ID)
|
||||||
errorResponse(w, http.StatusBadRequest, errorData, nil)
|
errorResponse(w, http.StatusBadRequest, message, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,7 +234,7 @@ func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
err = a.app().InsertBlocks(blocks)
|
err = a.app().InsertBlocks(blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,25 +243,69 @@ func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleGetUser(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleGetUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation GET /api/v1/users/{userID} getUser
|
||||||
|
//
|
||||||
|
// Returns a user
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: userID
|
||||||
|
// in: path
|
||||||
|
// description: User ID
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/User"
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
userID := vars["userID"]
|
userID := vars["userID"]
|
||||||
|
|
||||||
user, err := a.app().GetUser(userID)
|
user, err := a.app().GetUser(userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userData, err := json.Marshal(user)
|
userData, err := json.Marshal(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonStringResponse(w, http.StatusOK, string(userData))
|
jsonBytesResponse(w, http.StatusOK, userData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleGetMe(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleGetMe(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation GET /api/v1/users/me getMe
|
||||||
|
//
|
||||||
|
// Returns the currently logged-in user
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/User"
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
session := ctx.Value("session").(*model.Session)
|
session := ctx.Value("session").(*model.Session)
|
||||||
var user *model.User
|
var user *model.User
|
||||||
@ -221,21 +323,44 @@ func (a *API) handleGetMe(w http.ResponseWriter, r *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
user, err = a.app().GetUser(session.UserID)
|
user, err = a.app().GetUser(session.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userData, err := json.Marshal(user)
|
userData, err := json.Marshal(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonStringResponse(w, http.StatusOK, string(userData))
|
jsonBytesResponse(w, http.StatusOK, userData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleDeleteBlock(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleDeleteBlock(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation DELETE /api/v1/blocks/{blockID} deleteBlock
|
||||||
|
//
|
||||||
|
// Deletes a block
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: blockID
|
||||||
|
// in: path
|
||||||
|
// description: ID of block to delete
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
session := ctx.Value("session").(*model.Session)
|
session := ctx.Value("session").(*model.Session)
|
||||||
userID := session.UserID
|
userID := session.UserID
|
||||||
@ -245,7 +370,7 @@ func (a *API) handleDeleteBlock(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
err := a.app().DeleteBlock(blockID, userID)
|
err := a.app().DeleteBlock(blockID, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -255,6 +380,40 @@ func (a *API) handleDeleteBlock(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation GET /api/v1/blocks/{blockID}/subtree getSubTree
|
||||||
|
//
|
||||||
|
// Returns the blocks of a subtree
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: blockID
|
||||||
|
// in: path
|
||||||
|
// description: The ID of the root block of the subtree
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
|
// - name: l
|
||||||
|
// in: query
|
||||||
|
// description: The number of levels to return. 2 or 3. Defaults to 2.
|
||||||
|
// required: false
|
||||||
|
// type: integer
|
||||||
|
// minimum: 2
|
||||||
|
// maximum: 3
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// schema:
|
||||||
|
// type: array
|
||||||
|
// items:
|
||||||
|
// "$ref": "#/definitions/Block"
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
blockID := vars["blockID"]
|
blockID := vars["blockID"]
|
||||||
|
|
||||||
@ -267,18 +426,18 @@ func (a *API) handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Require read token
|
// Require read token
|
||||||
if len(readToken) < 1 {
|
if len(readToken) < 1 {
|
||||||
errorResponse(w, http.StatusUnauthorized, map[string]string{"error": "No read_token"}, nil)
|
errorResponse(w, http.StatusBadRequest, "No read_token", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid, err := a.app().IsValidReadToken(blockID, readToken)
|
isValid, err := a.app().IsValidReadToken(blockID, readToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isValid {
|
if !isValid {
|
||||||
errorResponse(w, http.StatusUnauthorized, nil, nil)
|
errorResponse(w, http.StatusUnauthorized, "", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,21 +450,20 @@ func (a *API) handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if levels != 2 && levels != 3 {
|
if levels != 2 && levels != 3 {
|
||||||
log.Printf(`ERROR Invalid levels: %d`, levels)
|
log.Printf(`ERROR Invalid levels: %d`, levels)
|
||||||
errorData := map[string]string{"description": "invalid levels"}
|
errorResponse(w, http.StatusBadRequest, "invalid levels", nil)
|
||||||
errorResponse(w, http.StatusInternalServerError, errorData, nil)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks, err := a.app().GetSubTree(blockID, int(levels))
|
blocks, err := a.app().GetSubTree(blockID, int(levels))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("GetSubTree (%v) blockID: %s, %d result(s)", levels, blockID, len(blocks))
|
log.Printf("GetSubTree (%v) blockID: %s, %d result(s)", levels, blockID, len(blocks))
|
||||||
json, err := json.Marshal(blocks)
|
json, err := json.Marshal(blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,9 +471,30 @@ func (a *API) handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleExport(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleExport(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation GET /api/v1/blocks/export exportBlocks
|
||||||
|
//
|
||||||
|
// Returns all blocks
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// schema:
|
||||||
|
// type: array
|
||||||
|
// items:
|
||||||
|
// "$ref": "#/definitions/Block"
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
blocks, err := a.app().GetAllBlocks()
|
blocks, err := a.app().GetAllBlocks()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +504,7 @@ func (a *API) handleExport(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
json, err := json.Marshal(blocks)
|
json, err := json.Marshal(blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,9 +556,35 @@ func arrayContainsBlockWithID(array []model.Block, blockID string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleImport(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleImport(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation POST /api/v1/blocks/import importBlocks
|
||||||
|
//
|
||||||
|
// Import blocks
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: Body
|
||||||
|
// in: body
|
||||||
|
// description: array of blocks to import
|
||||||
|
// required: true
|
||||||
|
// schema:
|
||||||
|
// type: array
|
||||||
|
// items:
|
||||||
|
// "$ref": "#/definitions/Block"
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
requestBody, err := ioutil.ReadAll(r.Body)
|
requestBody, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,8 +592,7 @@ func (a *API) handleImport(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
err = json.Unmarshal(requestBody, &blocks)
|
err = json.Unmarshal(requestBody, &blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,8 +600,7 @@ func (a *API) handleImport(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
err = a.app().InsertBlocks(blocks)
|
err = a.app().InsertBlocks(blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,29 +611,83 @@ func (a *API) handleImport(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Sharing
|
// Sharing
|
||||||
|
|
||||||
func (a *API) handleGetSharing(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleGetSharing(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation GET /api/v1/sharing/{rootID} getSharing
|
||||||
|
//
|
||||||
|
// Returns sharing information for a root block
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: rootID
|
||||||
|
// in: path
|
||||||
|
// description: ID of the root block
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/Sharing"
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
rootID := vars["rootID"]
|
rootID := vars["rootID"]
|
||||||
|
|
||||||
sharing, err := a.app().GetSharing(rootID)
|
sharing, err := a.app().GetSharing(rootID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sharingData, err := json.Marshal(sharing)
|
sharingData, err := json.Marshal(sharing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("GET sharing %s", rootID)
|
log.Printf("GET sharing %s", rootID)
|
||||||
jsonStringResponse(w, http.StatusOK, string(sharingData))
|
jsonBytesResponse(w, http.StatusOK, sharingData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handlePostSharing(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handlePostSharing(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation POST /api/v1/sharing/{rootID} postSharing
|
||||||
|
//
|
||||||
|
// Sets sharing information for a root block
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: rootID
|
||||||
|
// in: path
|
||||||
|
// description: ID of the root block
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
|
// - name: Body
|
||||||
|
// in: body
|
||||||
|
// description: sharing information for a root block
|
||||||
|
// required: true
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/Sharing"
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
requestBody, err := ioutil.ReadAll(r.Body)
|
requestBody, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +695,7 @@ func (a *API) handlePostSharing(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
err = json.Unmarshal(requestBody, &sharing)
|
err = json.Unmarshal(requestBody, &sharing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +710,7 @@ func (a *API) handlePostSharing(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
err = a.app().UpsertSharing(sharing)
|
err = a.app().UpsertSharing(sharing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,25 +721,61 @@ func (a *API) handlePostSharing(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Workspace
|
// Workspace
|
||||||
|
|
||||||
func (a *API) handleGetWorkspace(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleGetWorkspace(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation GET /api/v1/workspace getWorkspace
|
||||||
|
//
|
||||||
|
// Returns information of the root workspace
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/Workspace"
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
workspace, err := a.app().GetRootWorkspace()
|
workspace, err := a.app().GetRootWorkspace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
workspaceData, err := json.Marshal(workspace)
|
workspaceData, err := json.Marshal(workspace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonStringResponse(w, http.StatusOK, string(workspaceData))
|
jsonBytesResponse(w, http.StatusOK, workspaceData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handlePostWorkspaceRegenerateSignupToken(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handlePostWorkspaceRegenerateSignupToken(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation POST /api/v1/workspace/regenerate_signup_token regenerateSignupToken
|
||||||
|
//
|
||||||
|
// Regenerates the signup token for the root workspace
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
workspace, err := a.app().GetRootWorkspace()
|
workspace, err := a.app().GetRootWorkspace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +783,7 @@ func (a *API) handlePostWorkspaceRegenerateSignupToken(w http.ResponseWriter, r
|
|||||||
|
|
||||||
err = a.app().UpsertWorkspaceSignupToken(*workspace)
|
err = a.app().UpsertWorkspaceSignupToken(*workspace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,6 +793,31 @@ func (a *API) handlePostWorkspaceRegenerateSignupToken(w http.ResponseWriter, r
|
|||||||
// File upload
|
// File upload
|
||||||
|
|
||||||
func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation GET /files/{fileID} getFile
|
||||||
|
//
|
||||||
|
// Returns the contents of an uploaded file
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// - image/jpg
|
||||||
|
// - image/png
|
||||||
|
// parameters:
|
||||||
|
// - name: fileID
|
||||||
|
// in: path
|
||||||
|
// description: ID of the file
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
filename := vars["filename"]
|
filename := vars["filename"]
|
||||||
|
|
||||||
@ -516,8 +834,40 @@ func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.ServeFile(w, r, filePath)
|
http.ServeFile(w, r, filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FileUploadResponse is the response to a file upload
|
||||||
|
// swagger:model
|
||||||
|
type FileUploadResponse struct {
|
||||||
|
// The URL to retrieve the uploaded file
|
||||||
|
// required: true
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Println(`handleUploadFile`)
|
// swagger:operation POST /api/v1/files uploadFile
|
||||||
|
//
|
||||||
|
// Upload a binary file
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// consumes:
|
||||||
|
// - multipart/form-data
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: uploaded file
|
||||||
|
// in: formData
|
||||||
|
// type: file
|
||||||
|
// description: The file to upload
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/FileUploadResponse"
|
||||||
|
// default:
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
file, handle, err := r.FormFile("file")
|
file, handle, err := r.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -527,18 +877,20 @@ func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
log.Printf(`handleUploadFile, filename: %s`, handle.Filename)
|
|
||||||
|
|
||||||
url, err := a.app().SaveFile(file, handle.Filename)
|
url, err := a.app().SaveFile(file, handle.Filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonStringResponse(w, http.StatusInternalServerError, `{}`)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf(`saveFile, url: %s`, url)
|
log.Printf("uploadFile, filename: %s, url: %s", handle.Filename, url)
|
||||||
json := fmt.Sprintf(`{ "url": "%s" }`, url)
|
data, err := json.Marshal(FileUploadResponse{URL: url})
|
||||||
jsonStringResponse(w, http.StatusOK, json)
|
if err != nil {
|
||||||
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytesResponse(w, http.StatusOK, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response helpers
|
// Response helpers
|
||||||
@ -555,10 +907,10 @@ func jsonBytesResponse(w http.ResponseWriter, code int, json []byte) {
|
|||||||
w.Write(json)
|
w.Write(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
func errorResponse(w http.ResponseWriter, code int, message map[string]string, sourceError error) {
|
func errorResponse(w http.ResponseWriter, code int, message string, sourceError error) {
|
||||||
log.Printf("API ERROR %d, err: %v\n", code, sourceError)
|
log.Printf("API ERROR %d, err: %v\n", code, sourceError)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
data, err := json.Marshal(message)
|
data, err := json.Marshal(model.ErrorResponse{Error: message})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
data = []byte("{}")
|
data = []byte("{}")
|
||||||
}
|
}
|
||||||
|
@ -17,22 +17,60 @@ import (
|
|||||||
"github.com/mattermost/focalboard/server/services/auth"
|
"github.com/mattermost/focalboard/server/services/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginData struct {
|
// LoginRequest is a login request
|
||||||
|
// swagger:model
|
||||||
|
type LoginRequest struct {
|
||||||
|
// Type of login, currently must be set to "normal"
|
||||||
|
// required: true
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// If specified, login using username
|
||||||
|
// required: false
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
|
|
||||||
|
// If specified, login using email
|
||||||
|
// required: false
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
|
||||||
|
// Password
|
||||||
|
// required: true
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
|
||||||
|
// MFA token
|
||||||
|
// required: false
|
||||||
|
// swagger:ignore
|
||||||
MfaToken string `json:"mfa_token"`
|
MfaToken string `json:"mfa_token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegisterData struct {
|
// LoginResponse is a login response
|
||||||
Username string `json:"username"`
|
// swagger:model
|
||||||
Email string `json:"email"`
|
type LoginResponse struct {
|
||||||
Password string `json:"password"`
|
// Session token
|
||||||
|
// required: true
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rd *RegisterData) IsValid() error {
|
// RegisterRequest is a user registration request
|
||||||
|
// swagger:model
|
||||||
|
type RegisterRequest struct {
|
||||||
|
// User name
|
||||||
|
// required: true
|
||||||
|
Username string `json:"username"`
|
||||||
|
|
||||||
|
// User's email
|
||||||
|
// required: true
|
||||||
|
Email string `json:"email"`
|
||||||
|
|
||||||
|
// Password
|
||||||
|
// required: true
|
||||||
|
Password string `json:"password"`
|
||||||
|
|
||||||
|
// Registration authorization token
|
||||||
|
// required: true
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rd *RegisterRequest) IsValid() error {
|
||||||
if rd.Username == "" {
|
if rd.Username == "" {
|
||||||
return errors.New("Username is required")
|
return errors.New("Username is required")
|
||||||
}
|
}
|
||||||
@ -51,12 +89,20 @@ func (rd *RegisterData) IsValid() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChangePasswordData struct {
|
// ChangePasswordRequest is a user password change request
|
||||||
|
// swagger:model
|
||||||
|
type ChangePasswordRequest struct {
|
||||||
|
// Old password
|
||||||
|
// required: true
|
||||||
OldPassword string `json:"oldPassword"`
|
OldPassword string `json:"oldPassword"`
|
||||||
|
|
||||||
|
// New password
|
||||||
|
// required: true
|
||||||
NewPassword string `json:"newPassword"`
|
NewPassword string `json:"newPassword"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rd *ChangePasswordData) IsValid() error {
|
// IsValid validates a password change request
|
||||||
|
func (rd *ChangePasswordRequest) IsValid() error {
|
||||||
if rd.OldPassword == "" {
|
if rd.OldPassword == "" {
|
||||||
return errors.New("Old password is required")
|
return errors.New("Old password is required")
|
||||||
}
|
}
|
||||||
@ -78,34 +124,62 @@ func isValidPassword(password string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleLogin(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation POST /api/v1/login login
|
||||||
|
//
|
||||||
|
// Login user
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// description: Login request
|
||||||
|
// required: true
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/LoginRequest"
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/LoginResponse"
|
||||||
|
// '401':
|
||||||
|
// description: invalid login
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
// '500':
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
if len(a.singleUserToken) > 0 {
|
if len(a.singleUserToken) > 0 {
|
||||||
// Not permitted in single-user mode
|
// Not permitted in single-user mode
|
||||||
errorResponse(w, http.StatusUnauthorized, nil, nil)
|
errorResponse(w, http.StatusUnauthorized, "", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
requestBody, err := ioutil.ReadAll(r.Body)
|
requestBody, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var loginData LoginData
|
var loginData LoginRequest
|
||||||
err = json.Unmarshal(requestBody, &loginData)
|
err = json.Unmarshal(requestBody, &loginData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if loginData.Type == "normal" {
|
if loginData.Type == "normal" {
|
||||||
token, err := a.app().Login(loginData.Username, loginData.Email, loginData.Password, loginData.MfaToken)
|
token, err := a.app().Login(loginData.Username, loginData.Email, loginData.Password, loginData.MfaToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}, err)
|
errorResponse(w, http.StatusUnauthorized, "incorrect login", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
json, err := json.Marshal(map[string]string{"token": token})
|
json, err := json.Marshal(LoginResponse{Token: token})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,26 +187,50 @@ func (a *API) handleLogin(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errorResponse(w, http.StatusInternalServerError, map[string]string{"error": "Unknown login type"}, nil)
|
errorResponse(w, http.StatusBadRequest, "invalid login type", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleRegister(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleRegister(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation POST /api/v1/register register
|
||||||
|
//
|
||||||
|
// Register new user
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// description: Register request
|
||||||
|
// required: true
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/RegisterRequest"
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// '401':
|
||||||
|
// description: invalid registration token
|
||||||
|
// '500':
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
if len(a.singleUserToken) > 0 {
|
if len(a.singleUserToken) > 0 {
|
||||||
// Not permitted in single-user mode
|
// Not permitted in single-user mode
|
||||||
errorResponse(w, http.StatusUnauthorized, nil, nil)
|
errorResponse(w, http.StatusUnauthorized, "", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
requestBody, err := ioutil.ReadAll(r.Body)
|
requestBody, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var registerData RegisterData
|
var registerData RegisterRequest
|
||||||
err = json.Unmarshal(requestBody, ®isterData)
|
err = json.Unmarshal(requestBody, ®isterData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,45 +238,78 @@ func (a *API) handleRegister(w http.ResponseWriter, r *http.Request) {
|
|||||||
if len(registerData.Token) > 0 {
|
if len(registerData.Token) > 0 {
|
||||||
workspace, err := a.app().GetRootWorkspace()
|
workspace, err := a.app().GetRootWorkspace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if registerData.Token != workspace.SignupToken {
|
if registerData.Token != workspace.SignupToken {
|
||||||
errorResponse(w, http.StatusUnauthorized, nil, nil)
|
errorResponse(w, http.StatusUnauthorized, "", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No signup token, check if no active users
|
// No signup token, check if no active users
|
||||||
userCount, err := a.app().GetRegisteredUserCount()
|
userCount, err := a.app().GetRegisteredUserCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if userCount > 0 {
|
if userCount > 0 {
|
||||||
errorResponse(w, http.StatusUnauthorized, nil, nil)
|
errorResponse(w, http.StatusUnauthorized, "", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = registerData.IsValid(); err != nil {
|
if err = registerData.IsValid(); err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}, err)
|
errorResponse(w, http.StatusBadRequest, err.Error(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.app().RegisterUser(registerData.Username, registerData.Email, registerData.Password)
|
err = a.app().RegisterUser(registerData.Username, registerData.Email, registerData.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}, err)
|
errorResponse(w, http.StatusBadRequest, err.Error(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBytesResponse(w, http.StatusOK, nil)
|
jsonStringResponse(w, http.StatusOK, "{}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleChangePassword(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleChangePassword(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:operation POST /api/v1/users/{userID}/changepassword changePassword
|
||||||
|
//
|
||||||
|
// Change a user's password
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: userID
|
||||||
|
// in: path
|
||||||
|
// description: User ID
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// description: Change password request
|
||||||
|
// required: true
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ChangePasswordRequest"
|
||||||
|
// security:
|
||||||
|
// - BearerAuth: []
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: success
|
||||||
|
// '400':
|
||||||
|
// description: invalid request
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
// '500':
|
||||||
|
// description: internal error
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
if len(a.singleUserToken) > 0 {
|
if len(a.singleUserToken) > 0 {
|
||||||
// Not permitted in single-user mode
|
// Not permitted in single-user mode
|
||||||
errorResponse(w, http.StatusUnauthorized, nil, nil)
|
errorResponse(w, http.StatusUnauthorized, "", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,27 +318,27 @@ func (a *API) handleChangePassword(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
requestBody, err := ioutil.ReadAll(r.Body)
|
requestBody, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var requestData ChangePasswordData
|
var requestData ChangePasswordRequest
|
||||||
if err := json.Unmarshal(requestBody, &requestData); err != nil {
|
if err := json.Unmarshal(requestBody, &requestData); err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, nil, err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = requestData.IsValid(); err != nil {
|
if err = requestData.IsValid(); err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}, err)
|
errorResponse(w, http.StatusBadRequest, err.Error(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.app().ChangePassword(userID, requestData.OldPassword, requestData.NewPassword); err != nil {
|
if err = a.app().ChangePassword(userID, requestData.OldPassword, requestData.NewPassword); err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}, err)
|
errorResponse(w, http.StatusBadRequest, err.Error(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBytesResponse(w, http.StatusOK, nil)
|
jsonStringResponse(w, http.StatusOK, "{}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) sessionRequired(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
func (a *API) sessionRequired(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -221,7 +352,7 @@ func (a *API) attachSession(handler func(w http.ResponseWriter, r *http.Request)
|
|||||||
log.Printf(`Single User: %v`, len(a.singleUserToken) > 0)
|
log.Printf(`Single User: %v`, len(a.singleUserToken) > 0)
|
||||||
if len(a.singleUserToken) > 0 {
|
if len(a.singleUserToken) > 0 {
|
||||||
if required && (token != a.singleUserToken) {
|
if required && (token != a.singleUserToken) {
|
||||||
errorResponse(w, http.StatusUnauthorized, nil, nil)
|
errorResponse(w, http.StatusUnauthorized, "", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +372,7 @@ func (a *API) attachSession(handler func(w http.ResponseWriter, r *http.Request)
|
|||||||
session, err := a.app().GetSession(token)
|
session, err := a.app().GetSession(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if required {
|
if required {
|
||||||
errorResponse(w, http.StatusUnauthorized, nil, err)
|
errorResponse(w, http.StatusUnauthorized, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +389,7 @@ func (a *API) adminRequired(handler func(w http.ResponseWriter, r *http.Request)
|
|||||||
// Currently, admin APIs require local unix connections
|
// Currently, admin APIs require local unix connections
|
||||||
conn := serverContext.GetContextConn(r)
|
conn := serverContext.GetContextConn(r)
|
||||||
if _, isUnix := conn.(*net.UnixConn); !isUnix {
|
if _, isUnix := conn.(*net.UnixConn); !isUnix {
|
||||||
errorResponse(w, http.StatusUnauthorized, nil, nil)
|
errorResponse(w, http.StatusUnauthorized, "", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,28 @@
|
|||||||
|
// Package classification Focalboard Server
|
||||||
|
//
|
||||||
|
// Server for Focalboard
|
||||||
|
//
|
||||||
|
// Schemes: http, https
|
||||||
|
// Host: localhost
|
||||||
|
// BasePath: /api/v1
|
||||||
|
// Version: 0.5.0
|
||||||
|
// License: Custom https://github.com/mattermost/focalboard/blob/main/LICENSE.txt
|
||||||
|
// Contact: Focalboard<api@focalboard.com> https://www.focalboard.com
|
||||||
|
//
|
||||||
|
// Consumes:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// Produces:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// securityDefinitions:
|
||||||
|
// BearerAuth:
|
||||||
|
// type: apiKey
|
||||||
|
// name: Authorization
|
||||||
|
// in: header
|
||||||
|
// description: 'Pass session token using Bearer authentication, e.g. set header "Authorization: Bearer <session token>"'
|
||||||
|
//
|
||||||
|
// swagger:meta
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -5,18 +5,51 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Block is the basic data unit.
|
// Block is the basic data unit
|
||||||
|
// swagger:model
|
||||||
type Block struct {
|
type Block struct {
|
||||||
|
// The id for this block
|
||||||
|
// required: true
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// The id for this block's parent block. Empty for root blocks
|
||||||
|
// required: false
|
||||||
ParentID string `json:"parentId"`
|
ParentID string `json:"parentId"`
|
||||||
|
|
||||||
|
// The id for this block's root block
|
||||||
|
// required: true
|
||||||
RootID string `json:"rootId"`
|
RootID string `json:"rootId"`
|
||||||
|
|
||||||
|
// The id for user who last modified this block
|
||||||
|
// required: true
|
||||||
ModifiedBy string `json:"modifiedBy"`
|
ModifiedBy string `json:"modifiedBy"`
|
||||||
|
|
||||||
|
// The schema version of this block
|
||||||
|
// required: true
|
||||||
Schema int64 `json:"schema"`
|
Schema int64 `json:"schema"`
|
||||||
|
|
||||||
|
// The block type
|
||||||
|
// required: true
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// The display title
|
||||||
|
// required: false
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
|
|
||||||
|
// The block fields
|
||||||
|
// required: false
|
||||||
Fields map[string]interface{} `json:"fields"`
|
Fields map[string]interface{} `json:"fields"`
|
||||||
|
|
||||||
|
// The creation time
|
||||||
|
// required: true
|
||||||
CreateAt int64 `json:"createAt"`
|
CreateAt int64 `json:"createAt"`
|
||||||
|
|
||||||
|
// The last modified time
|
||||||
|
// required: true
|
||||||
UpdateAt int64 `json:"updateAt"`
|
UpdateAt int64 `json:"updateAt"`
|
||||||
|
|
||||||
|
// The deleted time. Set to indicate this block is deleted
|
||||||
|
// required: false
|
||||||
DeleteAt int64 `json:"deleteAt"`
|
DeleteAt int64 `json:"deleteAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
server/model/errorResponse.go
Normal file
9
server/model/errorResponse.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// ErrorResponse is an error response
|
||||||
|
// swagger:model
|
||||||
|
type ErrorResponse struct {
|
||||||
|
// The error message
|
||||||
|
// required: false
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
@ -5,11 +5,27 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Sharing is sharing information for a root block
|
||||||
|
// swagger:model
|
||||||
type Sharing struct {
|
type Sharing struct {
|
||||||
|
// ID of the root block
|
||||||
|
// required: true
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// Is sharing enabled
|
||||||
|
// required: true
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
|
|
||||||
|
// Access token
|
||||||
|
// required: true
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
|
||||||
|
// ID of the user who last modified this
|
||||||
|
// required: true
|
||||||
ModifiedBy string `json:"modifiedBy"`
|
ModifiedBy string `json:"modifiedBy"`
|
||||||
|
|
||||||
|
// Updated time
|
||||||
|
// required: true
|
||||||
UpdateAt int64 `json:"update_at,omitempty"`
|
UpdateAt int64 `json:"update_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,46 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
// User is a user
|
||||||
|
// swagger:model
|
||||||
type User struct {
|
type User struct {
|
||||||
|
// The user ID
|
||||||
|
// required: true
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// The user name
|
||||||
|
// required: true
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
|
|
||||||
|
// The user's email
|
||||||
|
// required: true
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
|
||||||
|
// swagger:ignore
|
||||||
Password string `json:"-"`
|
Password string `json:"-"`
|
||||||
|
|
||||||
|
// swagger:ignore
|
||||||
MfaSecret string `json:"-"`
|
MfaSecret string `json:"-"`
|
||||||
|
|
||||||
|
// swagger:ignore
|
||||||
AuthService string `json:"-"`
|
AuthService string `json:"-"`
|
||||||
|
|
||||||
|
// swagger:ignore
|
||||||
AuthData string `json:"-"`
|
AuthData string `json:"-"`
|
||||||
|
|
||||||
|
// User settings
|
||||||
|
// required: true
|
||||||
Props map[string]interface{} `json:"props"`
|
Props map[string]interface{} `json:"props"`
|
||||||
|
|
||||||
|
// Created time
|
||||||
|
// required: true
|
||||||
CreateAt int64 `json:"create_at,omitempty"`
|
CreateAt int64 `json:"create_at,omitempty"`
|
||||||
|
|
||||||
|
// Updated time
|
||||||
|
// required: true
|
||||||
UpdateAt int64 `json:"update_at,omitempty"`
|
UpdateAt int64 `json:"update_at,omitempty"`
|
||||||
|
|
||||||
|
// Deleted time, set to indicate user is deleted
|
||||||
|
// required: true
|
||||||
DeleteAt int64 `json:"delete_at"`
|
DeleteAt int64 `json:"delete_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
// Workspace is information global to a workspace
|
||||||
|
// swagger:model
|
||||||
type Workspace struct {
|
type Workspace struct {
|
||||||
|
// ID of the workspace
|
||||||
|
// required: true
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// Token required to register new users
|
||||||
|
// required: true
|
||||||
SignupToken string `json:"signupToken"`
|
SignupToken string `json:"signupToken"`
|
||||||
|
|
||||||
|
// Workspace settings
|
||||||
|
// required: false
|
||||||
Settings map[string]interface{} `json:"settings"`
|
Settings map[string]interface{} `json:"settings"`
|
||||||
|
|
||||||
|
// ID of user who last modified this
|
||||||
|
// required: true
|
||||||
ModifiedBy string `json:"modifiedBy"`
|
ModifiedBy string `json:"modifiedBy"`
|
||||||
|
|
||||||
|
// Updated time
|
||||||
|
// required: true
|
||||||
UpdateAt int64 `json:"updateAt"`
|
UpdateAt int64 `json:"updateAt"`
|
||||||
}
|
}
|
||||||
|
14
server/swagger/README.md
Normal file
14
server/swagger/README.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Swagger / OpenAPI 2.0 auto-generated files
|
||||||
|
|
||||||
|
This folder is generated by the `make swagger` command from comments in the server code.
|
||||||
|
|
||||||
|
Prerequisites:
|
||||||
|
1. [go-swagger](https://goswagger.io/install.html)
|
||||||
|
2. [openapi-generator](https://github.com/OpenAPITools/openapi-generator)
|
||||||
|
|
||||||
|
These can be installed via Homebrew:
|
||||||
|
```
|
||||||
|
brew tap go-swagger/go-swagger
|
||||||
|
brew install go-swagger
|
||||||
|
brew install openapi-generator
|
||||||
|
```
|
23
server/swagger/docs/html/.openapi-generator-ignore
Normal file
23
server/swagger/docs/html/.openapi-generator-ignore
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# OpenAPI Generator Ignore
|
||||||
|
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||||
|
|
||||||
|
# Use this file to prevent files from being overwritten by the generator.
|
||||||
|
# The patterns follow closely to .gitignore or .dockerignore.
|
||||||
|
|
||||||
|
# As an example, the C# client generator defines ApiClient.cs.
|
||||||
|
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||||
|
#ApiClient.cs
|
||||||
|
|
||||||
|
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||||
|
#foo/*/qux
|
||||||
|
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||||
|
|
||||||
|
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||||
|
#foo/**/qux
|
||||||
|
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||||
|
|
||||||
|
# You can also negate patterns with an exclamation (!).
|
||||||
|
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||||
|
#docs/*.md
|
||||||
|
# Then explicitly reverse the ignore rule for a single file:
|
||||||
|
#!docs/README.md
|
1
server/swagger/docs/html/.openapi-generator/VERSION
Normal file
1
server/swagger/docs/html/.openapi-generator/VERSION
Normal file
@ -0,0 +1 @@
|
|||||||
|
5.0.1
|
10306
server/swagger/docs/html/index.html
Normal file
10306
server/swagger/docs/html/index.html
Normal file
File diff suppressed because one or more lines are too long
693
server/swagger/swagger.yml
Normal file
693
server/swagger/swagger.yml
Normal file
@ -0,0 +1,693 @@
|
|||||||
|
basePath: /api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
definitions:
|
||||||
|
Block:
|
||||||
|
description: Block is the basic data unit
|
||||||
|
properties:
|
||||||
|
createAt:
|
||||||
|
description: The creation time
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: CreateAt
|
||||||
|
deleteAt:
|
||||||
|
description: The deleted time. Set to indicate this block is deleted
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: DeleteAt
|
||||||
|
fields:
|
||||||
|
additionalProperties:
|
||||||
|
type: object
|
||||||
|
description: The block fields
|
||||||
|
type: object
|
||||||
|
x-go-name: Fields
|
||||||
|
id:
|
||||||
|
description: The id for this block
|
||||||
|
type: string
|
||||||
|
x-go-name: ID
|
||||||
|
modifiedBy:
|
||||||
|
description: The id for user who last modified this block
|
||||||
|
type: string
|
||||||
|
x-go-name: ModifiedBy
|
||||||
|
parentId:
|
||||||
|
description: The id for this block's parent block. Empty for root blocks
|
||||||
|
type: string
|
||||||
|
x-go-name: ParentID
|
||||||
|
rootId:
|
||||||
|
description: The id for this block's root block
|
||||||
|
type: string
|
||||||
|
x-go-name: RootID
|
||||||
|
schema:
|
||||||
|
description: The schema version of this block
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: Schema
|
||||||
|
title:
|
||||||
|
description: The display title
|
||||||
|
type: string
|
||||||
|
x-go-name: Title
|
||||||
|
type:
|
||||||
|
description: The block type
|
||||||
|
type: string
|
||||||
|
x-go-name: Type
|
||||||
|
updateAt:
|
||||||
|
description: The last modified time
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: UpdateAt
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- rootId
|
||||||
|
- modifiedBy
|
||||||
|
- schema
|
||||||
|
- type
|
||||||
|
- createAt
|
||||||
|
- updateAt
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/model
|
||||||
|
ChangePasswordRequest:
|
||||||
|
description: ChangePasswordRequest is a user password change request
|
||||||
|
properties:
|
||||||
|
newPassword:
|
||||||
|
description: New password
|
||||||
|
type: string
|
||||||
|
x-go-name: NewPassword
|
||||||
|
oldPassword:
|
||||||
|
description: Old password
|
||||||
|
type: string
|
||||||
|
x-go-name: OldPassword
|
||||||
|
required:
|
||||||
|
- oldPassword
|
||||||
|
- newPassword
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/api
|
||||||
|
ErrorResponse:
|
||||||
|
description: ErrorResponse is an error response
|
||||||
|
properties:
|
||||||
|
error:
|
||||||
|
description: The error message
|
||||||
|
type: string
|
||||||
|
x-go-name: Error
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/model
|
||||||
|
FileUploadResponse:
|
||||||
|
description: FileUploadResponse is the response to a file upload
|
||||||
|
properties:
|
||||||
|
url:
|
||||||
|
description: The URL to retrieve the uploaded file
|
||||||
|
type: string
|
||||||
|
x-go-name: URL
|
||||||
|
required:
|
||||||
|
- url
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/api
|
||||||
|
LoginRequest:
|
||||||
|
description: LoginRequest is a login request
|
||||||
|
properties:
|
||||||
|
email:
|
||||||
|
description: If specified, login using email
|
||||||
|
type: string
|
||||||
|
x-go-name: Email
|
||||||
|
password:
|
||||||
|
description: Password
|
||||||
|
type: string
|
||||||
|
x-go-name: Password
|
||||||
|
type:
|
||||||
|
description: Type of login, currently must be set to "normal"
|
||||||
|
type: string
|
||||||
|
x-go-name: Type
|
||||||
|
username:
|
||||||
|
description: If specified, login using username
|
||||||
|
type: string
|
||||||
|
x-go-name: Username
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
- password
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/api
|
||||||
|
LoginResponse:
|
||||||
|
description: LoginResponse is a login response
|
||||||
|
properties:
|
||||||
|
token:
|
||||||
|
description: Session token
|
||||||
|
type: string
|
||||||
|
x-go-name: Token
|
||||||
|
required:
|
||||||
|
- token
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/api
|
||||||
|
RegisterRequest:
|
||||||
|
description: RegisterRequest is a user registration request
|
||||||
|
properties:
|
||||||
|
email:
|
||||||
|
description: User's email
|
||||||
|
type: string
|
||||||
|
x-go-name: Email
|
||||||
|
password:
|
||||||
|
description: Password
|
||||||
|
type: string
|
||||||
|
x-go-name: Password
|
||||||
|
token:
|
||||||
|
description: Registration authorization token
|
||||||
|
type: string
|
||||||
|
x-go-name: Token
|
||||||
|
username:
|
||||||
|
description: User name
|
||||||
|
type: string
|
||||||
|
x-go-name: Username
|
||||||
|
required:
|
||||||
|
- username
|
||||||
|
- email
|
||||||
|
- password
|
||||||
|
- token
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/api
|
||||||
|
Sharing:
|
||||||
|
description: Sharing is sharing information for a root block
|
||||||
|
properties:
|
||||||
|
enabled:
|
||||||
|
description: Is sharing enabled
|
||||||
|
type: boolean
|
||||||
|
x-go-name: Enabled
|
||||||
|
id:
|
||||||
|
description: ID of the root block
|
||||||
|
type: string
|
||||||
|
x-go-name: ID
|
||||||
|
modifiedBy:
|
||||||
|
description: ID of the user who last modified this
|
||||||
|
type: string
|
||||||
|
x-go-name: ModifiedBy
|
||||||
|
token:
|
||||||
|
description: Access token
|
||||||
|
type: string
|
||||||
|
x-go-name: Token
|
||||||
|
update_at:
|
||||||
|
description: Updated time
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: UpdateAt
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- enabled
|
||||||
|
- token
|
||||||
|
- modifiedBy
|
||||||
|
- update_at
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/model
|
||||||
|
User:
|
||||||
|
description: User is a user
|
||||||
|
properties:
|
||||||
|
create_at:
|
||||||
|
description: Created time
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: CreateAt
|
||||||
|
delete_at:
|
||||||
|
description: Deleted time, set to indicate user is deleted
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: DeleteAt
|
||||||
|
email:
|
||||||
|
description: The user's email
|
||||||
|
type: string
|
||||||
|
x-go-name: Email
|
||||||
|
id:
|
||||||
|
description: The user ID
|
||||||
|
type: string
|
||||||
|
x-go-name: ID
|
||||||
|
props:
|
||||||
|
additionalProperties:
|
||||||
|
type: object
|
||||||
|
description: User settings
|
||||||
|
type: object
|
||||||
|
x-go-name: Props
|
||||||
|
update_at:
|
||||||
|
description: Updated time
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: UpdateAt
|
||||||
|
username:
|
||||||
|
description: The user name
|
||||||
|
type: string
|
||||||
|
x-go-name: Username
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- username
|
||||||
|
- email
|
||||||
|
- props
|
||||||
|
- create_at
|
||||||
|
- update_at
|
||||||
|
- delete_at
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/model
|
||||||
|
Workspace:
|
||||||
|
description: Workspace is information global to a workspace
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
description: ID of the workspace
|
||||||
|
type: string
|
||||||
|
x-go-name: ID
|
||||||
|
modifiedBy:
|
||||||
|
description: ID of user who last modified this
|
||||||
|
type: string
|
||||||
|
x-go-name: ModifiedBy
|
||||||
|
settings:
|
||||||
|
additionalProperties:
|
||||||
|
type: object
|
||||||
|
description: Workspace settings
|
||||||
|
type: object
|
||||||
|
x-go-name: Settings
|
||||||
|
signupToken:
|
||||||
|
description: Token required to register new users
|
||||||
|
type: string
|
||||||
|
x-go-name: SignupToken
|
||||||
|
updateAt:
|
||||||
|
description: Updated time
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
x-go-name: UpdateAt
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- signupToken
|
||||||
|
- modifiedBy
|
||||||
|
- updateAt
|
||||||
|
type: object
|
||||||
|
x-go-package: github.com/mattermost/focalboard/server/model
|
||||||
|
host: localhost
|
||||||
|
info:
|
||||||
|
contact:
|
||||||
|
email: api@focalboard.com
|
||||||
|
name: Focalboard
|
||||||
|
url: https://www.focalboard.com
|
||||||
|
description: Server for Focalboard
|
||||||
|
license:
|
||||||
|
name: Custom
|
||||||
|
url: https://github.com/mattermost/focalboard/blob/main/LICENSE.txt
|
||||||
|
title: Focalboard Server
|
||||||
|
version: 0.5.0
|
||||||
|
paths:
|
||||||
|
/api/v1/blocks:
|
||||||
|
get:
|
||||||
|
description: Returns blocks
|
||||||
|
operationId: getBlocks
|
||||||
|
parameters:
|
||||||
|
- description: ID of parent block, omit to specify all blocks
|
||||||
|
in: query
|
||||||
|
name: parent_id
|
||||||
|
type: string
|
||||||
|
- description: Type of blocks to return, omit to specify all types
|
||||||
|
in: query
|
||||||
|
name: type
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/Block'
|
||||||
|
type: array
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
post:
|
||||||
|
description: Insert or update blocks
|
||||||
|
operationId: updateBlocks
|
||||||
|
parameters:
|
||||||
|
- description: array of blocks to insert or update
|
||||||
|
in: body
|
||||||
|
name: Body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/Block'
|
||||||
|
type: array
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/blocks/{blockID}:
|
||||||
|
delete:
|
||||||
|
description: Deletes a block
|
||||||
|
operationId: deleteBlock
|
||||||
|
parameters:
|
||||||
|
- description: ID of block to delete
|
||||||
|
in: path
|
||||||
|
name: blockID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/blocks/{blockID}/subtree:
|
||||||
|
get:
|
||||||
|
description: Returns the blocks of a subtree
|
||||||
|
operationId: getSubTree
|
||||||
|
parameters:
|
||||||
|
- description: The ID of the root block of the subtree
|
||||||
|
in: path
|
||||||
|
name: blockID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: The number of levels to return. 2 or 3. Defaults to 2.
|
||||||
|
in: query
|
||||||
|
maximum: 3
|
||||||
|
minimum: 2
|
||||||
|
name: l
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/Block'
|
||||||
|
type: array
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/blocks/export:
|
||||||
|
get:
|
||||||
|
description: Returns all blocks
|
||||||
|
operationId: exportBlocks
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/Block'
|
||||||
|
type: array
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/blocks/import:
|
||||||
|
post:
|
||||||
|
description: Import blocks
|
||||||
|
operationId: importBlocks
|
||||||
|
parameters:
|
||||||
|
- description: array of blocks to import
|
||||||
|
in: body
|
||||||
|
name: Body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/Block'
|
||||||
|
type: array
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/files:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- multipart/form-data
|
||||||
|
description: Upload a binary file
|
||||||
|
operationId: uploadFile
|
||||||
|
parameters:
|
||||||
|
- description: The file to upload
|
||||||
|
in: formData
|
||||||
|
name: uploaded file
|
||||||
|
type: file
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/FileUploadResponse'
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/login:
|
||||||
|
post:
|
||||||
|
description: Login user
|
||||||
|
operationId: login
|
||||||
|
parameters:
|
||||||
|
- description: Login request
|
||||||
|
in: body
|
||||||
|
name: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/LoginRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/LoginResponse'
|
||||||
|
"401":
|
||||||
|
description: invalid login
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
"500":
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
/api/v1/register:
|
||||||
|
post:
|
||||||
|
description: Register new user
|
||||||
|
operationId: register
|
||||||
|
parameters:
|
||||||
|
- description: Register request
|
||||||
|
in: body
|
||||||
|
name: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/RegisterRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
"401":
|
||||||
|
description: invalid registration token
|
||||||
|
"500":
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
/api/v1/sharing/{rootID}:
|
||||||
|
get:
|
||||||
|
description: Returns sharing information for a root block
|
||||||
|
operationId: getSharing
|
||||||
|
parameters:
|
||||||
|
- description: ID of the root block
|
||||||
|
in: path
|
||||||
|
name: rootID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Sharing'
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
post:
|
||||||
|
description: Sets sharing information for a root block
|
||||||
|
operationId: postSharing
|
||||||
|
parameters:
|
||||||
|
- description: ID of the root block
|
||||||
|
in: path
|
||||||
|
name: rootID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: sharing information for a root block
|
||||||
|
in: body
|
||||||
|
name: Body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Sharing'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/users/{userID}:
|
||||||
|
get:
|
||||||
|
description: Returns a user
|
||||||
|
operationId: getUser
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: path
|
||||||
|
name: userID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/User'
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/users/{userID}/changepassword:
|
||||||
|
post:
|
||||||
|
description: Change a user's password
|
||||||
|
operationId: changePassword
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: path
|
||||||
|
name: userID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: Change password request
|
||||||
|
in: body
|
||||||
|
name: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ChangePasswordRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
"400":
|
||||||
|
description: invalid request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
"500":
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/users/me:
|
||||||
|
get:
|
||||||
|
description: Returns the currently logged-in user
|
||||||
|
operationId: getMe
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/User'
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/workspace:
|
||||||
|
get:
|
||||||
|
description: Returns information of the root workspace
|
||||||
|
operationId: getWorkspace
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Workspace'
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/api/v1/workspace/regenerate_signup_token:
|
||||||
|
post:
|
||||||
|
description: Regenerates the signup token for the root workspace
|
||||||
|
operationId: regenerateSignupToken
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
/files/{fileID}:
|
||||||
|
get:
|
||||||
|
description: Returns the contents of an uploaded file
|
||||||
|
operationId: getFile
|
||||||
|
parameters:
|
||||||
|
- description: ID of the file
|
||||||
|
in: path
|
||||||
|
name: fileID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
- image/jpg
|
||||||
|
- image/png
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
schemes:
|
||||||
|
- http
|
||||||
|
- https
|
||||||
|
securityDefinitions:
|
||||||
|
BearerAuth:
|
||||||
|
description: 'Pass session token using Bearer authentication, e.g. set header "Authorization: Bearer <session token>"'
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
type: apiKey
|
||||||
|
swagger: "2.0"
|
Loading…
x
Reference in New Issue
Block a user