influxdb/chronograf/server/organizations.go

233 lines
5.9 KiB
Go
Raw Normal View History

2017-10-20 19:42:34 +00:00
package server
import (
"context"
2017-10-20 19:42:34 +00:00
"encoding/json"
"fmt"
"net/http"
"github.com/bouk/httprouter"
"github.com/influxdata/influxdb/v2/chronograf"
"github.com/influxdata/influxdb/v2/chronograf/organizations"
"github.com/influxdata/influxdb/v2/chronograf/roles"
2017-10-20 19:42:34 +00:00
)
type organizationRequest struct {
2017-11-11 02:23:41 +00:00
Name string `json:"name"`
DefaultRole string `json:"defaultRole"`
2017-10-20 19:42:34 +00:00
}
func (r *organizationRequest) ValidCreate() error {
if r.Name == "" {
return fmt.Errorf("name required on Chronograf Organization request body")
2017-10-20 19:42:34 +00:00
}
return r.ValidDefaultRole()
2017-10-20 19:42:34 +00:00
}
func (r *organizationRequest) ValidUpdate() error {
2018-02-10 00:00:27 +00:00
if r.Name == "" && r.DefaultRole == "" {
return fmt.Errorf("no fields to update")
2017-10-20 19:42:34 +00:00
}
if r.DefaultRole != "" {
return r.ValidDefaultRole()
}
return nil
}
func (r *organizationRequest) ValidDefaultRole() error {
if r.DefaultRole == "" {
2017-11-06 16:31:44 +00:00
r.DefaultRole = roles.MemberRoleName
}
switch r.DefaultRole {
2017-11-06 16:31:44 +00:00
case roles.MemberRoleName, roles.ViewerRoleName, roles.EditorRoleName, roles.AdminRoleName:
return nil
default:
return fmt.Errorf("default role must be member, viewer, editor, or admin")
}
2017-10-20 19:42:34 +00:00
}
type organizationResponse struct {
2017-11-11 02:31:28 +00:00
Links selfLinks `json:"links"`
chronograf.Organization
2017-10-20 19:42:34 +00:00
}
func newOrganizationResponse(o *chronograf.Organization) *organizationResponse {
2017-11-14 02:08:50 +00:00
if o == nil {
o = &chronograf.Organization{}
}
2017-10-20 19:42:34 +00:00
return &organizationResponse{
2017-11-11 02:31:28 +00:00
Organization: *o,
2017-10-20 19:42:34 +00:00
Links: selfLinks{
Self: fmt.Sprintf("/chronograf/v1/organizations/%s", o.ID),
2017-10-20 19:42:34 +00:00
},
}
}
type organizationsResponse struct {
Links selfLinks `json:"links"`
Organizations []*organizationResponse `json:"organizations"`
}
func newOrganizationsResponse(orgs []chronograf.Organization) *organizationsResponse {
orgsResp := make([]*organizationResponse, len(orgs))
for i, org := range orgs {
orgsResp[i] = newOrganizationResponse(&org)
}
return &organizationsResponse{
Organizations: orgsResp,
Links: selfLinks{
Self: "/chronograf/v1/organizations",
},
}
}
// Organizations retrieves all organizations from store
func (s *Service) Organizations(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
orgs, err := s.Store.Organizations(ctx).All(ctx)
2017-10-20 19:42:34 +00:00
if err != nil {
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
res := newOrganizationsResponse(orgs)
encodeJSON(w, http.StatusOK, res, s.Logger)
}
// NewOrganization adds a new organization to store
func (s *Service) NewOrganization(w http.ResponseWriter, r *http.Request) {
var req organizationRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
invalidJSON(w, s.Logger)
return
}
if err := req.ValidCreate(); err != nil {
invalidData(w, err, s.Logger)
return
}
ctx := r.Context()
org := &chronograf.Organization{
Name: req.Name,
DefaultRole: req.DefaultRole,
2017-10-20 19:42:34 +00:00
}
res, err := s.Store.Organizations(ctx).Add(ctx, org)
2017-10-20 19:42:34 +00:00
if err != nil {
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
// Now that the organization was created, add the user
// making the request to the organization
user, ok := hasUserContext(ctx)
if !ok {
// Best attempt at cleanup the organization if there were any errors
_ = s.Store.Organizations(ctx).Delete(ctx, res)
Error(w, http.StatusInternalServerError, "failed to retrieve user from context", s.Logger)
return
}
user.Roles = []chronograf.Role{
{
Organization: res.ID,
Name: roles.AdminRoleName,
},
}
orgCtx := context.WithValue(ctx, organizations.ContextKey, res.ID)
_, err = s.Store.Users(orgCtx).Add(orgCtx, user)
if err != nil {
// Best attempt at cleanup the organization if there were any errors adding user to org
_ = s.Store.Organizations(ctx).Delete(ctx, res)
s.Logger.Error("failed to add user to organization", err.Error())
Error(w, http.StatusInternalServerError, "failed to add user to organization", s.Logger)
return
}
2017-10-20 19:42:34 +00:00
co := newOrganizationResponse(res)
location(w, co.Links.Self)
encodeJSON(w, http.StatusCreated, co, s.Logger)
}
2017-10-23 18:16:31 +00:00
// OrganizationID retrieves a organization with ID from store
2017-10-20 19:42:34 +00:00
func (s *Service) OrganizationID(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
id := httprouter.GetParamFromContext(ctx, "oid")
2017-10-20 19:42:34 +00:00
org, err := s.Store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ID: &id})
2017-10-20 19:42:34 +00:00
if err != nil {
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
res := newOrganizationResponse(org)
encodeJSON(w, http.StatusOK, res, s.Logger)
}
// UpdateOrganization updates an organization in the organizations store
2017-10-20 19:42:34 +00:00
func (s *Service) UpdateOrganization(w http.ResponseWriter, r *http.Request) {
var req organizationRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
invalidJSON(w, s.Logger)
return
}
if err := req.ValidUpdate(); err != nil {
invalidData(w, err, s.Logger)
return
}
ctx := r.Context()
id := httprouter.GetParamFromContext(ctx, "oid")
2017-10-20 19:42:34 +00:00
org, err := s.Store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ID: &id})
2017-10-20 19:42:34 +00:00
if err != nil {
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
if req.Name != "" {
org.Name = req.Name
}
if req.DefaultRole != "" {
org.DefaultRole = req.DefaultRole
}
err = s.Store.Organizations(ctx).Update(ctx, org)
2017-10-20 19:42:34 +00:00
if err != nil {
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
res := newOrganizationResponse(org)
location(w, res.Links.Self)
encodeJSON(w, http.StatusOK, res, s.Logger)
}
// RemoveOrganization removes an organization in the organizations store
2017-10-20 19:42:34 +00:00
func (s *Service) RemoveOrganization(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
id := httprouter.GetParamFromContext(ctx, "oid")
2017-10-20 19:42:34 +00:00
org, err := s.Store.Organizations(ctx).Get(ctx, chronograf.OrganizationQuery{ID: &id})
2017-10-20 19:42:34 +00:00
if err != nil {
Error(w, http.StatusNotFound, err.Error(), s.Logger)
return
}
if err := s.Store.Organizations(ctx).Delete(ctx, org); err != nil {
2017-10-20 19:42:34 +00:00
Error(w, http.StatusBadRequest, err.Error(), s.Logger)
return
}
w.WriteHeader(http.StatusNoContent)
}