diff --git a/backend/src/database/sql.go b/backend/src/database/sql.go index 01ae9cef..5f047b2e 100644 --- a/backend/src/database/sql.go +++ b/backend/src/database/sql.go @@ -15,6 +15,13 @@ var ( WHERE user_id = $1 AND deleted = false` + SelectAllUsersByOrgIdStatement = `SELECT u.user_id, u.name, u.identity_provider, u.created_on, u.deleted, m.role, m.joined_on + FROM public."user" u + INNER JOIN public."membership" m + ON u.user_id = m.user_id + WHERE m.org_id = $1 + AND u.deleted = false` + CheckUserExistsStatement = `SELECT * FROM public."user" WHERE user_id = $1 diff --git a/backend/src/database/user.go b/backend/src/database/user.go index 1f6d23d3..9aa5912c 100644 --- a/backend/src/database/user.go +++ b/backend/src/database/user.go @@ -2,6 +2,7 @@ package database import ( "database/sql" + "time" "github.com/joshtyf/flowforge/src/database/models" ) @@ -28,3 +29,31 @@ func (u *User) GetUserById(user_id string) (*models.UserModel, error) { } return um, nil } + +type GetAllUsersByOrdIdResponse struct { + UserId string `json:"user_id"` + Name string `json:"name"` + IdentityProvider string `json:"identity_provider"` + CreatedOn time.Time `json:"created_on"` + Deleted bool `json:"deleted"` + Role string `json:"role"` + JoinedOn time.Time `json:"joined_on"` +} + +func (u *User) GetAllUsersByOrgId(orgId int) ([]*GetAllUsersByOrdIdResponse, error) { + rows, err := u.c.Query(SelectAllUsersByOrgIdStatement, orgId) + if err != nil { + return nil, err + } + defer rows.Close() + + users := make([]*GetAllUsersByOrdIdResponse, 0) + for rows.Next() { + um := &GetAllUsersByOrdIdResponse{} + if err := rows.Scan(&um.UserId, &um.Name, &um.IdentityProvider, &um.CreatedOn, &um.Deleted, &um.Role, &um.JoinedOn); err != nil { + return nil, err + } + users = append(users, um) + } + return users, nil +} diff --git a/backend/src/server/handlers.go b/backend/src/server/handlers.go index 15e2ce2b..cb646f98 100644 --- a/backend/src/server/handlers.go +++ b/backend/src/server/handlers.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/http" + "strconv" "strings" "time" @@ -78,6 +79,7 @@ func (s *ServerHandler) registerRoutes(r *mux.Router) { r.Handle("/api/organization", isAuthenticated(handleGetOrganizationsForUser(s.logger, s.psqlClient), s.logger)).Methods("GET") r.Handle("/api/organization", isAuthenticated(getOrgIdFromRequestBody(isOrgOwner(s.psqlClient, handleUpdateOrganization(s.logger, s.psqlClient), s.logger), s.logger), s.logger)).Methods("PATCH").Headers("Content-Type", "application/json") r.Handle("/api/organization", isAuthenticated(getOrgIdFromRequestBody(isOrgOwner(s.psqlClient, handleDeleteOrganization(s.logger, s.psqlClient), s.logger), s.logger), s.logger)).Methods("DELETE").Headers("Content-Type", "application/json") + r.Handle("/api/organization/{orgId}/members", isAuthenticated(handleGetOrganizationMembers(s.logger, s.psqlClient), s.logger)).Methods("GET") // Membership r.Handle("/api/membership", isAuthenticated(getOrgIdFromRequestBody(validateMembershipChange(s.psqlClient, isOrgAdmin(s.psqlClient, handleCreateMembership(s.logger, s.psqlClient), s.logger), s.logger), s.logger), s.logger)).Methods("POST").Headers("Content-Type", "application/json") @@ -821,6 +823,33 @@ func handleGetStepExecutionLogs(l logger.ServerLogger, psqlClient *sql.DB) http. }) } +func handleGetOrganizationMembers(logger logger.ServerLogger, client *sql.DB) http.Handler { + type ResponseBody struct { // Response body when org_id is provided + OrgId int `json:"org_id"` + Members []*database.GetAllUsersByOrdIdResponse `json:"members"` + } + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + orgId, err := strconv.Atoi(vars["orgId"]) + if err != nil { + logger.Error(fmt.Sprintf("unable to parse orgId: %s", err)) + encode(w, r, http.StatusBadRequest, newHandlerError(ErrInvalidOrganizationId, http.StatusBadRequest)) + return + } + users, err := database.NewUser(client).GetAllUsersByOrgId(orgId) + if err != nil { + logger.Error(fmt.Sprintf("error encountered while handling API request: %s", err)) + encode(w, r, http.StatusInternalServerError, newHandlerError(ErrUserRetrieve, http.StatusInternalServerError)) + return + } + response := ResponseBody{ + OrgId: orgId, + Members: users, + } + encode(w, r, http.StatusOK, response) + }) + +} func handleGetOrganizationsForUser(logger logger.ServerLogger, client *sql.DB) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Context().Value(jwtmiddleware.ContextKey{}).(*validator.ValidatedClaims) diff --git a/flowforge_api_bruno/user/all users by org id.bru b/flowforge_api_bruno/user/all users by org id.bru new file mode 100644 index 00000000..73b4b790 --- /dev/null +++ b/flowforge_api_bruno/user/all users by org id.bru @@ -0,0 +1,13 @@ +meta { + name: all users by org id + type: http + seq: 2 +} + +get { + url: {{HOST}}/organization/{{org_id}}/members + body: none + auth: inherit +} + +