Adding the board default role for public boards (#2884)
* Adding the default role concept in the backend * Adding the interface part * Fix golang-ci lint errors * Adding local permissions tests * Address PR review comments * Improving the code a bit * Another small fix * Renaming DefaultRole to MinimumRole * Setting the minimum role at minimum to check the permissions per roles in the integration tests * Adding the new minimum role behavior * Fixing some tests Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
This commit is contained in:
parent
11bd3720f1
commit
d3edf2f698
12 changed files with 504 additions and 36 deletions
|
@ -2759,7 +2759,7 @@ func (a *API) handlePatchBoard(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if patch.Type != nil {
|
||||
if patch.Type != nil || patch.MinimumRole != nil {
|
||||
if !a.permissions.HasPermissionToBoard(userID, boardID, model.PermissionManageBoardType) {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", PermissionError{"access denied to modifying board type"})
|
||||
return
|
||||
|
@ -3429,12 +3429,13 @@ func (a *API) handleJoinBoard(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// currently all memberships are created as editors by default
|
||||
// TODO: Support different public roles
|
||||
newBoardMember := &model.BoardMember{
|
||||
UserID: userID,
|
||||
BoardID: boardID,
|
||||
SchemeEditor: true,
|
||||
UserID: userID,
|
||||
BoardID: boardID,
|
||||
SchemeAdmin: board.MinimumRole == model.BoardRoleAdmin,
|
||||
SchemeEditor: board.MinimumRole == model.BoardRoleNone || board.MinimumRole == model.BoardRoleEditor,
|
||||
SchemeCommenter: board.MinimumRole == model.BoardRoleCommenter,
|
||||
SchemeViewer: board.MinimumRole == model.BoardRoleViewer,
|
||||
}
|
||||
|
||||
auditRec := a.makeAuditRecord(r, "joinBoard", audit.Fail)
|
||||
|
@ -3922,7 +3923,7 @@ func (a *API) handlePatchBoardsAndBlocks(w http.ResponseWriter, r *http.Request)
|
|||
return
|
||||
}
|
||||
|
||||
if patch.Type != nil {
|
||||
if patch.Type != nil || patch.MinimumRole != nil {
|
||||
if !a.permissions.HasPermissionToBoard(userID, boardID, model.PermissionManageBoardType) {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusForbidden, "", PermissionError{"access denied to modifying board type"})
|
||||
return
|
||||
|
|
|
@ -1945,7 +1945,83 @@ func TestJoinBoard(t *testing.T) {
|
|||
|
||||
me := th.GetUser1()
|
||||
|
||||
title := "Public board"
|
||||
title := "Test Public board"
|
||||
teamID := testTeamID
|
||||
newBoard := &model.Board{
|
||||
Title: title,
|
||||
Type: model.BoardTypeOpen,
|
||||
TeamID: teamID,
|
||||
}
|
||||
board, resp := th.Client.CreateBoard(newBoard)
|
||||
th.CheckOK(resp)
|
||||
require.NoError(t, resp.Error)
|
||||
require.NotNil(t, board)
|
||||
require.NotNil(t, board.ID)
|
||||
require.Equal(t, title, board.Title)
|
||||
require.Equal(t, model.BoardTypeOpen, board.Type)
|
||||
require.Equal(t, teamID, board.TeamID)
|
||||
require.Equal(t, me.ID, board.CreatedBy)
|
||||
require.Equal(t, me.ID, board.ModifiedBy)
|
||||
require.Equal(t, model.BoardRoleNone, board.MinimumRole)
|
||||
|
||||
member, resp := th.Client2.JoinBoard(board.ID)
|
||||
th.CheckOK(resp)
|
||||
require.NoError(t, resp.Error)
|
||||
require.NotNil(t, member)
|
||||
require.Equal(t, board.ID, member.BoardID)
|
||||
require.Equal(t, th.GetUser2().ID, member.UserID)
|
||||
|
||||
s, _ := json.MarshalIndent(member, "", "\t")
|
||||
t.Log(string(s))
|
||||
})
|
||||
|
||||
t.Run("create and join public board should match the minimumRole in the membership", func(t *testing.T) {
|
||||
th := SetupTestHelper(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
me := th.GetUser1()
|
||||
|
||||
title := "Public board for commenters"
|
||||
teamID := testTeamID
|
||||
newBoard := &model.Board{
|
||||
Title: title,
|
||||
Type: model.BoardTypeOpen,
|
||||
TeamID: teamID,
|
||||
MinimumRole: model.BoardRoleCommenter,
|
||||
}
|
||||
board, resp := th.Client.CreateBoard(newBoard)
|
||||
th.CheckOK(resp)
|
||||
require.NoError(t, resp.Error)
|
||||
require.NotNil(t, board)
|
||||
require.NotNil(t, board.ID)
|
||||
require.Equal(t, title, board.Title)
|
||||
require.Equal(t, model.BoardTypeOpen, board.Type)
|
||||
require.Equal(t, teamID, board.TeamID)
|
||||
require.Equal(t, me.ID, board.CreatedBy)
|
||||
require.Equal(t, me.ID, board.ModifiedBy)
|
||||
|
||||
member, resp := th.Client2.JoinBoard(board.ID)
|
||||
th.CheckOK(resp)
|
||||
require.NoError(t, resp.Error)
|
||||
require.NotNil(t, member)
|
||||
require.Equal(t, board.ID, member.BoardID)
|
||||
require.Equal(t, th.GetUser2().ID, member.UserID)
|
||||
require.False(t, member.SchemeAdmin, "new member should not be admin")
|
||||
require.False(t, member.SchemeEditor, "new member should not be editor")
|
||||
require.True(t, member.SchemeCommenter, "new member should be commenter")
|
||||
require.False(t, member.SchemeViewer, "new member should not be viewer")
|
||||
|
||||
s, _ := json.MarshalIndent(member, "", "\t")
|
||||
t.Log(string(s))
|
||||
})
|
||||
|
||||
t.Run("create and join public board should match editor role in the membership when MinimumRole is empty", func(t *testing.T) {
|
||||
th := SetupTestHelper(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
me := th.GetUser1()
|
||||
|
||||
title := "Public board for editors"
|
||||
teamID := testTeamID
|
||||
newBoard := &model.Board{
|
||||
Title: title,
|
||||
|
@ -1969,6 +2045,10 @@ func TestJoinBoard(t *testing.T) {
|
|||
require.NotNil(t, member)
|
||||
require.Equal(t, board.ID, member.BoardID)
|
||||
require.Equal(t, th.GetUser2().ID, member.UserID)
|
||||
require.False(t, member.SchemeAdmin, "new member should not be admin")
|
||||
require.True(t, member.SchemeEditor, "new member should be editor")
|
||||
require.False(t, member.SchemeCommenter, "new member should not be commenter")
|
||||
require.False(t, member.SchemeViewer, "new member should not be viewer")
|
||||
|
||||
s, _ := json.MarshalIndent(member, "", "\t")
|
||||
t.Log(string(s))
|
||||
|
|
|
@ -129,23 +129,27 @@ type TestData struct {
|
|||
}
|
||||
|
||||
func setupData(t *testing.T, th *TestHelper) TestData {
|
||||
customTemplate1, err := th.Server.App().CreateBoard(&model.Board{Title: "Custom template 1", TeamID: "test-team", IsTemplate: true, Type: model.BoardTypeOpen}, userAdminID, true)
|
||||
customTemplate1, err := th.Server.App().CreateBoard(
|
||||
&model.Board{Title: "Custom template 1", TeamID: "test-team", IsTemplate: true, Type: model.BoardTypeOpen, MinimumRole: "viewer"},
|
||||
userAdminID,
|
||||
true,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
err = th.Server.App().InsertBlock(model.Block{ID: "block-1", Title: "Test", Type: "card", BoardID: customTemplate1.ID}, userAdminID)
|
||||
require.NoError(t, err)
|
||||
customTemplate2, err := th.Server.App().CreateBoard(
|
||||
&model.Board{Title: "Custom template 2", TeamID: "test-team", IsTemplate: true, Type: model.BoardTypePrivate},
|
||||
&model.Board{Title: "Custom template 2", TeamID: "test-team", IsTemplate: true, Type: model.BoardTypePrivate, MinimumRole: "viewer"},
|
||||
userAdminID,
|
||||
true)
|
||||
require.NoError(t, err)
|
||||
err = th.Server.App().InsertBlock(model.Block{ID: "block-2", Title: "Test", Type: "card", BoardID: customTemplate2.ID}, userAdminID)
|
||||
require.NoError(t, err)
|
||||
|
||||
board1, err := th.Server.App().CreateBoard(&model.Board{Title: "Board 1", TeamID: "test-team", Type: model.BoardTypeOpen}, userAdminID, true)
|
||||
board1, err := th.Server.App().CreateBoard(&model.Board{Title: "Board 1", TeamID: "test-team", Type: model.BoardTypeOpen, MinimumRole: "viewer"}, userAdminID, true)
|
||||
require.NoError(t, err)
|
||||
err = th.Server.App().InsertBlock(model.Block{ID: "block-3", Title: "Test", Type: "card", BoardID: board1.ID}, userAdminID)
|
||||
require.NoError(t, err)
|
||||
board2, err := th.Server.App().CreateBoard(&model.Board{Title: "Board 2", TeamID: "test-team", Type: model.BoardTypePrivate}, userAdminID, true)
|
||||
board2, err := th.Server.App().CreateBoard(&model.Board{Title: "Board 2", TeamID: "test-team", Type: model.BoardTypePrivate, MinimumRole: "viewer"}, userAdminID, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
rBoard2, err := th.Server.App().GetBoard(board2.ID)
|
||||
|
@ -558,6 +562,109 @@ func TestPermissionsPatchBoard(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestPermissionsPatchBoardType(t *testing.T) {
|
||||
ttCases := []TestCase{
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userEditor, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userEditor, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, "{\"type\": \"P\"}", userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userEditor, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userEditor, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, "{\"type\": \"P\"}", userAdmin, http.StatusOK, 1},
|
||||
}
|
||||
|
||||
t.Run("plugin", func(t *testing.T) {
|
||||
th := SetupTestHelperPluginMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupClients(th)
|
||||
testData := setupData(t, th)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
t.Run("local", func(t *testing.T) {
|
||||
th := SetupTestHelperLocalMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupLocalClients(th)
|
||||
testData := setupData(t, th)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPermissionsPatchBoardMinimumRole(t *testing.T) {
|
||||
patch := toJSON(t, map[string]model.BoardRole{"minimumRole": model.BoardRoleViewer})
|
||||
ttCases := []TestCase{
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, patch, userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, patch, userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, patch, userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, patch, userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, patch, userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, patch, userEditor, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodPatch, patch, userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, patch, userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, patch, userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, patch, userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, patch, userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, patch, userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, patch, userEditor, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}", methodPatch, patch, userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, patch, userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, patch, userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, patch, userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, patch, userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, patch, userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, patch, userEditor, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}", methodPatch, patch, userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, patch, userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, patch, userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, patch, userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, patch, userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, patch, userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, patch, userEditor, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}", methodPatch, patch, userAdmin, http.StatusOK, 1},
|
||||
}
|
||||
|
||||
t.Run("plugin", func(t *testing.T) {
|
||||
th := SetupTestHelperPluginMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupClients(th)
|
||||
testData := setupData(t, th)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
t.Run("local", func(t *testing.T) {
|
||||
th := SetupTestHelperLocalMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupLocalClients(th)
|
||||
testData := setupData(t, th)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPermissionsDeleteBoard(t *testing.T) {
|
||||
ttCases := []TestCase{
|
||||
{"/boards/{PRIVATE_BOARD_ID}", methodDelete, "", userAnon, http.StatusUnauthorized, 0},
|
||||
|
@ -3095,3 +3202,167 @@ func TestPermissionsBoardArchiveImport(t *testing.T) {
|
|||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPermissionsMinimumRolesApplied(t *testing.T) {
|
||||
ttCasesF := func(t *testing.T, th *TestHelper, minimumRole model.BoardRole, testData TestData) []TestCase {
|
||||
counter := 0
|
||||
newBlockJSON := func(boardID string) string {
|
||||
counter++
|
||||
return toJSON(t, []*model.Block{{
|
||||
ID: fmt.Sprintf("%d", counter),
|
||||
Title: "Board To Create",
|
||||
BoardID: boardID,
|
||||
Type: "card",
|
||||
CreateAt: model.GetMillis(),
|
||||
UpdateAt: model.GetMillis(),
|
||||
}})
|
||||
}
|
||||
_, err := th.Server.App().PatchBoard(&model.BoardPatch{MinimumRole: &minimumRole}, testData.privateBoard.ID, userAdminID)
|
||||
require.NoError(t, err)
|
||||
_, err = th.Server.App().PatchBoard(&model.BoardPatch{MinimumRole: &minimumRole}, testData.publicBoard.ID, userAdminID)
|
||||
require.NoError(t, err)
|
||||
_, err = th.Server.App().PatchBoard(&model.BoardPatch{MinimumRole: &minimumRole}, testData.privateTemplate.ID, userAdminID)
|
||||
require.NoError(t, err)
|
||||
_, err = th.Server.App().PatchBoard(&model.BoardPatch{MinimumRole: &minimumRole}, testData.publicTemplate.ID, userAdminID)
|
||||
require.NoError(t, err)
|
||||
|
||||
if minimumRole == "viewer" || minimumRole == "commenter" {
|
||||
return []TestCase{
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userEditor, http.StatusOK, 1},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userEditor, http.StatusOK, 1},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userEditor, http.StatusOK, 1},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userViewer, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userCommenter, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userEditor, http.StatusOK, 1},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userAdmin, http.StatusOK, 1},
|
||||
}
|
||||
} else {
|
||||
return []TestCase{
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userViewer, http.StatusOK, 1},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userCommenter, http.StatusOK, 1},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userEditor, http.StatusOK, 1},
|
||||
{"/boards/{PRIVATE_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.privateBoard.ID), userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userViewer, http.StatusOK, 1},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userCommenter, http.StatusOK, 1},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userEditor, http.StatusOK, 1},
|
||||
{"/boards/{PUBLIC_BOARD_ID}/blocks", methodPost, newBlockJSON(testData.publicBoard.ID), userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userViewer, http.StatusOK, 1},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userCommenter, http.StatusOK, 1},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userEditor, http.StatusOK, 1},
|
||||
{"/boards/{PRIVATE_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.privateTemplate.ID), userAdmin, http.StatusOK, 1},
|
||||
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userAnon, http.StatusUnauthorized, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userNoTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userTeamMember, http.StatusForbidden, 0},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userViewer, http.StatusOK, 1},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userCommenter, http.StatusOK, 1},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userEditor, http.StatusOK, 1},
|
||||
{"/boards/{PUBLIC_TEMPLATE_ID}/blocks", methodPost, newBlockJSON(testData.publicTemplate.ID), userAdmin, http.StatusOK, 1},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("plugin", func(t *testing.T) {
|
||||
t.Run("minimum role viewer", func(t *testing.T) {
|
||||
th := SetupTestHelperPluginMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupClients(th)
|
||||
testData := setupData(t, th)
|
||||
ttCases := ttCasesF(t, th, "viewer", testData)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
t.Run("minimum role commenter", func(t *testing.T) {
|
||||
th := SetupTestHelperPluginMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupClients(th)
|
||||
testData := setupData(t, th)
|
||||
ttCases := ttCasesF(t, th, "commenter", testData)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
t.Run("minimum role editor", func(t *testing.T) {
|
||||
th := SetupTestHelperPluginMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupClients(th)
|
||||
testData := setupData(t, th)
|
||||
ttCases := ttCasesF(t, th, "editor", testData)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
t.Run("minimum role admin", func(t *testing.T) {
|
||||
th := SetupTestHelperPluginMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupClients(th)
|
||||
testData := setupData(t, th)
|
||||
ttCases := ttCasesF(t, th, "admin", testData)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
})
|
||||
t.Run("local", func(t *testing.T) {
|
||||
t.Run("minimum role viewer", func(t *testing.T) {
|
||||
th := SetupTestHelperLocalMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupLocalClients(th)
|
||||
testData := setupData(t, th)
|
||||
ttCases := ttCasesF(t, th, "viewer", testData)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
t.Run("minimum role commenter", func(t *testing.T) {
|
||||
th := SetupTestHelperLocalMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupLocalClients(th)
|
||||
testData := setupData(t, th)
|
||||
ttCases := ttCasesF(t, th, "commenter", testData)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
t.Run("minimum role editor", func(t *testing.T) {
|
||||
th := SetupTestHelperLocalMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupLocalClients(th)
|
||||
testData := setupData(t, th)
|
||||
ttCases := ttCasesF(t, th, "editor", testData)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
t.Run("minimum role admin", func(t *testing.T) {
|
||||
th := SetupTestHelperLocalMode(t)
|
||||
defer th.TearDown()
|
||||
clients := setupLocalClients(th)
|
||||
testData := setupData(t, th)
|
||||
ttCases := ttCasesF(t, th, "admin", testData)
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,12 +7,21 @@ import (
|
|||
)
|
||||
|
||||
type BoardType string
|
||||
type BoardRole string
|
||||
|
||||
const (
|
||||
BoardTypeOpen BoardType = "O"
|
||||
BoardTypePrivate BoardType = "P"
|
||||
)
|
||||
|
||||
const (
|
||||
BoardRoleNone BoardRole = ""
|
||||
BoardRoleViewer BoardRole = "viewer"
|
||||
BoardRoleCommenter BoardRole = "commenter"
|
||||
BoardRoleEditor BoardRole = "editor"
|
||||
BoardRoleAdmin BoardRole = "admin"
|
||||
)
|
||||
|
||||
// Board groups a set of blocks and its layout
|
||||
// swagger:model
|
||||
type Board struct {
|
||||
|
@ -40,6 +49,10 @@ type Board struct {
|
|||
// required: true
|
||||
Type BoardType `json:"type"`
|
||||
|
||||
// The minimum role applied when somebody joins the board
|
||||
// required: true
|
||||
MinimumRole BoardRole `json:"minimumRole"`
|
||||
|
||||
// The title of the board
|
||||
// required: false
|
||||
Title string `json:"title"`
|
||||
|
@ -92,6 +105,10 @@ type BoardPatch struct {
|
|||
// required: false
|
||||
Type *BoardType `json:"type"`
|
||||
|
||||
// The minimum role applied when somebody joins the board
|
||||
// required: false
|
||||
MinimumRole *BoardRole `json:"minimumRole"`
|
||||
|
||||
// The title of the board
|
||||
// required: false
|
||||
Title *string `json:"title"`
|
||||
|
@ -140,6 +157,10 @@ type BoardMember struct {
|
|||
// required: false
|
||||
Roles string `json:"roles"`
|
||||
|
||||
// Minimum role because the board configuration
|
||||
// required: false
|
||||
MinimumRole string `json:"minimumRole"`
|
||||
|
||||
// Marks the user as an admin of the board
|
||||
// required: true
|
||||
SchemeAdmin bool `json:"schemeAdmin"`
|
||||
|
@ -221,6 +242,10 @@ func (p *BoardPatch) Patch(board *Board) *Board {
|
|||
board.Title = *p.Title
|
||||
}
|
||||
|
||||
if p.MinimumRole != nil {
|
||||
board.MinimumRole = *p.MinimumRole
|
||||
}
|
||||
|
||||
if p.Description != nil {
|
||||
board.Description = *p.Description
|
||||
}
|
||||
|
@ -296,11 +321,19 @@ func IsBoardTypeValid(t BoardType) bool {
|
|||
return t == BoardTypeOpen || t == BoardTypePrivate
|
||||
}
|
||||
|
||||
func IsBoardMinimumRoleValid(r BoardRole) bool {
|
||||
return r == BoardRoleNone || r == BoardRoleAdmin || r == BoardRoleEditor || r == BoardRoleCommenter || r == BoardRoleViewer
|
||||
}
|
||||
|
||||
func (p *BoardPatch) IsValid() error {
|
||||
if p.Type != nil && !IsBoardTypeValid(*p.Type) {
|
||||
return InvalidBoardErr{"invalid-board-type"}
|
||||
}
|
||||
|
||||
if p.MinimumRole != nil && !IsBoardMinimumRoleValid(*p.MinimumRole) {
|
||||
return InvalidBoardErr{"invalid-board-minimum-role"}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -320,6 +353,11 @@ func (b *Board) IsValid() error {
|
|||
if !IsBoardTypeValid(b.Type) {
|
||||
return InvalidBoardErr{"invalid-board-type"}
|
||||
}
|
||||
|
||||
if !IsBoardMinimumRoleValid(b.MinimumRole) {
|
||||
return InvalidBoardErr{"invalid-board-minimum-role"}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,17 @@ func (s *Service) HasPermissionToBoard(userID, boardID string, permission *mmMod
|
|||
return false
|
||||
}
|
||||
|
||||
switch member.MinimumRole {
|
||||
case "admin":
|
||||
member.SchemeAdmin = true
|
||||
case "editor":
|
||||
member.SchemeEditor = true
|
||||
case "commenter":
|
||||
member.SchemeCommenter = true
|
||||
case "viewer":
|
||||
member.SchemeViewer = true
|
||||
}
|
||||
|
||||
switch permission {
|
||||
case model.PermissionManageBoardType, model.PermissionDeleteBoard, model.PermissionManageBoardRoles, model.PermissionShareBoard:
|
||||
return member.SchemeAdmin
|
||||
|
|
|
@ -78,6 +78,17 @@ func (s *Service) HasPermissionToBoard(userID, boardID string, permission *mmMod
|
|||
return false
|
||||
}
|
||||
|
||||
switch member.MinimumRole {
|
||||
case "admin":
|
||||
member.SchemeAdmin = true
|
||||
case "editor":
|
||||
member.SchemeEditor = true
|
||||
case "commenter":
|
||||
member.SchemeCommenter = true
|
||||
case "viewer":
|
||||
member.SchemeViewer = true
|
||||
}
|
||||
|
||||
switch permission {
|
||||
case model.PermissionManageBoardType, model.PermissionDeleteBoard, model.PermissionManageBoardRoles, model.PermissionShareBoard:
|
||||
return member.SchemeAdmin
|
||||
|
|
|
@ -31,6 +31,7 @@ func boardFields(prefix string) []string {
|
|||
"COALESCE(created_by, '')",
|
||||
"modified_by",
|
||||
"type",
|
||||
"minimum_role",
|
||||
"title",
|
||||
"description",
|
||||
"icon",
|
||||
|
@ -67,6 +68,7 @@ func boardHistoryFields() []string {
|
|||
"COALESCE(created_by, '')",
|
||||
"COALESCE(modified_by, '')",
|
||||
"type",
|
||||
"minimum_role",
|
||||
"COALESCE(title, '')",
|
||||
"COALESCE(description, '')",
|
||||
"COALESCE(icon, '')",
|
||||
|
@ -84,13 +86,14 @@ func boardHistoryFields() []string {
|
|||
}
|
||||
|
||||
var boardMemberFields = []string{
|
||||
"board_id",
|
||||
"user_id",
|
||||
"roles",
|
||||
"scheme_admin",
|
||||
"scheme_editor",
|
||||
"scheme_commenter",
|
||||
"scheme_viewer",
|
||||
"COALESCE(B.minimum_role, '')",
|
||||
"BM.board_id",
|
||||
"BM.user_id",
|
||||
"BM.roles",
|
||||
"BM.scheme_admin",
|
||||
"BM.scheme_editor",
|
||||
"BM.scheme_commenter",
|
||||
"BM.scheme_viewer",
|
||||
}
|
||||
|
||||
func (s *SQLStore) boardsFromRows(rows *sql.Rows) ([]*model.Board, error) {
|
||||
|
@ -108,6 +111,7 @@ func (s *SQLStore) boardsFromRows(rows *sql.Rows) ([]*model.Board, error) {
|
|||
&board.CreatedBy,
|
||||
&board.ModifiedBy,
|
||||
&board.Type,
|
||||
&board.MinimumRole,
|
||||
&board.Title,
|
||||
&board.Description,
|
||||
&board.Icon,
|
||||
|
@ -149,6 +153,7 @@ func (s *SQLStore) boardMembersFromRows(rows *sql.Rows) ([]*model.BoardMember, e
|
|||
var boardMember model.BoardMember
|
||||
|
||||
err := rows.Scan(
|
||||
&boardMember.MinimumRole,
|
||||
&boardMember.BoardID,
|
||||
&boardMember.UserID,
|
||||
&boardMember.Roles,
|
||||
|
@ -308,6 +313,7 @@ func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID stri
|
|||
"modified_by": userID,
|
||||
"type": board.Type,
|
||||
"title": board.Title,
|
||||
"minimum_role": board.MinimumRole,
|
||||
"description": board.Description,
|
||||
"icon": board.Icon,
|
||||
"show_description": board.ShowDescription,
|
||||
|
@ -325,6 +331,7 @@ func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID stri
|
|||
Where(sq.Eq{"id": board.ID}).
|
||||
Set("modified_by", userID).
|
||||
Set("type", board.Type).
|
||||
Set("minimum_role", board.MinimumRole).
|
||||
Set("title", board.Title).
|
||||
Set("description", board.Description).
|
||||
Set("icon", board.Icon).
|
||||
|
@ -398,6 +405,7 @@ func (s *SQLStore) deleteBoard(db sq.BaseRunner, boardID, userID string) error {
|
|||
"created_by": board.CreatedBy,
|
||||
"modified_by": userID,
|
||||
"type": board.Type,
|
||||
"minimum_role": board.MinimumRole,
|
||||
"title": board.Title,
|
||||
"description": board.Description,
|
||||
"icon": board.Icon,
|
||||
|
@ -536,9 +544,10 @@ func (s *SQLStore) deleteMember(db sq.BaseRunner, boardID, userID string) error
|
|||
func (s *SQLStore) getMemberForBoard(db sq.BaseRunner, boardID, userID string) (*model.BoardMember, error) {
|
||||
query := s.getQueryBuilder(db).
|
||||
Select(boardMemberFields...).
|
||||
From(s.tablePrefix + "board_members").
|
||||
Where(sq.Eq{"board_id": boardID}).
|
||||
Where(sq.Eq{"user_id": userID})
|
||||
From(s.tablePrefix + "board_members AS BM").
|
||||
LeftJoin(s.tablePrefix + "boards AS B ON B.id=BM.board_id").
|
||||
Where(sq.Eq{"BM.board_id": boardID}).
|
||||
Where(sq.Eq{"BM.user_id": userID})
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
|
@ -562,8 +571,9 @@ func (s *SQLStore) getMemberForBoard(db sq.BaseRunner, boardID, userID string) (
|
|||
func (s *SQLStore) getMembersForUser(db sq.BaseRunner, userID string) ([]*model.BoardMember, error) {
|
||||
query := s.getQueryBuilder(db).
|
||||
Select(boardMemberFields...).
|
||||
From(s.tablePrefix + "board_members").
|
||||
Where(sq.Eq{"user_id": userID})
|
||||
From(s.tablePrefix + "board_members AS BM").
|
||||
LeftJoin(s.tablePrefix + "boards AS B ON B.id=BM.board_id").
|
||||
Where(sq.Eq{"BM.user_id": userID})
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
|
@ -583,8 +593,9 @@ func (s *SQLStore) getMembersForUser(db sq.BaseRunner, userID string) ([]*model.
|
|||
func (s *SQLStore) getMembersForBoard(db sq.BaseRunner, boardID string) ([]*model.BoardMember, error) {
|
||||
query := s.getQueryBuilder(db).
|
||||
Select(boardMemberFields...).
|
||||
From(s.tablePrefix + "board_members").
|
||||
Where(sq.Eq{"board_id": boardID})
|
||||
From(s.tablePrefix + "board_members AS BM").
|
||||
LeftJoin(s.tablePrefix + "boards AS B ON B.id=BM.board_id").
|
||||
Where(sq.Eq{"BM.board_id": boardID})
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
|
@ -711,6 +722,7 @@ func (s *SQLStore) undeleteBoard(db sq.BaseRunner, boardID string, modifiedBy st
|
|||
"modified_by",
|
||||
"type",
|
||||
"title",
|
||||
"minimum_role",
|
||||
"description",
|
||||
"icon",
|
||||
"show_description",
|
||||
|
@ -730,6 +742,7 @@ func (s *SQLStore) undeleteBoard(db sq.BaseRunner, boardID string, modifiedBy st
|
|||
board.CreatedBy,
|
||||
modifiedBy,
|
||||
board.Type,
|
||||
board.MinimumRole,
|
||||
board.Title,
|
||||
board.Description,
|
||||
board.Icon,
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE {{.prefix}}boards DROP COLUMN minimum_role;
|
||||
ALTER TABLE {{.prefix}}boards_history DROP COLUMN minimum_role;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE {{.prefix}}boards ADD COLUMN minimum_role VARCHAR(36) NOT NULL DEFAULT '';
|
||||
ALTER TABLE {{.prefix}}boards_history ADD COLUMN minimum_role VARCHAR(36) NOT NULL DEFAULT '';
|
||||
UPDATE {{.prefix}}boards SET minimum_role = 'editor';
|
||||
UPDATE {{.prefix}}boards_history SET minimum_role = 'editor';
|
|
@ -20,6 +20,7 @@ type Board = {
|
|||
createdBy: string
|
||||
modifiedBy: string
|
||||
type: BoardTypes
|
||||
minimumRole: string
|
||||
|
||||
title: string
|
||||
description: string
|
||||
|
@ -37,6 +38,7 @@ type Board = {
|
|||
|
||||
type BoardPatch = {
|
||||
type?: BoardTypes
|
||||
minimumRole?: string
|
||||
title?: string
|
||||
description?: string
|
||||
icon?: string
|
||||
|
@ -120,6 +122,7 @@ function createBoard(board?: Board): Board {
|
|||
createdBy: board?.createdBy || '',
|
||||
modifiedBy: board?.modifiedBy || '',
|
||||
type: board?.type || BoardTypePrivate,
|
||||
minimumRole: board?.minimumRole || '',
|
||||
title: board?.title || '',
|
||||
description: board?.description || '',
|
||||
icon: board?.icon || '',
|
||||
|
|
|
@ -67,6 +67,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
|
|||
description: 'test',
|
||||
showDescription: false,
|
||||
type: 'board',
|
||||
minimumRole: 'editor',
|
||||
isTemplate: true,
|
||||
templateVersion: 0,
|
||||
icon: '🚴🏻♂️',
|
||||
|
@ -84,6 +85,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
|
|||
updateAt: 20,
|
||||
deleteAt: 0,
|
||||
type: 'board',
|
||||
minimumRole: 'editor',
|
||||
icon: '🚴🏻♂️',
|
||||
description: 'test',
|
||||
showDescription: false,
|
||||
|
|
|
@ -21,13 +21,14 @@ import BoardPermissionGate from '../permissions/boardPermissionGate'
|
|||
|
||||
import mutator from '../../mutator'
|
||||
|
||||
function updateBoardType(board: Board, newType: string) {
|
||||
if (board.type === newType) {
|
||||
function updateBoardType(board: Board, newType: string, newMinimumRole: string) {
|
||||
if (board.type === newType && board.minimumRole == newMinimumRole) {
|
||||
return
|
||||
}
|
||||
|
||||
const newBoard = createBoard(board)
|
||||
newBoard.type = newType
|
||||
newBoard.minimumRole = newMinimumRole
|
||||
|
||||
mutator.updateBoard(newBoard, board, 'update board type')
|
||||
}
|
||||
|
@ -37,7 +38,16 @@ const TeamPermissionsRow = (): JSX.Element => {
|
|||
const team = useAppSelector(getCurrentTeam)
|
||||
const board = useAppSelector(getCurrentBoard)
|
||||
|
||||
const currentRole = board.type === BoardTypeOpen ? 'Editor' : 'None'
|
||||
let currentRoleName = intl.formatMessage({id: 'BoardMember.schemeNone', defaultMessage: 'None'})
|
||||
if (board.type === BoardTypeOpen && board.minimumRole === 'admin') {
|
||||
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeAdmin', defaultMessage: 'Admin'})
|
||||
}else if (board.type === BoardTypeOpen && board.minimumRole === 'editor') {
|
||||
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})
|
||||
}else if (board.type === BoardTypeOpen && board.minimumRole === 'commenter') {
|
||||
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeCommenter', defaultMessage: 'Commenter'})
|
||||
}else if (board.type === BoardTypeOpen && board.minimumRole === 'viewer') {
|
||||
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='user-item'>
|
||||
|
@ -54,26 +64,47 @@ const TeamPermissionsRow = (): JSX.Element => {
|
|||
<BoardPermissionGate permissions={[Permission.ManageBoardType]}>
|
||||
<MenuWrapper>
|
||||
<button className='user-item__button'>
|
||||
{currentRole}
|
||||
{currentRoleName}
|
||||
<CompassIcon
|
||||
icon='chevron-down'
|
||||
className='CompassIcon'
|
||||
/>
|
||||
</button>
|
||||
<Menu position='left'>
|
||||
<Menu.Text
|
||||
id='Admin'
|
||||
check={board.minimumRole === 'admin'}
|
||||
icon={board.type === BoardTypeOpen && board.minimumRole === 'admin' ? <CheckIcon/> : null}
|
||||
name={intl.formatMessage({id: 'BoardMember.schemeAdmin', defaultMessage: 'Admin'})}
|
||||
onClick={() => updateBoardType(board, BoardTypeOpen, 'admin')}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='Editor'
|
||||
check={true}
|
||||
icon={currentRole === 'Editor' ? <CheckIcon/> : null}
|
||||
check={board.minimumRole === '' || board.minimumRole === 'editor' }
|
||||
icon={board.type === BoardTypeOpen && board.minimumRole === 'editor' ? <CheckIcon/> : null}
|
||||
name={intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})}
|
||||
onClick={() => updateBoardType(board, BoardTypeOpen)}
|
||||
onClick={() => updateBoardType(board, BoardTypeOpen, 'editor')}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='Commenter'
|
||||
check={board.minimumRole === 'commenter'}
|
||||
icon={board.type === BoardTypeOpen && board.minimumRole === 'commenter' ? <CheckIcon/> : null}
|
||||
name={intl.formatMessage({id: 'BoardMember.schemeCommenter', defaultMessage: 'Commenter'})}
|
||||
onClick={() => updateBoardType(board, BoardTypeOpen, 'commenter')}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='Viewer'
|
||||
check={board.minimumRole === 'viewer'}
|
||||
icon={board.type === BoardTypeOpen && board.minimumRole === 'viewer' ? <CheckIcon/> : null}
|
||||
name={intl.formatMessage({id: 'BoardMember.schemeViwer', defaultMessage: 'Viewer'})}
|
||||
onClick={() => updateBoardType(board, BoardTypeOpen, 'viewer')}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='None'
|
||||
check={true}
|
||||
icon={currentRole === 'None' ? <CheckIcon/> : null}
|
||||
icon={board.type === BoardTypePrivate ? <CheckIcon/> : null}
|
||||
name={intl.formatMessage({id: 'BoardMember.schemeNone', defaultMessage: 'None'})}
|
||||
onClick={() => updateBoardType(board, BoardTypePrivate)}
|
||||
onClick={() => updateBoardType(board, BoardTypePrivate, 'editor')}
|
||||
/>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
|
@ -82,7 +113,7 @@ const TeamPermissionsRow = (): JSX.Element => {
|
|||
permissions={[Permission.ManageBoardType]}
|
||||
invert={true}
|
||||
>
|
||||
<span>{currentRole}</span>
|
||||
<span>{currentRoleName}</span>
|
||||
</BoardPermissionGate>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue