1
0
mirror of https://github.com/mattermost/focalboard.git synced 2025-07-03 23:30:29 +02:00

Merge branch 'main' into private-templates

This commit is contained in:
Mattermod
2022-03-30 18:10:16 +03:00
committed by GitHub
112 changed files with 2931 additions and 1163 deletions

View File

@ -89,6 +89,7 @@ func (a *API) RegisterRoutes(r *mux.Router) {
apiv1.HandleFunc("/boards/{boardID}/blocks/{blockID}/undelete", a.sessionRequired(a.handleUndeleteBlock)).Methods("POST")
apiv1.HandleFunc("/boards/{boardID}/blocks/{blockID}/subtree", a.attachSession(a.handleGetSubTree, false)).Methods("GET")
apiv1.HandleFunc("/boards/{boardID}/blocks/{blockID}/duplicate", a.attachSession(a.handleDuplicateBlock, false)).Methods("POST")
apiv1.HandleFunc("/boards/{boardID}/metadata", a.sessionRequired(a.handleGetBoardMetadata)).Methods("GET")
// Import&Export APIs
apiv1.HandleFunc("/boards/{boardID}/blocks/export", a.sessionRequired(a.handleExport)).Methods("GET")
@ -99,6 +100,7 @@ func (a *API) RegisterRoutes(r *mux.Router) {
apiv1.HandleFunc("/boards/{boardID}/members", a.sessionRequired(a.handleAddMember)).Methods("POST")
apiv1.HandleFunc("/boards/{boardID}/members/{userID}", a.sessionRequired(a.handleUpdateMember)).Methods("PUT")
apiv1.HandleFunc("/boards/{boardID}/members/{userID}", a.sessionRequired(a.handleDeleteMember)).Methods("DELETE")
apiv1.HandleFunc("/boards/{boardID}/join", a.sessionRequired(a.handleJoinBoard)).Methods("POST")
// Sharing APIs
apiv1.HandleFunc("/boards/{boardID}/sharing", a.sessionRequired(a.handlePostSharing)).Methods("POST")
@ -2968,6 +2970,81 @@ func (a *API) handleDuplicateBlock(w http.ResponseWriter, r *http.Request) {
auditRec.Success()
}
func (a *API) handleGetBoardMetadata(w http.ResponseWriter, r *http.Request) {
// swagger:operation GET /api/v1/boards/{boardID}/metadata getBoardMetadata
//
// Returns a board's metadata
//
// ---
// produces:
// - application/json
// parameters:
// - name: boardID
// in: path
// description: Board ID
// required: true
// type: string
// security:
// - BearerAuth: []
// responses:
// '200':
// description: success
// schema:
// "$ref": "#/definitions/BoardMetadata"
// '404':
// description: board not found
// '501':
// description: required license not found
// default:
// description: internal error
// schema:
// "$ref": "#/definitions/ErrorResponse"
boardID := mux.Vars(r)["boardID"]
userID := getUserID(r)
board, boardMetadata, err := a.app.GetBoardMetadata(boardID)
if errors.Is(err, app.ErrInsufficientLicense) {
a.errorResponse(w, r.URL.Path, http.StatusNotImplemented, "", err)
return
}
if err != nil {
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
return
}
if board == nil || boardMetadata == nil {
a.errorResponse(w, r.URL.Path, http.StatusNotFound, "", nil)
return
}
if board.Type == model.BoardTypePrivate {
if !a.permissions.HasPermissionToBoard(userID, boardID, model.PermissionViewBoard) {
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", PermissionError{"access denied to board"})
return
}
} else {
if !a.permissions.HasPermissionToTeam(userID, board.TeamID, model.PermissionViewTeam) {
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", PermissionError{"access denied to board"})
return
}
}
auditRec := a.makeAuditRecord(r, "getBoardMetadata", audit.Fail)
defer a.audit.LogRecord(audit.LevelRead, auditRec)
auditRec.AddMeta("boardID", boardID)
data, err := json.Marshal(boardMetadata)
if err != nil {
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
return
}
// response
jsonBytesResponse(w, http.StatusOK, data)
auditRec.Success()
}
func (a *API) handleSearchBoards(w http.ResponseWriter, r *http.Request) {
// swagger:operation GET /api/v1/teams/{teamID}/boards/search searchBoards
//
@ -3214,6 +3291,98 @@ func (a *API) handleAddMember(w http.ResponseWriter, r *http.Request) {
auditRec.Success()
}
func (a *API) handleJoinBoard(w http.ResponseWriter, r *http.Request) {
// swagger:operation POST /boards/{boardID}/join joinBoard
//
// Become a member of a board
//
// ---
// produces:
// - application/json
// parameters:
// - name: boardID
// in: path
// description: Board ID
// required: true
// type: string
// security:
// - BearerAuth: []
// responses:
// '200':
// description: success
// schema:
// $ref: '#/definitions/BoardMember'
// '404':
// description: board not found
// '503':
// description: access denied
// default:
// description: internal error
// schema:
// "$ref": "#/definitions/ErrorResponse"
userID := getUserID(r)
if userID == "" {
a.errorResponse(w, r.URL.Path, http.StatusBadRequest, "", nil)
return
}
boardID := mux.Vars(r)["boardID"]
board, err := a.app.GetBoard(boardID)
if err != nil {
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
return
}
if board == nil {
a.errorResponse(w, r.URL.Path, http.StatusNotFound, "", nil)
return
}
if board.Type != model.BoardTypeOpen {
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", nil)
return
}
if !a.permissions.HasPermissionToTeam(userID, board.TeamID, model.PermissionViewTeam) {
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", nil)
return
}
// currently all memberships are created as editors by default
// TODO: Support different public roles
newBoardMember := &model.BoardMember{
UserID: userID,
BoardID: boardID,
SchemeEditor: true,
}
auditRec := a.makeAuditRecord(r, "joinBoard", audit.Fail)
defer a.audit.LogRecord(audit.LevelModify, auditRec)
auditRec.AddMeta("boardID", boardID)
auditRec.AddMeta("addedUserID", userID)
member, err := a.app.AddMemberToBoard(newBoardMember)
if err != nil {
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
return
}
a.logger.Debug("AddMember",
mlog.String("boardID", board.ID),
mlog.String("addedUserID", userID),
)
data, err := json.Marshal(member)
if err != nil {
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
return
}
// response
jsonBytesResponse(w, http.StatusOK, data)
auditRec.Success()
}
func (a *API) handleUpdateMember(w http.ResponseWriter, r *http.Request) {
// swagger:operation PUT /boards/{boardID}/members/{userID} updateMember
//