]> source.dussan.org Git - gitea.git/commitdiff
[API] Add endpount to get user org permissions (#17232)
authorRomain <romdum@users.noreply.github.com>
Tue, 12 Oct 2021 10:47:19 +0000 (12:47 +0200)
committerGitHub <noreply@github.com>
Tue, 12 Oct 2021 10:47:19 +0000 (12:47 +0200)
* Add endpoint

* Add swagger response + generate swagger

* Stop execution if user / org is not found

* Add tests

Co-authored-by: 6543 <6543@obermui.de>
integrations/api_user_org_perm_test.go [new file with mode: 0644]
models/org.go
modules/structs/org.go
routers/api/v1/api.go
routers/api/v1/org/org.go
routers/api/v1/swagger/org.go
templates/swagger/v1_json.tmpl

diff --git a/integrations/api_user_org_perm_test.go b/integrations/api_user_org_perm_test.go
new file mode 100644 (file)
index 0000000..abba247
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package integrations
+
+import (
+       "fmt"
+       "net/http"
+       "testing"
+
+       api "code.gitea.io/gitea/modules/structs"
+       "github.com/stretchr/testify/assert"
+)
+
+type apiUserOrgPermTestCase struct {
+       LoginUser                       string
+       User                            string
+       Organization                    string
+       ExpectedOrganizationPermissions api.OrganizationPermissions
+}
+
+func TestTokenNeeded(t *testing.T) {
+       defer prepareTestEnv(t)()
+
+       session := emptyTestSession(t)
+       req := NewRequest(t, "GET", "/api/v1/users/user1/orgs/user6/permissions")
+       session.MakeRequest(t, req, http.StatusUnauthorized)
+}
+
+func sampleTest(t *testing.T, auoptc apiUserOrgPermTestCase) {
+       defer prepareTestEnv(t)()
+
+       session := loginUser(t, auoptc.LoginUser)
+       token := getTokenForLoggedInUser(t, session)
+
+       req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s/orgs/%s/permissions?token=%s", auoptc.User, auoptc.Organization, token))
+       resp := session.MakeRequest(t, req, http.StatusOK)
+
+       var apiOP api.OrganizationPermissions
+       DecodeJSON(t, resp, &apiOP)
+       assert.Equal(t, auoptc.ExpectedOrganizationPermissions.IsOwner, apiOP.IsOwner)
+       assert.Equal(t, auoptc.ExpectedOrganizationPermissions.IsAdmin, apiOP.IsAdmin)
+       assert.Equal(t, auoptc.ExpectedOrganizationPermissions.CanWrite, apiOP.CanWrite)
+       assert.Equal(t, auoptc.ExpectedOrganizationPermissions.CanRead, apiOP.CanRead)
+       assert.Equal(t, auoptc.ExpectedOrganizationPermissions.CanCreateRepository, apiOP.CanCreateRepository)
+}
+
+func TestWithOwnerUser(t *testing.T) {
+       sampleTest(t, apiUserOrgPermTestCase{
+               LoginUser:    "user2",
+               User:         "user2",
+               Organization: "user3",
+               ExpectedOrganizationPermissions: api.OrganizationPermissions{
+                       IsOwner:             true,
+                       IsAdmin:             true,
+                       CanWrite:            true,
+                       CanRead:             true,
+                       CanCreateRepository: true,
+               },
+       })
+}
+
+func TestCanWriteUser(t *testing.T) {
+       sampleTest(t, apiUserOrgPermTestCase{
+               LoginUser:    "user4",
+               User:         "user4",
+               Organization: "user3",
+               ExpectedOrganizationPermissions: api.OrganizationPermissions{
+                       IsOwner:             false,
+                       IsAdmin:             false,
+                       CanWrite:            true,
+                       CanRead:             true,
+                       CanCreateRepository: false,
+               },
+       })
+}
+
+func TestAdminUser(t *testing.T) {
+       sampleTest(t, apiUserOrgPermTestCase{
+               LoginUser:    "user1",
+               User:         "user28",
+               Organization: "user3",
+               ExpectedOrganizationPermissions: api.OrganizationPermissions{
+                       IsOwner:             false,
+                       IsAdmin:             true,
+                       CanWrite:            true,
+                       CanRead:             true,
+                       CanCreateRepository: true,
+               },
+       })
+}
+
+func TestAdminCanNotCreateRepo(t *testing.T) {
+       sampleTest(t, apiUserOrgPermTestCase{
+               LoginUser:    "user1",
+               User:         "user28",
+               Organization: "user6",
+               ExpectedOrganizationPermissions: api.OrganizationPermissions{
+                       IsOwner:             false,
+                       IsAdmin:             true,
+                       CanWrite:            true,
+                       CanRead:             true,
+                       CanCreateRepository: false,
+               },
+       })
+}
+
+func TestCanReadUser(t *testing.T) {
+       sampleTest(t, apiUserOrgPermTestCase{
+               LoginUser:    "user1",
+               User:         "user24",
+               Organization: "org25",
+               ExpectedOrganizationPermissions: api.OrganizationPermissions{
+                       IsOwner:             false,
+                       IsAdmin:             false,
+                       CanWrite:            false,
+                       CanRead:             true,
+                       CanCreateRepository: false,
+               },
+       })
+}
+
+func TestUnknowUser(t *testing.T) {
+       defer prepareTestEnv(t)()
+
+       session := loginUser(t, "user1")
+       token := getTokenForLoggedInUser(t, session)
+
+       req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/unknow/orgs/org25/permissions?token=%s", token))
+       resp := session.MakeRequest(t, req, http.StatusNotFound)
+
+       var apiError api.APIError
+       DecodeJSON(t, resp, &apiError)
+       assert.Equal(t, "GetUserByName", apiError.Message)
+}
+
+func TestUnknowOrganization(t *testing.T) {
+       defer prepareTestEnv(t)()
+
+       session := loginUser(t, "user1")
+       token := getTokenForLoggedInUser(t, session)
+
+       req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/user1/orgs/unknow/permissions?token=%s", token))
+       resp := session.MakeRequest(t, req, http.StatusNotFound)
+       var apiError api.APIError
+       DecodeJSON(t, resp, &apiError)
+       assert.Equal(t, "GetUserByName", apiError.Message)
+}
index eadd1e157c9225a59befeba4ad822e69cc1ba611..8cba485a89fc282e7bf02f8bb20b68116cd9f7ba 100644 (file)
@@ -392,6 +392,19 @@ func CanCreateOrgRepo(orgID, uid int64) (bool, error) {
                Exist(new(Team))
 }
 
+// GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization
+func (org *User) GetOrgUserMaxAuthorizeLevel(uid int64) (AccessMode, error) {
+       var authorize AccessMode
+       _, err := db.GetEngine(db.DefaultContext).
+               Select("max(team.authorize)").
+               Table("team").
+               Join("INNER", "team_user", "team_user.team_id = team.id").
+               Where("team_user.uid = ?", uid).
+               And("team_user.org_id = ?", org.ID).
+               Get(&authorize)
+       return authorize, err
+}
+
 // GetUsersWhoCanCreateOrgRepo returns users which are able to create repo in organization
 func GetUsersWhoCanCreateOrgRepo(orgID int64) ([]*User, error) {
        return getUsersWhoCanCreateOrgRepo(db.GetEngine(db.DefaultContext), orgID)
index 38c6c6d6d849b4b4a533f5ed121e484246735c6c..4ae0ca8b6f3c7dc73b203cad531e7e0616f15584 100644 (file)
@@ -17,6 +17,15 @@ type Organization struct {
        RepoAdminChangeTeamAccess bool   `json:"repo_admin_change_team_access"`
 }
 
+// OrganizationPermissions list differents users permissions on an organization
+type OrganizationPermissions struct {
+       IsOwner             bool `json:"is_owner"`
+       IsAdmin             bool `json:"is_admin"`
+       CanWrite            bool `json:"can_write"`
+       CanRead             bool `json:"can_read"`
+       CanCreateRepository bool `json:"can_create_repository"`
+}
+
 // CreateOrgOption options for creating an organization
 type CreateOrgOption struct {
        // required: true
index 0a967e3c5a78f95418d32cb261b5faa26bf5bf5b..d11bbf3c06c43b124452cc9de9bb20521c0ec5e7 100644 (file)
@@ -973,7 +973,10 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 
                // Organizations
                m.Get("/user/orgs", reqToken(), org.ListMyOrgs)
-               m.Get("/users/{username}/orgs", org.ListUserOrgs)
+               m.Group("/users/{username}/orgs", func() {
+                       m.Get("", org.ListUserOrgs)
+                       m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
+               })
                m.Post("/orgs", reqToken(), bind(api.CreateOrgOption{}), org.Create)
                m.Get("/orgs", org.GetAll)
                m.Group("/orgs/{org}", func() {
index cf4c328ebbe86b6ca76f29c3ade8c7f91b1af086..d3aa92f46d1d98ddbc02d99755186fc00b212d22 100644 (file)
@@ -97,6 +97,77 @@ func ListUserOrgs(ctx *context.APIContext) {
        listUserOrgs(ctx, u)
 }
 
+// GetUserOrgsPermissions get user permissions in organization
+func GetUserOrgsPermissions(ctx *context.APIContext) {
+       // swagger:operation GET /users/{username}/orgs/{org}/permissions organization orgGetUserPermissions
+       // ---
+       // summary: Get user permissions in organization
+       // produces:
+       // - application/json
+       // parameters:
+       // - name: username
+       //   in: path
+       //   description: username of user
+       //   type: string
+       //   required: true
+       // - name: org
+       //   in: path
+       //   description: name of the organization
+       //   type: string
+       //   required: true
+       // responses:
+       //   "200":
+       //     "$ref": "#/responses/OrganizationPermissions"
+       //   "403":
+       //     "$ref": "#/responses/forbidden"
+       //   "404":
+       //     "$ref": "#/responses/notFound"
+
+       var u *models.User
+       if u = user.GetUserByParams(ctx); u == nil {
+               return
+       }
+
+       var o *models.User
+       if o = user.GetUserByParamsName(ctx, ":org"); o == nil {
+               return
+       }
+
+       op := api.OrganizationPermissions{}
+
+       if !models.HasOrgOrUserVisible(o, u) {
+               ctx.NotFound("HasOrgOrUserVisible", nil)
+               return
+       }
+
+       authorizeLevel, err := o.GetOrgUserMaxAuthorizeLevel(u.ID)
+       if err != nil {
+               ctx.Error(http.StatusInternalServerError, "GetOrgUserAuthorizeLevel", err)
+               return
+       }
+
+       if authorizeLevel > models.AccessModeNone {
+               op.CanRead = true
+       }
+       if authorizeLevel > models.AccessModeRead {
+               op.CanWrite = true
+       }
+       if authorizeLevel > models.AccessModeWrite {
+               op.IsAdmin = true
+       }
+       if authorizeLevel > models.AccessModeAdmin {
+               op.IsOwner = true
+       }
+
+       op.CanCreateRepository, err = o.CanCreateOrgRepo(u.ID)
+       if err != nil {
+               ctx.Error(http.StatusInternalServerError, "CanCreateOrgRepo", err)
+               return
+       }
+
+       ctx.JSON(http.StatusOK, op)
+}
+
 // GetAll return list of all public organizations
 func GetAll(ctx *context.APIContext) {
        // swagger:operation Get /orgs organization orgGetAll
index c962e7b188ee543bbb1d484dbf9e750c59f0da0b..d98e821ba744ed65d844e3c1f496c02a1e25ba79 100644 (file)
@@ -35,3 +35,10 @@ type swaggerResponseTeamList struct {
        // in:body
        Body []api.Team `json:"body"`
 }
+
+// OrganizationPermissions
+// swagger:response OrganizationPermissions
+type swaggerResponseOrganizationPermissions struct {
+       // in:body
+       Body api.OrganizationPermissions `json:"body"`
+}
index c6fa664af6d9f8c6ee9d484872e71b132e8c421c..afb93c50fe1ba2ee6db63171f09d53787bff160c 100644 (file)
         }
       }
     },
+    "/users/{username}/orgs/{org}/permissions": {
+      "get": {
+        "produces": [
+          "application/json"
+        ],
+        "tags": [
+          "organization"
+        ],
+        "summary": "Get user permissions in organization",
+        "operationId": "orgGetUserPermissions",
+        "parameters": [
+          {
+            "type": "string",
+            "description": "username of user",
+            "name": "username",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "string",
+            "description": "name of the organization",
+            "name": "org",
+            "in": "path",
+            "required": true
+          }
+        ],
+        "responses": {
+          "200": {
+            "$ref": "#/responses/OrganizationPermissions"
+          },
+          "403": {
+            "$ref": "#/responses/forbidden"
+          },
+          "404": {
+            "$ref": "#/responses/notFound"
+          }
+        }
+      }
+    },
     "/users/{username}/repos": {
       "get": {
         "produces": [
       },
       "x-go-package": "code.gitea.io/gitea/modules/structs"
     },
+    "OrganizationPermissions": {
+      "description": "OrganizationPermissions list differents users permissions on an organization",
+      "type": "object",
+      "properties": {
+        "can_create_repository": {
+          "type": "boolean",
+          "x-go-name": "CanCreateRepository"
+        },
+        "can_read": {
+          "type": "boolean",
+          "x-go-name": "CanRead"
+        },
+        "can_write": {
+          "type": "boolean",
+          "x-go-name": "CanWrite"
+        },
+        "is_admin": {
+          "type": "boolean",
+          "x-go-name": "IsAdmin"
+        },
+        "is_owner": {
+          "type": "boolean",
+          "x-go-name": "IsOwner"
+        }
+      },
+      "x-go-package": "code.gitea.io/gitea/modules/structs"
+    },
     "PRBranchInfo": {
       "description": "PRBranchInfo information about a branch",
       "type": "object",
         }
       }
     },
+    "OrganizationPermissions": {
+      "description": "OrganizationPermissions",
+      "schema": {
+        "$ref": "#/definitions/OrganizationPermissions"
+      }
+    },
     "PublicKey": {
       "description": "PublicKey",
       "schema": {