diff --git a/pkg/models/team_members.go b/pkg/models/team_members.go index 62dc133c7..1e1a28b56 100644 --- a/pkg/models/team_members.go +++ b/pkg/models/team_members.go @@ -96,3 +96,39 @@ func (tm *TeamMember) Delete() (err error) { _, err = x.Where("team_id = ? AND user_id = ?", tm.TeamID, tm.UserID).Delete(&TeamMember{}) return } + +// Update toggles a team member's admin status +// @Summary Toggle a team member's admin status +// @Description If a user is team admin, this will make them member and vise-versa. +// @tags team +// @Produce json +// @Security JWTKeyAuth +// @Param id path int true "Team ID" +// @Param userID path int true "User ID" +// @Success 200 {object} models.Message "The member right was successfully changed." +// @Failure 500 {object} models.Message "Internal error" +// @Router /teams/{id}/members/{userID}/admin [post] +func (tm *TeamMember) Update() (err error) { + // Find the numeric user id + user, err := user2.GetUserByUsername(tm.Username) + if err != nil { + return + } + tm.UserID = user.ID + + // Get the full member object and change the admin right + _, err = x. + Where("team_id = ? AND user_id = ?", tm.TeamID, tm.UserID). + Get(tm) + if err != nil { + return err + } + tm.Admin = !tm.Admin + + // Do the update + _, err = x. + Where("team_id = ? AND user_id = ?", tm.TeamID, tm.UserID). + Cols("admin"). + Update(tm) + return +} diff --git a/pkg/models/team_members_rights.go b/pkg/models/team_members_rights.go index 3926dee61..872c0f704 100644 --- a/pkg/models/team_members_rights.go +++ b/pkg/models/team_members_rights.go @@ -30,6 +30,11 @@ func (tm *TeamMember) CanDelete(a web.Auth) (bool, error) { return tm.IsAdmin(a) } +// CanUpdate checks if the user can modify a team member's right +func (tm *TeamMember) CanUpdate(a web.Auth) (bool, error) { + return tm.IsAdmin(a) +} + // IsAdmin checks if the user is team admin func (tm *TeamMember) IsAdmin(a web.Auth) (bool, error) { // Don't allow anything if we're dealing with a list share here diff --git a/pkg/models/team_members_test.go b/pkg/models/team_members_test.go index 1222d1057..79446e551 100644 --- a/pkg/models/team_members_test.go +++ b/pkg/models/team_members_test.go @@ -81,3 +81,30 @@ func TestTeamMember_Delete(t *testing.T) { assert.NoError(t, err) }) } + +func TestTeamMember_Update(t *testing.T) { + t.Run("normal", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + tm := &TeamMember{ + TeamID: 1, + Username: "user1", + Admin: true, + } + err := tm.Update() + assert.NoError(t, err) + assert.False(t, tm.Admin) + }) + // This should have the same result as the normal run as the update function + // should ignore what was passed. + t.Run("explicitly false in payload", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + tm := &TeamMember{ + TeamID: 1, + Username: "user1", + Admin: true, + } + err := tm.Update() + assert.NoError(t, err) + assert.False(t, tm.Admin) + }) +} diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index b9e1cde10..ad384d423 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -478,6 +478,7 @@ func registerAPIRoutes(a *echo.Group) { } a.PUT("/teams/:team/members", teamMemberHandler.CreateWeb) a.DELETE("/teams/:team/members/:user", teamMemberHandler.DeleteWeb) + a.POST("/teams/:team/members/:user/admin", teamMemberHandler.UpdateWeb) // Migrations m := a.Group("/migration") diff --git a/pkg/swagger/docs.go b/pkg/swagger/docs.go index ec1464310..949d99a5e 100644 --- a/pkg/swagger/docs.go +++ b/pkg/swagger/docs.go @@ -5311,6 +5311,53 @@ var doc = `{ } } }, + "/teams/{id}/members/{userID}/admin": { + "post": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "If a user is team admin, this will make them member and vise-versa.", + "produces": [ + "application/json" + ], + "tags": [ + "team" + ], + "summary": "Toggle a team member's admin status", + "parameters": [ + { + "type": "integer", + "description": "Team ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "User ID", + "name": "userID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "The member right was successfully changed.", + "schema": { + "$ref": "#/definitions/models.Message" + } + }, + "500": { + "description": "Internal error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + } + }, "/user": { "get": { "security": [ diff --git a/pkg/swagger/swagger.json b/pkg/swagger/swagger.json index 533f9cae9..46ca36fee 100644 --- a/pkg/swagger/swagger.json +++ b/pkg/swagger/swagger.json @@ -5294,6 +5294,53 @@ } } }, + "/teams/{id}/members/{userID}/admin": { + "post": { + "security": [ + { + "JWTKeyAuth": [] + } + ], + "description": "If a user is team admin, this will make them member and vise-versa.", + "produces": [ + "application/json" + ], + "tags": [ + "team" + ], + "summary": "Toggle a team member's admin status", + "parameters": [ + { + "type": "integer", + "description": "Team ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "User ID", + "name": "userID", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "The member right was successfully changed.", + "schema": { + "$ref": "#/definitions/models.Message" + } + }, + "500": { + "description": "Internal error", + "schema": { + "$ref": "#/definitions/models.Message" + } + } + } + } + }, "/user": { "get": { "security": [ diff --git a/pkg/swagger/swagger.yaml b/pkg/swagger/swagger.yaml index 524c69b9e..58e919a2c 100644 --- a/pkg/swagger/swagger.yaml +++ b/pkg/swagger/swagger.yaml @@ -4524,6 +4524,36 @@ paths: summary: Remove a user from a team tags: - team + /teams/{id}/members/{userID}/admin: + post: + description: If a user is team admin, this will make them member and vise-versa. + parameters: + - description: Team ID + in: path + name: id + required: true + type: integer + - description: User ID + in: path + name: userID + required: true + type: integer + produces: + - application/json + responses: + "200": + description: The member right was successfully changed. + schema: + $ref: '#/definitions/models.Message' + "500": + description: Internal error + schema: + $ref: '#/definitions/models.Message' + security: + - JWTKeyAuth: [] + summary: Toggle a team member's admin status + tags: + - team /user: get: consumes: