From e230039d6818a0b0385837c47ac7740a818812ae Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 4 Nov 2018 09:53:56 +0800 Subject: [PATCH 1/7] add api for user to create org --- routers/api/v1/api.go | 1 + routers/api/v1/org/org.go | 59 ++++++++++++++++++++++++++++++++++ templates/swagger/v1_json.tmpl | 45 +++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index a839ce8dc1d5f..2281bd33a4cc7 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -578,6 +578,7 @@ func RegisterRoutes(m *macaron.Macaron) { // Organizations m.Get("/user/orgs", reqToken(), org.ListMyOrgs) m.Get("/users/:username/orgs", org.ListUserOrgs) + m.Post("/orgs", reqToken(), org.Create) m.Group("/orgs/:orgname", func() { m.Get("/repos", user.ListOrgRepos) m.Combo("").Get(org.Get). diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index 29d45d2f2ed6f..8cf4401582812 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -62,6 +62,65 @@ func ListUserOrgs(ctx *context.APIContext) { listUserOrgs(ctx, u, false) } +// Create api for create organization +func Create(ctx *context.APIContext, form api.CreateOrgOption) { + // swagger:operation POST /orgs organization orgCreate + // --- + // summary: Create an organization + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: username + // in: path + // description: username of the user that will own the created organization + // type: string + // required: true + // - name: organization + // in: body + // required: true + // schema: { "$ref": "#/definitions/CreateOrgOption" } + // responses: + // "201": + // "$ref": "#/responses/Organization" + // "403": + // "$ref": "#/responses/forbidden" + // "422": + // "$ref": "#/responses/validationError" + u := user.GetUserByParams(ctx) + if ctx.Written() { + return + } + + if !u.AllowCreateOrganization { + ctx.Error(403, "Create organization not allowed", nil) + return + } + + org := &models.User{ + Name: form.UserName, + FullName: form.FullName, + Description: form.Description, + Website: form.Website, + Location: form.Location, + IsActive: true, + Type: models.UserTypeOrganization, + } + if err := models.CreateOrganization(org, u); err != nil { + if models.IsErrUserAlreadyExist(err) || + models.IsErrNameReserved(err) || + models.IsErrNamePatternNotAllowed(err) { + ctx.Error(422, "", err) + } else { + ctx.Error(500, "CreateOrganization", err) + } + return + } + + ctx.JSON(201, convert.ToOrganization(org)) +} + // Get get an organization func Get(ctx *context.APIContext) { // swagger:operation GET /orgs/{org} organization orgGet diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 5c8c666041f57..7d5b92081d0c3 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -406,6 +406,49 @@ } } }, + "/orgs": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "organization" + ], + "summary": "Create an organization", + "operationId": "orgCreate", + "parameters": [ + { + "type": "string", + "description": "username of the user that will own the created organization", + "name": "username", + "in": "path", + "required": true + }, + { + "name": "organization", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateOrgOption" + } + } + ], + "responses": { + "201": { + "$ref": "#/responses/Organization" + }, + "403": { + "$ref": "#/responses/forbidden" + }, + "422": { + "$ref": "#/responses/validationError" + } + } + } + }, "/orgs/{org}": { "get": { "produces": [ @@ -8359,4 +8402,4 @@ "SudoHeader": [] } ] -} \ No newline at end of file +} From da327aa95810d8c995345185204a42f53fe32849 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 6 Nov 2018 08:30:12 +0800 Subject: [PATCH 2/7] remove unused blank line on the swagger file end --- templates/swagger/v1_json.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 7d5b92081d0c3..d24adf7af5490 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -8402,4 +8402,4 @@ "SudoHeader": [] } ] -} +} \ No newline at end of file From 94ac0da25bf7cd84dffeb48674bae8fc202f973f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 6 Nov 2018 09:05:31 +0800 Subject: [PATCH 3/7] fix create and add test --- integrations/api_org_test.go | 40 ++++++++++++++++++++++++++++++++++ routers/api/v1/org/org.go | 13 ++--------- templates/swagger/v1_json.tmpl | 7 ------ 3 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 integrations/api_org_test.go diff --git a/integrations/api_org_test.go b/integrations/api_org_test.go new file mode 100644 index 0000000000000..df821009d44d6 --- /dev/null +++ b/integrations/api_org_test.go @@ -0,0 +1,40 @@ +// Copyright 2018 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 ( + "net/http" + "testing" + + api "code.gitea.io/sdk/gitea" + + "github.com/stretchr/testify/assert" +) + +func TestAPIOrg(t *testing.T) { + prepareTestEnv(t) + + session := loginUser(t, "user1") + + token := getTokenForLoggedInUser(t, session) + var org = api.CreateOrgOption{ + UserName: "user1_org", + FullName: "User1's organization", + Description: "This organization created by user1", + Website: "https://try.gitea.io", + Location: "Shanghai", + } + req := NewRequestf(t, "POST", "/api/v1/orgs?token="+token, &org) + resp := session.MakeRequest(t, req, http.StatusOK) + + var apiOrg api.Organization + DecodeJSON(t, resp, &apiOrg) + + assert.Equal(t, org.UserName, apiOrg.UserName) + assert.Equal(t, org.FullName, apiOrg.FullName) + assert.Equal(t, org.Description, apiOrg.Description) + assert.Equal(t, org.Website, apiOrg.Website) + assert.Equal(t, org.Location, apiOrg.Location) +} diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index 8cf4401582812..8d934a129cd41 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -72,11 +72,6 @@ func Create(ctx *context.APIContext, form api.CreateOrgOption) { // produces: // - application/json // parameters: - // - name: username - // in: path - // description: username of the user that will own the created organization - // type: string - // required: true // - name: organization // in: body // required: true @@ -88,12 +83,8 @@ func Create(ctx *context.APIContext, form api.CreateOrgOption) { // "$ref": "#/responses/forbidden" // "422": // "$ref": "#/responses/validationError" - u := user.GetUserByParams(ctx) - if ctx.Written() { - return - } - if !u.AllowCreateOrganization { + if !ctx.User.AllowCreateOrganization { ctx.Error(403, "Create organization not allowed", nil) return } @@ -107,7 +98,7 @@ func Create(ctx *context.APIContext, form api.CreateOrgOption) { IsActive: true, Type: models.UserTypeOrganization, } - if err := models.CreateOrganization(org, u); err != nil { + if err := models.CreateOrganization(org, ctx.User); err != nil { if models.IsErrUserAlreadyExist(err) || models.IsErrNameReserved(err) || models.IsErrNamePatternNotAllowed(err) { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index d24adf7af5490..dada2c98e3901 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -420,13 +420,6 @@ "summary": "Create an organization", "operationId": "orgCreate", "parameters": [ - { - "type": "string", - "description": "username of the user that will own the created organization", - "name": "username", - "in": "path", - "required": true - }, { "name": "organization", "in": "body", From 4861c5757a90648fea72eac189972d3d61378871 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 9 Nov 2018 11:31:08 +0800 Subject: [PATCH 4/7] fix tests --- integrations/api_org_test.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/integrations/api_org_test.go b/integrations/api_org_test.go index df821009d44d6..d30b746738a9f 100644 --- a/integrations/api_org_test.go +++ b/integrations/api_org_test.go @@ -6,8 +6,10 @@ package integrations import ( "net/http" + "strings" "testing" + "code.gitea.io/gitea/models" api "code.gitea.io/sdk/gitea" "github.com/stretchr/testify/assert" @@ -26,8 +28,8 @@ func TestAPIOrg(t *testing.T) { Website: "https://try.gitea.io", Location: "Shanghai", } - req := NewRequestf(t, "POST", "/api/v1/orgs?token="+token, &org) - resp := session.MakeRequest(t, req, http.StatusOK) + req := NewRequestWithJSON(t, "POST", "/api/v1/orgs?token="+token, &org) + resp := session.MakeRequest(t, req, http.StatusCreated) var apiOrg api.Organization DecodeJSON(t, resp, &apiOrg) @@ -37,4 +39,10 @@ func TestAPIOrg(t *testing.T) { assert.Equal(t, org.Description, apiOrg.Description) assert.Equal(t, org.Website, apiOrg.Website) assert.Equal(t, org.Location, apiOrg.Location) + + models.AssertExistsAndLoadBean(t, &models.User{ + Name: org.UserName, + LowerName: strings.ToLower(org.UserName), + FullName: org.FullName, + }) } From c55543c73323ce98c9c84da59a94d938bab4bde0 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 9 Nov 2018 11:46:36 +0800 Subject: [PATCH 5/7] fix routes of create org API --- routers/api/v1/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 2281bd33a4cc7..d9a8997c9f3d5 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -578,7 +578,7 @@ func RegisterRoutes(m *macaron.Macaron) { // Organizations m.Get("/user/orgs", reqToken(), org.ListMyOrgs) m.Get("/users/:username/orgs", org.ListUserOrgs) - m.Post("/orgs", reqToken(), org.Create) + m.Post("/orgs", reqToken(), bind(api.CreateIssueOption{}), org.Create) m.Group("/orgs/:orgname", func() { m.Get("/repos", user.ListOrgRepos) m.Combo("").Get(org.Get). From 9dacfec6609cbe68ef05ed6f6ae8dadecbb8996e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 9 Nov 2018 20:32:04 +0800 Subject: [PATCH 6/7] fix bug --- routers/api/v1/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index d9a8997c9f3d5..0961e7cbe374a 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -578,7 +578,7 @@ func RegisterRoutes(m *macaron.Macaron) { // Organizations m.Get("/user/orgs", reqToken(), org.ListMyOrgs) m.Get("/users/:username/orgs", org.ListUserOrgs) - m.Post("/orgs", reqToken(), bind(api.CreateIssueOption{}), org.Create) + m.Post("/orgs", reqToken(), bind(api.CreateOrgOption{}), org.Create) m.Group("/orgs/:orgname", func() { m.Get("/repos", user.ListOrgRepos) m.Combo("").Get(org.Get). From 7f8d4e461cac41c3d9dadec70199dbdd0115b263 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 11 Nov 2018 12:44:45 +0800 Subject: [PATCH 7/7] add copyright heads --- routers/api/v1/api.go | 1 + routers/api/v1/org/org.go | 1 + 2 files changed, 2 insertions(+) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 0961e7cbe374a..c5f01d91d8c50 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1,4 +1,5 @@ // Copyright 2015 The Gogs Authors. All rights reserved. +// Copyright 2018 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. diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index 8d934a129cd41..93c2ed7a88959 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -1,4 +1,5 @@ // Copyright 2015 The Gogs Authors. All rights reserved. +// Copyright 2018 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.