// GetPendingInvitations is the handler for GET /organizations/{globalid}/invitations // Get the list of pending invitations for users to join this organization. func (api OrganizationsAPI) GetPendingInvitations(w http.ResponseWriter, r *http.Request) { globalid := mux.Vars(r)["globalid"] invitationMgr := invitations.NewInvitationManager(r) requests, err := invitationMgr.GetPendingByOrganization(globalid) if err != nil { log.Error("Error in GetPendingByOrganization: ", err.Error()) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } pendingInvites := make([]organization.Invitation, len(requests), len(requests)) for index, request := range requests { pendingInvites[index] = organization.Invitation{ Role: request.Role, User: request.User, Created: request.Created, } } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(pendingInvites) }
// Get the list of notifications, these are pending invitations or approvals // It is handler for GET /users/{username}/notifications func (api UsersAPI) usernamenotificationsGet(w http.ResponseWriter, r *http.Request) { username := mux.Vars(r)["username"] type NotificationList struct { Approvals []invitations.JoinOrganizationInvitation `json:"approvals"` ContractRequests []contract.ContractSigningRequest `json:"contractRequests"` Invitations []invitations.JoinOrganizationInvitation `json:"invitations"` } var notifications NotificationList invititationMgr := invitations.NewInvitationManager(r) userOrgRequests, err := invititationMgr.GetByUser(username) if err != nil { http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } notifications.Invitations = userOrgRequests // TODO: Get Approvals and Contract requests notifications.Approvals = []invitations.JoinOrganizationInvitation{} notifications.ContractRequests = []contract.ContractSigningRequest{} w.Header().Set("Content-type", "application/json") json.NewEncoder(w).Encode(¬ifications) }
// Accept membership in organization // It is handler for POST /users/{username}/organizations/{globalid}/roles/{role} func (api UsersusernameorganizationsAPI) globalidrolesrolePost(w http.ResponseWriter, r *http.Request) { username := mux.Vars(r)["username"] role := mux.Vars(r)["role"] organization := mux.Vars(r)["globalid"] var j invitations.JoinOrganizationInvitation if err := json.NewDecoder(r.Body).Decode(&j); err != nil { http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } orgReqMgr := invitations.NewInvitationManager(r) orgRequest, err := orgReqMgr.Get(username, organization, role, invitations.RequestPending) if err != nil { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } // TODO: Save member orgMgr := organizationpackage.NewManager(r) if org, err := orgMgr.GetByName(organization); err != nil { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } else { if invitations.RoleOwner == orgRequest.Role { // Accepted Owner role if err := orgMgr.SaveOwner(org, username); err != nil { log.Error("Failed to save owner: ", username) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } } else { // Accepted member role if err := orgMgr.SaveMember(org, username); err != nil { log.Error("Failed to save member: ", username) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } } } orgRequest.Status = invitations.RequestAccepted if err := orgReqMgr.Save(orgRequest); err != nil { log.Error("Failed to update org request status: ", orgRequest.Organization) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } w.Header().Set("Content-type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(orgRequest) }
// AddOrganizationOwner It is handler for POST /organizations/{globalid}/owners func (api OrganizationsAPI) AddOrganizationOwner(w http.ResponseWriter, r *http.Request) { globalid := mux.Vars(r)["globalid"] var s searchMember if err := json.NewDecoder(r.Body).Decode(&s); err != nil { http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } orgMgr := organization.NewManager(r) org, err := orgMgr.GetByName(globalid) if err != nil { if err == mgo.ErrNotFound { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) } else { handleServerError(w, "getting organization", err) } return } u, err := SearchUser(r, s.SearchString) if err != nil { log.Error(err) http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } for _, membername := range org.Owners { if membername == u.Username { http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict) return } } // Create JoinRequest invitationMgr := invitations.NewInvitationManager(r) orgReq := &invitations.JoinOrganizationInvitation{ Role: invitations.RoleOwner, Organization: globalid, User: u.Username, Status: invitations.RequestPending, Created: db.DateTime(time.Now()), } if err := invitationMgr.Save(orgReq); err != nil { log.Error("Error inviting owner: ", err.Error()) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(orgReq) }
// It is handler for POST /organizations/{globalid}/members func (api OrganizationsAPI) globalidownersPost(w http.ResponseWriter, r *http.Request) { globalid := mux.Vars(r)["globalid"] var m member if err := json.NewDecoder(r.Body).Decode(&m); err != nil { http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } orgMgr := NewManager(r) org, err := orgMgr.GetByName(globalid) if err != nil { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } // Check if user exists userMgr := user.NewManager(r) if ok, err := userMgr.Exists(m.Username); err != nil || !ok { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } for _, membername := range org.Owners { if membername == m.Username { http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict) return } } // Create JoinRequest invitationMgr := invitations.NewInvitationManager(r) orgReq := &invitations.JoinOrganizationInvitation{ Role: invitations.RoleOwner, Organization: globalid, User: m.Username, Status: invitations.RequestPending, } if err := invitationMgr.Save(orgReq); err != nil { log.Error("Error inviting owner: ", err.Error()) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(orgReq) }
// It is handler for DELETE /users/{username}/organizations/{globalid}/roles/{role} func (api UsersusernameorganizationsAPI) globalidrolesroleDelete(w http.ResponseWriter, r *http.Request) { username := mux.Vars(r)["username"] role := mux.Vars(r)["role"] organization := mux.Vars(r)["globalid"] orgReqMgr := invitations.NewInvitationManager(r) orgRequest, err := orgReqMgr.Get(username, organization, role, invitations.RequestPending) if err != nil { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } orgMgr := organizationpackage.NewManager(r) if org, err := orgMgr.GetByName(organization); err != nil { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } else { if invitations.RoleOwner == orgRequest.Role { // Rejected Owner role if err := orgMgr.RemoveOwner(org, username); err != nil { log.Error("Failed to remove owner: ", username) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } } else { // Rejected member role if err := orgMgr.RemoveMember(org, username); err != nil { log.Error("Failed to reject member: ", username) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } } } orgRequest.Status = invitations.RequestRejected if err := orgReqMgr.Save(orgRequest); err != nil { http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) }
//FilterPossibleScopes filters the requestedScopes to the relevant ones that are possible // For example, a `user:memberof:orgid1` is not possible if the user is not a member the `orgid1` organization and there is no outstanding invite for this organization // If allowInvitations is true, invitations to organizations allows the "user:memberof:organization" as possible scopes func (service *Service) FilterPossibleScopes(r *http.Request, username string, requestedScopes []string, allowInvitations bool) (possibleScopes []string, err error) { possibleScopes = make([]string, 0, len(requestedScopes)) orgmgr := organizationdb.NewManager(r) invitationMgr := invitations.NewInvitationManager(r) for _, rawscope := range requestedScopes { scope := strings.TrimSpace(rawscope) if strings.HasPrefix(scope, "user:memberof:") { orgid := strings.TrimPrefix(scope, "user:memberof:") isMember, err := orgmgr.IsMember(orgid, username) if err != nil { return nil, err } if isMember { possibleScopes = append(possibleScopes, scope) continue } isOwner, err := orgmgr.IsOwner(orgid, username) if err != nil { return nil, err } if isOwner { possibleScopes = append(possibleScopes, scope) continue } if allowInvitations { hasInvite, err := invitationMgr.HasInvite(orgid, username) if err != nil { log.Error("FilterPossibleScopes: Error while checking if user has invite for organization: ", err) return nil, err } if hasInvite { possibleScopes = append(possibleScopes, scope) } } } else { possibleScopes = append(possibleScopes, scope) } } return }
// DeleteOrganization is the handler for DELETE /organizations/{globalid} // Deletes an organization and all data linked to it (join-organization-invitations, oauth_access_tokens, oauth_clients, authorizations) func (api OrganizationsAPI) DeleteOrganization(w http.ResponseWriter, r *http.Request) { globalid := mux.Vars(r)["globalid"] orgMgr := organization.NewManager(r) logoMgr := organization.NewLogoManager(r) if !orgMgr.Exists(globalid) { writeErrorResponse(w, http.StatusNotFound, "organization_not_found") return } suborganizations, err := orgMgr.GetSubOrganizations(globalid) if handleServerError(w, "fetching suborganizations", err) { return } if len(suborganizations) != 0 { writeErrorResponse(w, 422, "organization_has_children") return } err = orgMgr.Remove(globalid) if handleServerError(w, "removing organization", err) { return } // Remove the organizations as a member/ an owner of other organizations organizations, err := orgMgr.AllByOrg(globalid) if handleServerError(w, "fetching organizations where this org is an owner/a member", err) { return } for _, org := range organizations { err = orgMgr.RemoveOrganization(org.Globalid, globalid) if handleServerError(w, "removing organizations as a member / an owner of another organization", err) { return } } if logoMgr.Exists(globalid) { err = logoMgr.Remove(globalid) if handleServerError(w, "removing organization logo", err) { return } } orgReqMgr := invitations.NewInvitationManager(r) err = orgReqMgr.RemoveAll(globalid) if handleServerError(w, "removing organization invitations", err) { return } oauthMgr := oauthservice.NewManager(r) err = oauthMgr.RemoveTokensByGlobalId(globalid) if handleServerError(w, "removing organization oauth accesstokens", err) { return } err = oauthMgr.DeleteAllForOrganization(globalid) if handleServerError(w, "removing client secrets", err) { return } err = oauthMgr.RemoveClientsById(globalid) if handleServerError(w, "removing organization oauth clients", err) { return } userMgr := user.NewManager(r) err = userMgr.DeleteAllAuthorizations(globalid) if handleServerError(w, "removing all authorizations", err) { return } err = oauthMgr.RemoveClientsById(globalid) if handleServerError(w, "removing organization oauth clients", err) { return } l2faMgr := organization.NewLast2FAManager(r) err = l2faMgr.RemoveByOrganization(globalid) if handleServerError(w, "removing organization 2FA history", err) { return } w.WriteHeader(http.StatusNoContent) }
// AddOrganizationMember Assign a member to organization // It is handler for POST /organizations/{globalid}/members func (api OrganizationsAPI) AddOrganizationMember(w http.ResponseWriter, r *http.Request) { globalid := mux.Vars(r)["globalid"] var s searchMember if err := json.NewDecoder(r.Body).Decode(&s); err != nil { http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } orgMgr := organization.NewManager(r) org, err := orgMgr.GetByName(globalid) if err != nil { if err == mgo.ErrNotFound { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) } else { handleServerError(w, "getting organization", err) } return } // Check if user exists u, err := SearchUser(r, s.SearchString) if err != nil { if err != mgo.ErrNotFound { log.Error(err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } for _, membername := range org.Members { if membername == u.Username { http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict) return } } for _, membername := range org.Owners { if membername == u.Username { http.Error(w, http.StatusText(http.StatusConflict), http.StatusConflict) return } } // Create JoinRequest invitationMgr := invitations.NewInvitationManager(r) count, err := invitationMgr.CountByOrganization(globalid) if err != nil { log.Error(err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } if count >= MAX_AMOUNT_INVITATIONS_PER_ORGANIZATION { log.Error("Reached invitation limit for organization ", globalid) writeErrorResponse(w, 422, "max_amount_of_invitations_reached") return } orgReq := &invitations.JoinOrganizationInvitation{ Role: invitations.RoleMember, Organization: globalid, User: u.Username, Status: invitations.RequestPending, Created: db.DateTime(time.Now()), } if err := invitationMgr.Save(orgReq); err != nil { log.Error("Error inviting member: ", err.Error()) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(orgReq) }