diff --git a/cmd/agola/cmd/orgcreate.go b/cmd/agola/cmd/orgcreate.go index a4fbaf6..d3bd974 100644 --- a/cmd/agola/cmd/orgcreate.go +++ b/cmd/agola/cmd/orgcreate.go @@ -19,6 +19,7 @@ import ( "github.com/pkg/errors" "github.com/sorintlab/agola/internal/services/gateway/api" + "github.com/sorintlab/agola/internal/services/types" "github.com/spf13/cobra" ) @@ -34,7 +35,8 @@ var cmdOrgCreate = &cobra.Command{ } type orgCreateOptions struct { - name string + name string + visibility string } var orgCreateOpts orgCreateOptions @@ -43,6 +45,7 @@ func init() { flags := cmdOrgCreate.Flags() flags.StringVarP(&orgCreateOpts.name, "name", "n", "", "organization name") + flags.StringVar(&orgCreateOpts.visibility, "visibility", "public", `organization visibility (public or private)`) cmdOrgCreate.MarkFlagRequired("name") @@ -52,8 +55,14 @@ func init() { func orgCreate(cmd *cobra.Command, args []string) error { gwclient := api.NewClient(gatewayURL, token) + // TODO(sgotti) make this a custom pflag Value? + if !types.IsValidVisibility(types.Visibility(orgCreateOpts.visibility)) { + return errors.Errorf("invalid visibility %q", orgCreateOpts.visibility) + } + req := &api.CreateOrgRequest{ - Name: orgCreateOpts.name, + Name: orgCreateOpts.name, + Visibility: types.Visibility(orgCreateOpts.visibility), } log.Infof("creating org") diff --git a/internal/services/configstore/action/org.go b/internal/services/configstore/action/org.go index 7d2953b..421b7aa 100644 --- a/internal/services/configstore/action/org.go +++ b/internal/services/configstore/action/org.go @@ -36,6 +36,9 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) if !util.ValidateName(org.Name) { return nil, util.NewErrBadRequest(errors.Errorf("invalid organization name %q", org.Name)) } + if !types.IsValidVisibility(org.Visibility) { + return nil, util.NewErrBadRequest(errors.Errorf("invalid organization visibility")) + } var cgt *datamanager.ChangeGroupsUpdateToken // changegroup is the org name @@ -109,8 +112,11 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) }) } + // create root org project group pg := &types.ProjectGroup{ ID: uuid.NewV4().String(), + // use same org visibility + Visibility: org.Visibility, Parent: types.Parent{ Type: types.ConfigTypeOrg, ID: org.ID, diff --git a/internal/services/configstore/action/user.go b/internal/services/configstore/action/user.go index 0b0a80e..b2410d1 100644 --- a/internal/services/configstore/action/user.go +++ b/internal/services/configstore/action/user.go @@ -117,8 +117,11 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) return nil, errors.Wrapf(err, "failed to marshal user") } + // create root user project group pg := &types.ProjectGroup{ ID: uuid.NewV4().String(), + // use public visibility + Visibility: types.VisibilityPublic, Parent: types.Parent{ Type: types.ConfigTypeUser, ID: user.ID, diff --git a/internal/services/configstore/api/project.go b/internal/services/configstore/api/project.go index 92cbfd9..8d0b7f4 100644 --- a/internal/services/configstore/api/project.go +++ b/internal/services/configstore/api/project.go @@ -102,13 +102,23 @@ func getGlobalVisibility(readDB *readdb.ReadDB, tx *db.Tx, curVisibility types.V return "", err } if projectGroup.Visibility == types.VisibilityPrivate { - curVisibility = types.VisibilityPrivate - continue + return types.VisibilityPrivate, nil } curParent = &projectGroup.Parent } + // check parent visibility + if curParent.Type == types.ConfigTypeOrg { + org, err := readDB.GetOrg(tx, curParent.ID) + if err != nil { + return "", err + } + if org.Visibility == types.VisibilityPrivate { + return types.VisibilityPrivate, nil + } + } + return curVisibility, nil } diff --git a/internal/services/configstore/configstore_test.go b/internal/services/configstore/configstore_test.go index 493ed5c..a6fbbcd 100644 --- a/internal/services/configstore/configstore_test.go +++ b/internal/services/configstore/configstore_test.go @@ -386,7 +386,7 @@ func TestProjectGroupsAndProjects(t *testing.T) { if err != nil { t.Fatalf("unexpected err: %v", err) } - org, err := cs.ah.CreateOrg(ctx, &types.Organization{Name: "org01"}) + org, err := cs.ah.CreateOrg(ctx, &types.Organization{Name: "org01", Visibility: types.VisibilityPublic}) if err != nil { t.Fatalf("unexpected err: %v", err) } @@ -533,7 +533,7 @@ func TestProjectGroupDelete(t *testing.T) { //if err != nil { // t.Fatalf("unexpected err: %v", err) //} - org, err := cs.ah.CreateOrg(ctx, &types.Organization{Name: "org01"}) + org, err := cs.ah.CreateOrg(ctx, &types.Organization{Name: "org01", Visibility: types.VisibilityPublic}) if err != nil { t.Fatalf("unexpected err: %v", err) } @@ -674,7 +674,7 @@ func TestOrgMembers(t *testing.T) { if err != nil { t.Fatalf("unexpected err: %v", err) } - org, err := cs.ah.CreateOrg(ctx, &types.Organization{Name: "org01", CreatorUserID: user.ID}) + org, err := cs.ah.CreateOrg(ctx, &types.Organization{Name: "org01", Visibility: types.VisibilityPublic, CreatorUserID: user.ID}) if err != nil { t.Fatalf("unexpected err: %v", err) } @@ -700,7 +700,7 @@ func TestOrgMembers(t *testing.T) { orgs := []*types.Organization{} for i := 0; i < 10; i++ { - org, err := cs.ah.CreateOrg(ctx, &types.Organization{Name: fmt.Sprintf("org%d", i), CreatorUserID: user.ID}) + org, err := cs.ah.CreateOrg(ctx, &types.Organization{Name: fmt.Sprintf("org%d", i), Visibility: types.VisibilityPublic, CreatorUserID: user.ID}) if err != nil { t.Fatalf("err: %v", err) } diff --git a/internal/services/gateway/action/org.go b/internal/services/gateway/action/org.go index 4828f31..f48c8f4 100644 --- a/internal/services/gateway/action/org.go +++ b/internal/services/gateway/action/org.go @@ -46,7 +46,8 @@ func (h *ActionHandler) GetOrgs(ctx context.Context, req *GetOrgsRequest) ([]*ty } type CreateOrgRequest struct { - Name string + Name string + Visibility types.Visibility CreatorUserID string } @@ -64,7 +65,8 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, req *CreateOrgRequest) (* } org := &types.Organization{ - Name: req.Name, + Name: req.Name, + Visibility: req.Visibility, } if req.CreatorUserID != "" { org.CreatorUserID = req.CreatorUserID diff --git a/internal/services/gateway/api/org.go b/internal/services/gateway/api/org.go index 25003ed..61498c4 100644 --- a/internal/services/gateway/api/org.go +++ b/internal/services/gateway/api/org.go @@ -29,7 +29,8 @@ import ( ) type CreateOrgRequest struct { - Name string `json:"name"` + Name string `json:"name"` + Visibility types.Visibility `json:"visibility"` } type CreateOrgHandler struct { @@ -60,6 +61,7 @@ func (h *CreateOrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { creq := &action.CreateOrgRequest{ Name: req.Name, + Visibility: req.Visibility, CreatorUserID: userID, } @@ -127,14 +129,16 @@ func (h *OrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } type OrgResponse struct { - ID string `json:"id"` - Name string `json:"name"` + ID string `json:"id"` + Name string `json:"name"` + Visibility types.Visibility `json:"visibility,omitempty"` } func createOrgResponse(o *types.Organization) *OrgResponse { org := &OrgResponse{ - ID: o.ID, - Name: o.Name, + ID: o.ID, + Name: o.Name, + Visibility: o.Visibility, } return org } diff --git a/internal/services/types/types.go b/internal/services/types/types.go index 83f22cf..adccedc 100644 --- a/internal/services/types/types.go +++ b/internal/services/types/types.go @@ -107,6 +107,8 @@ type Organization struct { Name string `json:"name,omitempty"` + Visibility Visibility `json:"visibility,omitempty"` + // CreatorUserID is the user id that created the organization. It could be empty // if the org was created by using the admin user or the user has been removed. CreatorUserID string `json:"creator_user_id,omitempty"`