mirror of
https://github.com/coder/coder.git
synced 2026-09-21 12:44:32 +08:00
feat(coderd): add endpoints for editing and deleting organizations (#13287)
This commit is contained in:
Vendored
-1
@@ -195,7 +195,6 @@
|
||||
"**.pb.go": true,
|
||||
"**/*.gen.json": true,
|
||||
"**/testdata/*": true,
|
||||
"**Generated.ts": true,
|
||||
"coderd/apidoc/**": true,
|
||||
"docs/api/*.md": true,
|
||||
"docs/templates/*.md": true,
|
||||
|
||||
Generated
+87
@@ -1987,6 +1987,82 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Organizations"
|
||||
],
|
||||
"summary": "Delete organization",
|
||||
"operationId": "delete-organization",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Organization ID or name",
|
||||
"name": "organization",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Organizations"
|
||||
],
|
||||
"summary": "Update organization",
|
||||
"operationId": "update-organization",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Organization ID or name",
|
||||
"name": "organization",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Patch organization request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.UpdateOrganizationRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.Organization"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/organizations/{organization}/groups": {
|
||||
@@ -12099,6 +12175,17 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.UpdateOrganizationRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.UpdateRoles": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
Generated
+75
@@ -1732,6 +1732,72 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Organizations"],
|
||||
"summary": "Delete organization",
|
||||
"operationId": "delete-organization",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Organization ID or name",
|
||||
"name": "organization",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Organizations"],
|
||||
"summary": "Update organization",
|
||||
"operationId": "update-organization",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Organization ID or name",
|
||||
"name": "organization",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Patch organization request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.UpdateOrganizationRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.Organization"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/organizations/{organization}/groups": {
|
||||
@@ -10958,6 +11024,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.UpdateOrganizationRequest": {
|
||||
"type": "object",
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.UpdateRoles": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -812,6 +812,8 @@ func New(options *Options) *API {
|
||||
httpmw.ExtractOrganizationParam(options.Database),
|
||||
)
|
||||
r.Get("/", api.organization)
|
||||
r.Patch("/", api.patchOrganization)
|
||||
r.Delete("/", api.deleteOrganization)
|
||||
r.Post("/templateversions", api.postTemplateVersionsByOrganization)
|
||||
r.Route("/templates", func(r chi.Router) {
|
||||
r.Post("/", api.postTemplateByOrganization)
|
||||
|
||||
@@ -984,6 +984,10 @@ func (q *querier) DeleteOldWorkspaceAgentStats(ctx context.Context) error {
|
||||
return q.db.DeleteOldWorkspaceAgentStats(ctx)
|
||||
}
|
||||
|
||||
func (q *querier) DeleteOrganization(ctx context.Context, id uuid.UUID) error {
|
||||
return deleteQ(q.log, q.auth, q.db.GetOrganizationByID, q.db.DeleteOrganization)(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) DeleteReplicasUpdatedBefore(ctx context.Context, updatedAt time.Time) error {
|
||||
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceSystem); err != nil {
|
||||
return err
|
||||
@@ -2853,6 +2857,13 @@ func (q *querier) UpdateOAuth2ProviderAppSecretByID(ctx context.Context, arg dat
|
||||
return q.db.UpdateOAuth2ProviderAppSecretByID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateOrganization(ctx context.Context, arg database.UpdateOrganizationParams) (database.Organization, error) {
|
||||
fetch := func(ctx context.Context, arg database.UpdateOrganizationParams) (database.Organization, error) {
|
||||
return q.db.GetOrganizationByID(ctx, arg.ID)
|
||||
}
|
||||
return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateOrganization)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateProvisionerDaemonLastSeenAt(ctx context.Context, arg database.UpdateProvisionerDaemonLastSeenAtParams) error {
|
||||
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceProvisionerDaemon); err != nil {
|
||||
return err
|
||||
|
||||
@@ -624,7 +624,7 @@ func (s *MethodTestSuite) TestOrganization() {
|
||||
s.Run("InsertOrganization", s.Subtest(func(db database.Store, check *expects) {
|
||||
check.Args(database.InsertOrganizationParams{
|
||||
ID: uuid.New(),
|
||||
Name: "random",
|
||||
Name: "new-org",
|
||||
}).Asserts(rbac.ResourceOrganization, policy.ActionCreate)
|
||||
}))
|
||||
s.Run("InsertOrganizationMember", s.Subtest(func(db database.Store, check *expects) {
|
||||
@@ -639,6 +639,23 @@ func (s *MethodTestSuite) TestOrganization() {
|
||||
rbac.ResourceAssignRole.InOrg(o.ID), policy.ActionAssign,
|
||||
rbac.ResourceOrganizationMember.InOrg(o.ID).WithID(u.ID), policy.ActionCreate)
|
||||
}))
|
||||
s.Run("UpdateOrganization", s.Subtest(func(db database.Store, check *expects) {
|
||||
o := dbgen.Organization(s.T(), db, database.Organization{
|
||||
Name: "something-unique",
|
||||
})
|
||||
check.Args(database.UpdateOrganizationParams{
|
||||
ID: o.ID,
|
||||
Name: "something-different",
|
||||
}).Asserts(o, policy.ActionUpdate)
|
||||
}))
|
||||
s.Run("DeleteOrganization", s.Subtest(func(db database.Store, check *expects) {
|
||||
o := dbgen.Organization(s.T(), db, database.Organization{
|
||||
Name: "doomed",
|
||||
})
|
||||
check.Args(
|
||||
o.ID,
|
||||
).Asserts(o, policy.ActionDelete)
|
||||
}))
|
||||
s.Run("UpdateMemberRoles", s.Subtest(func(db database.Store, check *expects) {
|
||||
o := dbgen.Organization(s.T(), db, database.Organization{})
|
||||
u := dbgen.User(s.T(), db, database.User{})
|
||||
|
||||
@@ -33,15 +33,18 @@ import (
|
||||
|
||||
var validProxyByHostnameRegex = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`)
|
||||
|
||||
var errForeignKeyConstraint = &pq.Error{
|
||||
Code: "23503",
|
||||
Message: "update or delete on table violates foreign key constraint",
|
||||
}
|
||||
|
||||
var errDuplicateKey = &pq.Error{
|
||||
Code: "23505",
|
||||
Message: "duplicate key value violates unique constraint",
|
||||
}
|
||||
// A full mapping of error codes from pq v1.10.9 can be found here:
|
||||
// https://github.com/lib/pq/blob/2a217b94f5ccd3de31aec4152a541b9ff64bed05/error.go#L75
|
||||
var (
|
||||
errForeignKeyConstraint = &pq.Error{
|
||||
Code: "23503", // "foreign_key_violation"
|
||||
Message: "update or delete on table violates foreign key constraint",
|
||||
}
|
||||
errUniqueConstraint = &pq.Error{
|
||||
Code: "23505", // "unique_violation"
|
||||
Message: "duplicate key value violates unique constraint",
|
||||
}
|
||||
)
|
||||
|
||||
// New returns an in-memory fake of the database.
|
||||
func New() database.Store {
|
||||
@@ -1601,6 +1604,19 @@ func (q *FakeQuerier) DeleteOldWorkspaceAgentStats(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) DeleteOrganization(_ context.Context, id uuid.UUID) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
for i, org := range q.organizations {
|
||||
if org.ID == id && !org.IsDefault {
|
||||
q.organizations = append(q.organizations[:i], q.organizations[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) DeleteReplicasUpdatedBefore(_ context.Context, before time.Time) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
@@ -5823,7 +5839,7 @@ func (q *FakeQuerier) InsertDBCryptKey(_ context.Context, arg database.InsertDBC
|
||||
|
||||
for _, key := range q.dbcryptKeys {
|
||||
if key.Number == arg.Number {
|
||||
return errDuplicateKey
|
||||
return errUniqueConstraint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5927,7 +5943,7 @@ func (q *FakeQuerier) InsertGroup(_ context.Context, arg database.InsertGroupPar
|
||||
for _, group := range q.groups {
|
||||
if group.OrganizationID == arg.OrganizationID &&
|
||||
group.Name == arg.Name {
|
||||
return database.Group{}, errDuplicateKey
|
||||
return database.Group{}, errUniqueConstraint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5958,7 +5974,7 @@ func (q *FakeQuerier) InsertGroupMember(_ context.Context, arg database.InsertGr
|
||||
for _, member := range q.groupMembers {
|
||||
if member.GroupID == arg.GroupID &&
|
||||
member.UserID == arg.UserID {
|
||||
return errDuplicateKey
|
||||
return errUniqueConstraint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6042,7 +6058,7 @@ func (q *FakeQuerier) InsertOAuth2ProviderApp(_ context.Context, arg database.In
|
||||
|
||||
for _, app := range q.oauth2ProviderApps {
|
||||
if app.Name == arg.Name {
|
||||
return database.OAuth2ProviderApp{}, errDuplicateKey
|
||||
return database.OAuth2ProviderApp{}, errUniqueConstraint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6423,7 +6439,7 @@ func (q *FakeQuerier) InsertUser(_ context.Context, arg database.InsertUserParam
|
||||
|
||||
for _, user := range q.users {
|
||||
if user.Username == arg.Username && !user.Deleted {
|
||||
return database.User{}, errDuplicateKey
|
||||
return database.User{}, errUniqueConstraint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6836,7 +6852,7 @@ func (q *FakeQuerier) InsertWorkspaceProxy(_ context.Context, arg database.Inser
|
||||
lastRegionID := int32(0)
|
||||
for _, p := range q.workspaceProxies {
|
||||
if !p.Deleted && p.Name == arg.Name {
|
||||
return database.WorkspaceProxy{}, errDuplicateKey
|
||||
return database.WorkspaceProxy{}, errUniqueConstraint
|
||||
}
|
||||
if p.RegionID > lastRegionID {
|
||||
lastRegionID = p.RegionID
|
||||
@@ -7230,7 +7246,7 @@ func (q *FakeQuerier) UpdateOAuth2ProviderAppByID(_ context.Context, arg databas
|
||||
|
||||
for _, app := range q.oauth2ProviderApps {
|
||||
if app.Name == arg.Name && app.ID != arg.ID {
|
||||
return database.OAuth2ProviderApp{}, errDuplicateKey
|
||||
return database.OAuth2ProviderApp{}, errUniqueConstraint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7278,6 +7294,33 @@ func (q *FakeQuerier) UpdateOAuth2ProviderAppSecretByID(_ context.Context, arg d
|
||||
return database.OAuth2ProviderAppSecret{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpdateOrganization(_ context.Context, arg database.UpdateOrganizationParams) (database.Organization, error) {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
return database.Organization{}, err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
// Enforce the unique constraint, because the API endpoint relies on the database catching
|
||||
// non-unique names during updates.
|
||||
for _, org := range q.organizations {
|
||||
if org.Name == arg.Name && org.ID != arg.ID {
|
||||
return database.Organization{}, errUniqueConstraint
|
||||
}
|
||||
}
|
||||
|
||||
for i, org := range q.organizations {
|
||||
if org.ID == arg.ID {
|
||||
org.Name = arg.Name
|
||||
q.organizations[i] = org
|
||||
return org, nil
|
||||
}
|
||||
}
|
||||
return database.Organization{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpdateProvisionerDaemonLastSeenAt(_ context.Context, arg database.UpdateProvisionerDaemonLastSeenAtParams) error {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
@@ -7875,7 +7918,7 @@ func (q *FakeQuerier) UpdateWorkspace(_ context.Context, arg database.UpdateWork
|
||||
continue
|
||||
}
|
||||
if other.Name == arg.Name {
|
||||
return database.Workspace{}, errDuplicateKey
|
||||
return database.Workspace{}, errUniqueConstraint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8215,7 +8258,7 @@ func (q *FakeQuerier) UpdateWorkspaceProxy(_ context.Context, arg database.Updat
|
||||
|
||||
for _, p := range q.workspaceProxies {
|
||||
if p.Name == arg.Name && p.ID != arg.ID {
|
||||
return database.WorkspaceProxy{}, errDuplicateKey
|
||||
return database.WorkspaceProxy{}, errUniqueConstraint
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -284,6 +284,13 @@ func (m metricsStore) DeleteOldWorkspaceAgentStats(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (m metricsStore) DeleteOrganization(ctx context.Context, id uuid.UUID) error {
|
||||
start := time.Now()
|
||||
r0 := m.s.DeleteOrganization(ctx, id)
|
||||
m.queryLatencies.WithLabelValues("DeleteOrganization").Observe(time.Since(start).Seconds())
|
||||
return r0
|
||||
}
|
||||
|
||||
func (m metricsStore) DeleteReplicasUpdatedBefore(ctx context.Context, updatedAt time.Time) error {
|
||||
start := time.Now()
|
||||
err := m.s.DeleteReplicasUpdatedBefore(ctx, updatedAt)
|
||||
@@ -1845,6 +1852,13 @@ func (m metricsStore) UpdateOAuth2ProviderAppSecretByID(ctx context.Context, arg
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m metricsStore) UpdateOrganization(ctx context.Context, arg database.UpdateOrganizationParams) (database.Organization, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.UpdateOrganization(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("UpdateOrganization").Observe(time.Since(start).Seconds())
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m metricsStore) UpdateProvisionerDaemonLastSeenAt(ctx context.Context, arg database.UpdateProvisionerDaemonLastSeenAtParams) error {
|
||||
start := time.Now()
|
||||
r0 := m.s.UpdateProvisionerDaemonLastSeenAt(ctx, arg)
|
||||
|
||||
@@ -455,6 +455,20 @@ func (mr *MockStoreMockRecorder) DeleteOldWorkspaceAgentStats(arg0 any) *gomock.
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOldWorkspaceAgentStats", reflect.TypeOf((*MockStore)(nil).DeleteOldWorkspaceAgentStats), arg0)
|
||||
}
|
||||
|
||||
// DeleteOrganization mocks base method.
|
||||
func (m *MockStore) DeleteOrganization(arg0 context.Context, arg1 uuid.UUID) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteOrganization", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteOrganization indicates an expected call of DeleteOrganization.
|
||||
func (mr *MockStoreMockRecorder) DeleteOrganization(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOrganization", reflect.TypeOf((*MockStore)(nil).DeleteOrganization), arg0, arg1)
|
||||
}
|
||||
|
||||
// DeleteReplicasUpdatedBefore mocks base method.
|
||||
func (m *MockStore) DeleteReplicasUpdatedBefore(arg0 context.Context, arg1 time.Time) error {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -3881,6 +3895,21 @@ func (mr *MockStoreMockRecorder) UpdateOAuth2ProviderAppSecretByID(arg0, arg1 an
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateOAuth2ProviderAppSecretByID", reflect.TypeOf((*MockStore)(nil).UpdateOAuth2ProviderAppSecretByID), arg0, arg1)
|
||||
}
|
||||
|
||||
// UpdateOrganization mocks base method.
|
||||
func (m *MockStore) UpdateOrganization(arg0 context.Context, arg1 database.UpdateOrganizationParams) (database.Organization, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateOrganization", arg0, arg1)
|
||||
ret0, _ := ret[0].(database.Organization)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpdateOrganization indicates an expected call of UpdateOrganization.
|
||||
func (mr *MockStoreMockRecorder) UpdateOrganization(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateOrganization", reflect.TypeOf((*MockStore)(nil).UpdateOrganization), arg0, arg1)
|
||||
}
|
||||
|
||||
// UpdateProvisionerDaemonLastSeenAt mocks base method.
|
||||
func (m *MockStore) UpdateProvisionerDaemonLastSeenAt(arg0 context.Context, arg1 database.UpdateProvisionerDaemonLastSeenAtParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -74,6 +74,7 @@ type sqlcQuerier interface {
|
||||
// Logs can take up a lot of space, so it's important we clean up frequently.
|
||||
DeleteOldWorkspaceAgentLogs(ctx context.Context) error
|
||||
DeleteOldWorkspaceAgentStats(ctx context.Context) error
|
||||
DeleteOrganization(ctx context.Context, id uuid.UUID) error
|
||||
DeleteReplicasUpdatedBefore(ctx context.Context, updatedAt time.Time) error
|
||||
DeleteTailnetAgent(ctx context.Context, arg DeleteTailnetAgentParams) (DeleteTailnetAgentRow, error)
|
||||
DeleteTailnetClient(ctx context.Context, arg DeleteTailnetClientParams) (DeleteTailnetClientRow, error)
|
||||
@@ -368,6 +369,7 @@ type sqlcQuerier interface {
|
||||
UpdateMemberRoles(ctx context.Context, arg UpdateMemberRolesParams) (OrganizationMember, error)
|
||||
UpdateOAuth2ProviderAppByID(ctx context.Context, arg UpdateOAuth2ProviderAppByIDParams) (OAuth2ProviderApp, error)
|
||||
UpdateOAuth2ProviderAppSecretByID(ctx context.Context, arg UpdateOAuth2ProviderAppSecretByIDParams) (OAuth2ProviderAppSecret, error)
|
||||
UpdateOrganization(ctx context.Context, arg UpdateOrganizationParams) (Organization, error)
|
||||
UpdateProvisionerDaemonLastSeenAt(ctx context.Context, arg UpdateProvisionerDaemonLastSeenAtParams) error
|
||||
UpdateProvisionerJobByID(ctx context.Context, arg UpdateProvisionerJobByIDParams) error
|
||||
UpdateProvisionerJobWithCancelByID(ctx context.Context, arg UpdateProvisionerJobWithCancelByIDParams) error
|
||||
|
||||
@@ -3934,6 +3934,19 @@ func (q *sqlQuerier) UpdateMemberRoles(ctx context.Context, arg UpdateMemberRole
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteOrganization = `-- name: DeleteOrganization :exec
|
||||
DELETE FROM
|
||||
organizations
|
||||
WHERE
|
||||
id = $1 AND
|
||||
is_default = false
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) DeleteOrganization(ctx context.Context, id uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteOrganization, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const getDefaultOrganization = `-- name: GetDefaultOrganization :one
|
||||
SELECT
|
||||
id, name, description, created_at, updated_at, is_default
|
||||
@@ -4126,6 +4139,37 @@ func (q *sqlQuerier) InsertOrganization(ctx context.Context, arg InsertOrganizat
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateOrganization = `-- name: UpdateOrganization :one
|
||||
UPDATE
|
||||
organizations
|
||||
SET
|
||||
updated_at = $1,
|
||||
name = $2
|
||||
WHERE
|
||||
id = $3
|
||||
RETURNING id, name, description, created_at, updated_at, is_default
|
||||
`
|
||||
|
||||
type UpdateOrganizationParams struct {
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
Name string `db:"name" json:"name"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateOrganization(ctx context.Context, arg UpdateOrganizationParams) (Organization, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateOrganization, arg.UpdatedAt, arg.Name, arg.ID)
|
||||
var i Organization
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.Description,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.IsDefault,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getParameterSchemasByJobID = `-- name: GetParameterSchemasByJobID :many
|
||||
SELECT
|
||||
id, created_at, job_id, name, description, default_source_scheme, default_source_value, allow_override_source, default_destination_scheme, allow_override_destination, default_refresh, redisplay_value, validation_error, validation_condition, validation_type_system, validation_value_type, index
|
||||
|
||||
@@ -53,3 +53,20 @@ INSERT INTO
|
||||
VALUES
|
||||
-- If no organizations exist, and this is the first, make it the default.
|
||||
($1, $2, $3, $4, $5, (SELECT TRUE FROM organizations LIMIT 1) IS NULL) RETURNING *;
|
||||
|
||||
-- name: UpdateOrganization :one
|
||||
UPDATE
|
||||
organizations
|
||||
SET
|
||||
updated_at = @updated_at,
|
||||
name = @name
|
||||
WHERE
|
||||
id = @id
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteOrganization :exec
|
||||
DELETE FROM
|
||||
organizations
|
||||
WHERE
|
||||
id = $1 AND
|
||||
is_default = false;
|
||||
|
||||
@@ -118,6 +118,97 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(ctx, rw, http.StatusCreated, convertOrganization(organization))
|
||||
}
|
||||
|
||||
// @Summary Update organization
|
||||
// @ID update-organization
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Organizations
|
||||
// @Param organization path string true "Organization ID or name"
|
||||
// @Param request body codersdk.UpdateOrganizationRequest true "Patch organization request"
|
||||
// @Success 200 {object} codersdk.Organization
|
||||
// @Router /organizations/{organization} [patch]
|
||||
func (api *API) patchOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
organization := httpmw.OrganizationParam(r)
|
||||
|
||||
var req codersdk.UpdateOrganizationRequest
|
||||
if !httpapi.Read(ctx, rw, r, &req) {
|
||||
return
|
||||
}
|
||||
|
||||
// "default" is a reserved name that always refers to the default org (much like the way we
|
||||
// use "me" for users).
|
||||
if req.Name == codersdk.DefaultOrganization {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: fmt.Sprintf("Organization name %q is reserved.", codersdk.DefaultOrganization),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
organization, err := api.Database.UpdateOrganization(ctx, database.UpdateOrganizationParams{
|
||||
ID: organization.ID,
|
||||
UpdatedAt: dbtime.Now(),
|
||||
Name: req.Name,
|
||||
})
|
||||
if httpapi.Is404Error(err) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if database.IsUniqueViolation(err) {
|
||||
httpapi.Write(ctx, rw, http.StatusConflict, codersdk.Response{
|
||||
Message: fmt.Sprintf("Organization already exists with the name %q.", req.Name),
|
||||
Validations: []codersdk.ValidationError{{
|
||||
Field: "name",
|
||||
Detail: "This value is already in use and should be unique.",
|
||||
}},
|
||||
})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error updating organization.",
|
||||
Detail: fmt.Sprintf("update organization: %s", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertOrganization(organization))
|
||||
}
|
||||
|
||||
// @Summary Delete organization
|
||||
// @ID delete-organization
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Organizations
|
||||
// @Param organization path string true "Organization ID or name"
|
||||
// @Success 200 {object} codersdk.Response
|
||||
// @Router /organizations/{organization} [delete]
|
||||
func (api *API) deleteOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
organization := httpmw.OrganizationParam(r)
|
||||
|
||||
if organization.IsDefault {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Default organization cannot be deleted.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := api.Database.DeleteOrganization(ctx, organization.ID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error deleting organization.",
|
||||
Detail: fmt.Sprintf("delete organization: %s", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, codersdk.Response{
|
||||
Message: "Organization has been deleted.",
|
||||
})
|
||||
}
|
||||
|
||||
// convertOrganization consumes the database representation and outputs an API friendly representation.
|
||||
func convertOrganization(organization database.Organization) codersdk.Organization {
|
||||
return codersdk.Organization{
|
||||
|
||||
+134
-22
@@ -1,7 +1,6 @@
|
||||
package coderd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -16,9 +15,7 @@ func TestMultiOrgFetch(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
makeOrgs := []string{"foo", "bar", "baz"}
|
||||
for _, name := range makeOrgs {
|
||||
@@ -38,9 +35,7 @@ func TestOrganizationsByUser(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
orgs, err := client.OrganizationsByUser(ctx, codersdk.Me)
|
||||
require.NoError(t, err)
|
||||
@@ -62,9 +57,7 @@ func TestOrganizationByUserAndName(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
_, err := client.OrganizationByUserAndName(ctx, codersdk.Me, "nothing")
|
||||
var apiErr *codersdk.Error
|
||||
@@ -77,9 +70,7 @@ func TestOrganizationByUserAndName(t *testing.T) {
|
||||
client := coderdtest.New(t, nil)
|
||||
first := coderdtest.CreateFirstUser(t, client)
|
||||
other, _ := coderdtest.CreateAnotherUser(t, client, first.OrganizationID)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
org, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
|
||||
Name: "another",
|
||||
@@ -95,9 +86,7 @@ func TestOrganizationByUserAndName(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
org, err := client.Organization(ctx, user.OrganizationID)
|
||||
require.NoError(t, err)
|
||||
@@ -112,9 +101,7 @@ func TestPostOrganizationsByUser(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
org, err := client.Organization(ctx, user.OrganizationID)
|
||||
require.NoError(t, err)
|
||||
@@ -130,9 +117,7 @@ func TestPostOrganizationsByUser(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
_, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
|
||||
Name: "new",
|
||||
@@ -140,3 +125,130 @@ func TestPostOrganizationsByUser(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPatchOrganizationsByUser(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("Conflict", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
originalOrg, err := client.Organization(ctx, user.OrganizationID)
|
||||
require.NoError(t, err)
|
||||
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
|
||||
Name: "something-unique",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.UpdateOrganization(ctx, o.ID.String(), codersdk.UpdateOrganizationRequest{
|
||||
Name: originalOrg.Name,
|
||||
})
|
||||
var apiErr *codersdk.Error
|
||||
require.ErrorAs(t, err, &apiErr)
|
||||
require.Equal(t, http.StatusConflict, apiErr.StatusCode())
|
||||
})
|
||||
|
||||
t.Run("ReservedName", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
|
||||
Name: "something-unique",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.UpdateOrganization(ctx, o.ID.String(), codersdk.UpdateOrganizationRequest{
|
||||
Name: codersdk.DefaultOrganization,
|
||||
})
|
||||
var apiErr *codersdk.Error
|
||||
require.ErrorAs(t, err, &apiErr)
|
||||
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
||||
})
|
||||
|
||||
t.Run("UpdateById", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
|
||||
Name: "new",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
o, err = client.UpdateOrganization(ctx, o.ID.String(), codersdk.UpdateOrganizationRequest{
|
||||
Name: "new-new",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "new-new", o.Name)
|
||||
})
|
||||
|
||||
t.Run("UpdateByName", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
|
||||
Name: "new",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
o, err = client.UpdateOrganization(ctx, o.Name, codersdk.UpdateOrganizationRequest{
|
||||
Name: "new-new",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "new-new", o.Name)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteOrganizationsByUser(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("Default", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
o, err := client.Organization(ctx, user.OrganizationID)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.DeleteOrganization(ctx, o.ID.String())
|
||||
var apiErr *codersdk.Error
|
||||
require.ErrorAs(t, err, &apiErr)
|
||||
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
||||
})
|
||||
|
||||
t.Run("DeleteById", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
|
||||
Name: "doomed",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.DeleteOrganization(ctx, o.ID.String())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("DeleteByName", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
o, err := client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
|
||||
Name: "doomed",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.DeleteOrganization(ctx, o.Name)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -55,6 +55,14 @@ type OrganizationMember struct {
|
||||
Roles []SlimRole `db:"roles" json:"roles"`
|
||||
}
|
||||
|
||||
type CreateOrganizationRequest struct {
|
||||
Name string `json:"name" validate:"required,username"`
|
||||
}
|
||||
|
||||
type UpdateOrganizationRequest struct {
|
||||
Name string `json:"name" validate:"required,username"`
|
||||
}
|
||||
|
||||
// CreateTemplateVersionRequest enables callers to create a new Template Version.
|
||||
type CreateTemplateVersionRequest struct {
|
||||
Name string `json:"name,omitempty" validate:"omitempty,template_version_name"`
|
||||
@@ -187,6 +195,55 @@ func (c *Client) Organization(ctx context.Context, id uuid.UUID) (Organization,
|
||||
return c.OrganizationByName(ctx, id.String())
|
||||
}
|
||||
|
||||
// CreateOrganization creates an organization and adds the user making the request as an owner.
|
||||
func (c *Client) CreateOrganization(ctx context.Context, req CreateOrganizationRequest) (Organization, error) {
|
||||
res, err := c.Request(ctx, http.MethodPost, "/api/v2/organizations", req)
|
||||
if err != nil {
|
||||
return Organization{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
return Organization{}, ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
var org Organization
|
||||
return org, json.NewDecoder(res.Body).Decode(&org)
|
||||
}
|
||||
|
||||
// UpdateOrganization will update information about the corresponding organization, based on
|
||||
// the UUID/name provided as `orgID`.
|
||||
func (c *Client) UpdateOrganization(ctx context.Context, orgID string, req UpdateOrganizationRequest) (Organization, error) {
|
||||
res, err := c.Request(ctx, http.MethodPatch, fmt.Sprintf("/api/v2/organizations/%s", orgID), req)
|
||||
if err != nil {
|
||||
return Organization{}, xerrors.Errorf("execute request: %w", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return Organization{}, ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
var organization Organization
|
||||
return organization, json.NewDecoder(res.Body).Decode(&organization)
|
||||
}
|
||||
|
||||
// DeleteOrganization will remove the corresponding organization from the deployment, based on
|
||||
// the UUID/name provided as `orgID`.
|
||||
func (c *Client) DeleteOrganization(ctx context.Context, orgID string) error {
|
||||
res, err := c.Request(ctx, http.MethodDelete, fmt.Sprintf("/api/v2/organizations/%s", orgID), nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("execute request: %w", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProvisionerDaemons returns provisioner daemons available.
|
||||
func (c *Client) ProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet,
|
||||
|
||||
@@ -203,10 +203,6 @@ type OAuthConversionResponse struct {
|
||||
UserID uuid.UUID `json:"user_id" format:"uuid"`
|
||||
}
|
||||
|
||||
type CreateOrganizationRequest struct {
|
||||
Name string `json:"name" validate:"required,username"`
|
||||
}
|
||||
|
||||
// AuthMethods contains authentication method information like whether they are enabled or not or custom text, etc.
|
||||
type AuthMethods struct {
|
||||
TermsOfServiceURL string `json:"terms_of_service_url,omitempty"`
|
||||
@@ -587,22 +583,6 @@ func (c *Client) OrganizationByUserAndName(ctx context.Context, user string, nam
|
||||
return org, json.NewDecoder(res.Body).Decode(&org)
|
||||
}
|
||||
|
||||
// CreateOrganization creates an organization and adds the provided user as an admin.
|
||||
func (c *Client) CreateOrganization(ctx context.Context, req CreateOrganizationRequest) (Organization, error) {
|
||||
res, err := c.Request(ctx, http.MethodPost, "/api/v2/organizations", req)
|
||||
if err != nil {
|
||||
return Organization{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
return Organization{}, ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
var org Organization
|
||||
return org, json.NewDecoder(res.Body).Decode(&org)
|
||||
}
|
||||
|
||||
// AuthMethods returns types of authentication available to the user.
|
||||
func (c *Client) AuthMethods(ctx context.Context) (AuthMethods, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, "/api/v2/users/authmethods", nil)
|
||||
|
||||
Generated
+95
@@ -177,3 +177,98 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization} \
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Organization](schemas.md#codersdkorganization) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Delete organization
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X DELETE http://coder-server:8080/api/v2/organizations/{organization} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`DELETE /organizations/{organization}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| -------------- | ---- | ------ | -------- | ----------------------- |
|
||||
| `organization` | path | string | true | Organization ID or name |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "string",
|
||||
"message": "string",
|
||||
"validations": [
|
||||
{
|
||||
"detail": "string",
|
||||
"field": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Response](schemas.md#codersdkresponse) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Update organization
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X PATCH http://coder-server:8080/api/v2/organizations/{organization} \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`PATCH /organizations/{organization}`
|
||||
|
||||
> Body parameter
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| -------------- | ---- | ---------------------------------------------------------------------------------- | -------- | -------------------------- |
|
||||
| `organization` | path | string | true | Organization ID or name |
|
||||
| `body` | body | [codersdk.UpdateOrganizationRequest](schemas.md#codersdkupdateorganizationrequest) | true | Patch organization request |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"is_default": true,
|
||||
"name": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------- |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Organization](schemas.md#codersdkorganization) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
Generated
+14
@@ -5361,6 +5361,20 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
|
||||
| `url` | string | false | | URL to download the latest release of Coder. |
|
||||
| `version` | string | false | | Version is the semantic version for the latest release of Coder. |
|
||||
|
||||
## codersdk.UpdateOrganizationRequest
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------ | ------ | -------- | ------------ | ----------- |
|
||||
| `name` | string | true | | |
|
||||
|
||||
## codersdk.UpdateRoles
|
||||
|
||||
```json
|
||||
|
||||
Generated
+6
-1
@@ -223,7 +223,7 @@ export interface CreateGroupRequest {
|
||||
readonly quota_allowance: number;
|
||||
}
|
||||
|
||||
// From codersdk/users.go
|
||||
// From codersdk/organizations.go
|
||||
export interface CreateOrganizationRequest {
|
||||
readonly name: string;
|
||||
}
|
||||
@@ -1318,6 +1318,11 @@ export interface UpdateCheckResponse {
|
||||
readonly url: string;
|
||||
}
|
||||
|
||||
// From codersdk/organizations.go
|
||||
export interface UpdateOrganizationRequest {
|
||||
readonly name: string;
|
||||
}
|
||||
|
||||
// From codersdk/users.go
|
||||
export interface UpdateRoles {
|
||||
readonly roles: readonly string[];
|
||||
|
||||
Reference in New Issue
Block a user