2022-01-23 05:58:10 +00:00
|
|
|
package coderd
|
|
|
|
|
|
|
|
import (
|
2022-05-27 16:19:13 +00:00
|
|
|
"database/sql"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2022-03-07 17:40:54 +00:00
|
|
|
"net/http"
|
2022-01-23 05:58:10 +00:00
|
|
|
|
2022-05-27 16:19:13 +00:00
|
|
|
"github.com/google/uuid"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
|
2023-08-18 18:55:43 +00:00
|
|
|
"github.com/coder/coder/v2/coderd/database"
|
2023-09-01 16:50:12 +00:00
|
|
|
"github.com/coder/coder/v2/coderd/database/dbtime"
|
2023-08-18 18:55:43 +00:00
|
|
|
"github.com/coder/coder/v2/coderd/httpapi"
|
|
|
|
"github.com/coder/coder/v2/coderd/httpmw"
|
|
|
|
"github.com/coder/coder/v2/coderd/rbac"
|
|
|
|
"github.com/coder/coder/v2/codersdk"
|
2022-01-23 05:58:10 +00:00
|
|
|
)
|
|
|
|
|
2023-01-11 11:16:09 +00:00
|
|
|
// @Summary Get organization by ID
|
|
|
|
// @ID get-organization-by-id
|
|
|
|
// @Security CoderSessionToken
|
|
|
|
// @Produce json
|
|
|
|
// @Tags Organizations
|
|
|
|
// @Param organization path string true "Organization ID" format(uuid)
|
|
|
|
// @Success 200 {object} codersdk.Organization
|
|
|
|
// @Router /organizations/{organization} [get]
|
2023-03-21 14:10:22 +00:00
|
|
|
func (*API) organization(rw http.ResponseWriter, r *http.Request) {
|
2022-09-21 22:07:00 +00:00
|
|
|
ctx := r.Context()
|
2022-03-07 17:40:54 +00:00
|
|
|
organization := httpmw.OrganizationParam(r)
|
2022-05-17 18:43:19 +00:00
|
|
|
|
2022-09-21 22:07:00 +00:00
|
|
|
httpapi.Write(ctx, rw, http.StatusOK, convertOrganization(organization))
|
2022-03-07 17:40:54 +00:00
|
|
|
}
|
|
|
|
|
2023-01-11 11:16:09 +00:00
|
|
|
// @Summary Create organization
|
|
|
|
// @ID create-organization
|
|
|
|
// @Security CoderSessionToken
|
2023-01-13 11:27:21 +00:00
|
|
|
// @Accept json
|
2023-01-11 11:16:09 +00:00
|
|
|
// @Produce json
|
|
|
|
// @Tags Organizations
|
|
|
|
// @Param request body codersdk.CreateOrganizationRequest true "Create organization request"
|
|
|
|
// @Success 201 {object} codersdk.Organization
|
|
|
|
// @Router /organizations [post]
|
2022-05-27 16:19:13 +00:00
|
|
|
func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
|
2022-09-21 22:07:00 +00:00
|
|
|
ctx := r.Context()
|
2022-05-27 16:19:13 +00:00
|
|
|
apiKey := httpmw.APIKey(r)
|
|
|
|
|
|
|
|
var req codersdk.CreateOrganizationRequest
|
2022-09-21 22:07:00 +00:00
|
|
|
if !httpapi.Read(ctx, rw, r, &req) {
|
2022-05-27 16:19:13 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-03-04 21:15:41 +00:00
|
|
|
if req.Name == codersdk.DefaultOrganization {
|
|
|
|
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
|
|
|
Message: fmt.Sprintf("Organization name %q is reserved.", codersdk.DefaultOrganization),
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-09-21 22:07:00 +00:00
|
|
|
_, err := api.Database.GetOrganizationByName(ctx, req.Name)
|
2022-05-27 16:19:13 +00:00
|
|
|
if err == nil {
|
2022-09-21 22:07:00 +00:00
|
|
|
httpapi.Write(ctx, rw, http.StatusConflict, codersdk.Response{
|
2022-06-07 14:33:06 +00:00
|
|
|
Message: "Organization already exists with that name.",
|
2022-05-27 16:19:13 +00:00
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !errors.Is(err, sql.ErrNoRows) {
|
2022-09-21 22:07:00 +00:00
|
|
|
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
2022-06-07 14:33:06 +00:00
|
|
|
Message: fmt.Sprintf("Internal error fetching organization %q.", req.Name),
|
2022-06-03 21:48:09 +00:00
|
|
|
Detail: err.Error(),
|
2022-05-27 16:19:13 +00:00
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var organization database.Organization
|
2022-10-10 20:37:06 +00:00
|
|
|
err = api.Database.InTx(func(tx database.Store) error {
|
|
|
|
organization, err = tx.InsertOrganization(ctx, database.InsertOrganizationParams{
|
2023-10-03 08:23:45 +00:00
|
|
|
ID: uuid.New(),
|
|
|
|
Name: req.Name,
|
|
|
|
CreatedAt: dbtime.Now(),
|
|
|
|
UpdatedAt: dbtime.Now(),
|
|
|
|
Description: "",
|
2022-05-27 16:19:13 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("create organization: %w", err)
|
|
|
|
}
|
2022-10-10 20:37:06 +00:00
|
|
|
_, err = tx.InsertOrganizationMember(ctx, database.InsertOrganizationMemberParams{
|
2022-05-27 16:19:13 +00:00
|
|
|
OrganizationID: organization.ID,
|
|
|
|
UserID: apiKey.UserID,
|
2023-09-01 16:50:12 +00:00
|
|
|
CreatedAt: dbtime.Now(),
|
|
|
|
UpdatedAt: dbtime.Now(),
|
2022-05-27 16:19:13 +00:00
|
|
|
Roles: []string{
|
2022-12-14 17:05:42 +00:00
|
|
|
// TODO: When organizations are allowed to be created, we should
|
|
|
|
// come back to determining the default role of the person who
|
|
|
|
// creates the org. Until that happens, all users in an organization
|
|
|
|
// should be just regular members.
|
|
|
|
rbac.RoleOrgMember(organization.ID),
|
2022-05-27 16:19:13 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
2022-06-01 14:07:50 +00:00
|
|
|
return xerrors.Errorf("create organization admin: %w", err)
|
2022-05-27 16:19:13 +00:00
|
|
|
}
|
2022-10-10 20:37:06 +00:00
|
|
|
|
|
|
|
_, err = tx.InsertAllUsersGroup(ctx, organization.ID)
|
|
|
|
if err != nil {
|
2023-08-17 18:25:16 +00:00
|
|
|
return xerrors.Errorf("create %q group: %w", database.EveryoneGroup, err)
|
2022-10-10 20:37:06 +00:00
|
|
|
}
|
2022-05-27 16:19:13 +00:00
|
|
|
return nil
|
2022-11-14 17:57:33 +00:00
|
|
|
}, nil)
|
2022-05-27 16:19:13 +00:00
|
|
|
if err != nil {
|
2022-09-21 22:07:00 +00:00
|
|
|
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
2022-06-07 14:33:06 +00:00
|
|
|
Message: "Internal error inserting organization member.",
|
2022-06-03 21:48:09 +00:00
|
|
|
Detail: err.Error(),
|
2022-05-27 16:19:13 +00:00
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-09-21 22:07:00 +00:00
|
|
|
httpapi.Write(ctx, rw, http.StatusCreated, convertOrganization(organization))
|
2022-05-27 16:19:13 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 05:58:10 +00:00
|
|
|
// convertOrganization consumes the database representation and outputs an API friendly representation.
|
2022-03-22 19:17:50 +00:00
|
|
|
func convertOrganization(organization database.Organization) codersdk.Organization {
|
|
|
|
return codersdk.Organization{
|
2022-01-23 05:58:10 +00:00
|
|
|
ID: organization.ID,
|
|
|
|
Name: organization.Name,
|
|
|
|
CreatedAt: organization.CreatedAt,
|
|
|
|
UpdatedAt: organization.UpdatedAt,
|
2024-02-15 17:01:16 +00:00
|
|
|
IsDefault: organization.IsDefault,
|
2022-01-23 05:58:10 +00:00
|
|
|
}
|
|
|
|
}
|