Skip to content

Commit

Permalink
user management API (#50)
Browse files Browse the repository at this point in the history
* user management API

* user management API

* renamed method to be more clear their functionality
  • Loading branch information
danielbonilha authored Nov 4, 2022
1 parent f1f7a6f commit c8331f9
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 34 deletions.
4 changes: 4 additions & 0 deletions gateway/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ func (api *Api) buildRoutes(route *gin.RouterGroup) {
route.GET("/login", api.SecurityHandler.Login)
route.GET("/callback", api.SecurityHandler.Callback)

route.GET("/users", api.Authenticate, api.UserHandler.FindAll)
route.GET("/users/:id", api.Authenticate, api.UserHandler.FindOne)
route.PUT("/users/:id", api.Authenticate, api.UserHandler.Put)

route.POST("/connections", api.Authenticate, api.ConnectionHandler.Post)
route.GET("/connections", api.Authenticate, api.ConnectionHandler.FindAll)
route.GET("/connections/:name", api.Authenticate, api.ConnectionHandler.FindOne)
Expand Down
86 changes: 86 additions & 0 deletions gateway/user/api.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package user

import (
"github.com/gin-gonic/gin"
"net/http"
)

type (
Handler struct {
Service service
Expand All @@ -8,5 +13,86 @@ type (
service interface {
Signup(org *Org, user *User) (txId int64, err error)
FindBySub(sub string) (*Context, error)
FindAll(context *Context) ([]User, error)
FindOne(context *Context, id string) (*User, error)
Persist(user any) error
}
)

func (a *Handler) FindAll(c *gin.Context) {
ctx, _ := c.Get("context")
context := ctx.(*Context)

users, err := a.Service.FindAll(context)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return
}

c.PureJSON(http.StatusOK, users)
}

func (a *Handler) FindOne(c *gin.Context) {
ctx, _ := c.Get("context")
context := ctx.(*Context)

id := c.Param("id")
user, err := a.Service.FindOne(context, id)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return
}

if user == nil {
c.JSON(http.StatusNotFound, gin.H{"message": "not found"})
return
}

c.PureJSON(http.StatusOK, user)
}

func (a *Handler) Put(c *gin.Context) {
ctx, _ := c.Get("context")
context := ctx.(*Context)

id := c.Param("id")
existingUser, err := a.Service.FindOne(context, id)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
return
}

if existingUser == nil {
c.JSON(http.StatusNotFound, gin.H{"message": "not found"})
return
}

var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
return
}

if !isInStatus(user.Status) {
c.JSON(http.StatusBadRequest, gin.H{"message": "invalid status"})
return
}

// for admins to not auto-exclude themselves from admin by mistake
if existingUser.Id == context.User.Id &&
existingUser.isAdmin() &&
!isInList(GroupAdmin, user.Groups) {
user.Groups = append(user.Groups, GroupAdmin)
}

existingUser.Status = user.Status
existingUser.Groups = user.Groups

err = a.Service.Persist(existingUser)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
}

c.JSON(http.StatusOK, existingUser)
}
67 changes: 58 additions & 9 deletions gateway/user/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ type (

storage interface {
Signup(org *Org, user *User) (txId int64, err error)
FindById(email string) (*Context, error)
GetOrgByName(name string) (*Org, error)
FindById(identifier string) (*Context, error)
Persist(user any) (int64, error)
FindAll(context *Context) ([]User, error)

GetOrgByName(name string) (*Org, error)
}

Context struct {
Expand All @@ -28,7 +30,7 @@ type (
Id string `json:"id" edn:"xt/id"`
Org string `json:"-" edn:"user/org"`
Name string `json:"name" edn:"user/name"`
Email string `json:"email" edn:"user/email" binding:"required"`
Email string `json:"email" edn:"user/email"`
Status StatusType `json:"status" edn:"user/status"`
Groups []string `json:"groups" edn:"user/groups"`
}
Expand All @@ -39,20 +41,37 @@ type (
const (
StatusActive StatusType = "active"
StatusReviewing StatusType = "reviewing"
StatusInactive StatusType = "inactive"

GroupAdmin string = "admin"
)

func (s *Service) Signup(org *Org, user *User) (txId int64, err error) {
return s.Storage.Signup(org, user)
var statuses = []StatusType{
StatusActive,
StatusReviewing,
StatusInactive,
}

func (s *Service) FindBySub(sub string) (*Context, error) {
return s.Storage.FindById(sub)
func (s *Service) FindAll(context *Context) ([]User, error) {
return s.Storage.FindAll(context)
}

func (s *Service) GetOrgByName(name string) (*Org, error) {
return s.Storage.GetOrgByName(name)
func (s *Service) FindOne(context *Context, id string) (*User, error) {
ctx, err := s.Storage.FindById(id)
if err != nil {
return nil, err
}

if ctx.User == nil || ctx.User.Org != context.Org.Id {
return nil, nil
}

return ctx.User, nil

}

func (s *Service) FindBySub(sub string) (*Context, error) {
return s.Storage.FindById(sub)
}

func (s *Service) Persist(user any) error {
Expand All @@ -63,6 +82,14 @@ func (s *Service) Persist(user any) error {
return nil
}

func (s *Service) Signup(org *Org, user *User) (txId int64, err error) {
return s.Storage.Signup(org, user)
}

func (s *Service) GetOrgByName(name string) (*Org, error) {
return s.Storage.GetOrgByName(name)
}

func ExtractDomain(email string) string {
emailsParts := strings.Split(email, "@")
domainParts := strings.Split(emailsParts[1], ".")
Expand Down Expand Up @@ -96,3 +123,25 @@ func isPublicDomain(domain string) bool {
}
return false
}

func (user *User) isAdmin() bool {
return isInList(GroupAdmin, user.Groups)
}

func isInList(item string, items []string) bool {
for _, i := range items {
if i == item {
return true
}
}
return false
}

func isInStatus(status StatusType) bool {
for _, s := range statuses {
if s == status {
return true
}
}
return false
}
46 changes: 21 additions & 25 deletions gateway/user/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,24 @@ func (s *Storage) FindById(identifier string) (*Context, error) {
return c, nil
}

func (s *Storage) Signup(org *Org, user *User) (txId int64, err error) {
orgPayload := st.EntityToMap(org)
userPayload := st.EntityToMap(user)
func (s *Storage) FindAll(context *Context) ([]User, error) {
var payload = `{:query {
:find [(pull ?user [*])]
:in [org]
:where [[?user :user/org org]]}
:in-args ["` + context.Org.Id + `"]}`

entities := []map[string]any{orgPayload, userPayload}
txId, err = s.PersistEntities(entities)
b, err := s.Query([]byte(payload))
if err != nil {
return 0, err
return nil, err
}

return txId, nil
var users []User
if err := edn.Unmarshal(b, &users); err != nil {
return nil, err
}

return users, nil
}

func (s *Storage) Persist(user any) (int64, error) {
Expand All @@ -63,28 +70,17 @@ func (s *Storage) Persist(user any) (int64, error) {
return txId, nil
}

func (s *Storage) GetByEmail(email string) (*User, error) {
var payload = `{:query {
:find [(pull ?user [*])]
:in [email]
:where [[?user :user/email email]]}
:in-args ["` + email + `"]}`
func (s *Storage) Signup(org *Org, user *User) (txId int64, err error) {
orgPayload := st.EntityToMap(org)
userPayload := st.EntityToMap(user)

b, err := s.Query([]byte(payload))
entities := []map[string]any{orgPayload, userPayload}
txId, err = s.PersistEntities(entities)
if err != nil {
return nil, err
}

var u []User
if err := edn.Unmarshal(b, &u); err != nil {
return nil, err
}

if len(u) == 0 {
return nil, nil
return 0, err
}

return &u[0], nil
return txId, nil
}

func (s *Storage) GetOrgByName(name string) (*Org, error) {
Expand Down

0 comments on commit c8331f9

Please sign in to comment.