Changes to system REST & service layer

This commit is contained in:
Denis Arh
2019-02-11 20:57:14 +01:00
parent 5b2cacd871
commit 3911316321
16 changed files with 110 additions and 290 deletions
+6 -73
View File
@@ -86,7 +86,7 @@
}
},
{
"name": "edit",
"name": "update",
"method": "PUT",
"title": "Update organisation details",
"path": "/{id}",
@@ -208,7 +208,7 @@
}
},
{
"name": "edit",
"name": "update",
"method": "PUT",
"title": "Update team details",
"path": "/{teamID}",
@@ -391,13 +391,6 @@
"Client ID",
"Session ID"
],
"struct": [
{
"imports": [
"sqlxTypes github.com/jmoiron/sqlx/types"
]
}
],
"apis": [
{
"name": "list",
@@ -440,28 +433,16 @@
"required": true,
"title": "Email"
},
{
"name": "username",
"type": "string",
"required": true,
"title": "Username"
},
{
"name": "password",
"type": "string",
"required": true,
"title": "Password"
},
{
"name": "name",
"type": "string",
"required": true,
"required": false,
"title": "Name"
},
{
"name": "handle",
"type": "string",
"required": true,
"required": false,
"title": "Handle"
},
{
@@ -469,30 +450,12 @@
"type": "string",
"required": false,
"title": "Kind (normal, bot)"
},
{
"name": "meta",
"type": "sqlxTypes.JSONText",
"required": false,
"title": "Meta data"
},
{
"name": "satosaID",
"type": "string",
"required": false,
"title": "Satosa ID"
},
{
"name": "organisationID",
"type": "uint64",
"required": false,
"title": "Organisation ID"
}
]
}
},
{
"name": "edit",
"name": "update",
"method": "PUT",
"title": "Update user details",
"path": "/{userID}",
@@ -512,18 +475,6 @@
"required": true,
"title": "Email"
},
{
"name": "username",
"type": "string",
"required": true,
"title": "Username"
},
{
"name": "password",
"type": "string",
"required": true,
"title": "Password"
},
{
"name": "name",
"type": "string",
@@ -533,7 +484,7 @@
{
"name": "handle",
"type": "string",
"required": true,
"required": false,
"title": "Handle"
},
{
@@ -541,24 +492,6 @@
"type": "string",
"required": false,
"title": "Kind (normal, bot)"
},
{
"name": "meta",
"type": "sqlxTypes.JSONText",
"required": false,
"title": "Meta data"
},
{
"name": "satosaID",
"type": "string",
"required": false,
"title": "Satosa ID"
},
{
"name": "organisationID",
"type": "uint64",
"required": false,
"title": "Organisation ID"
}
]
}
+1 -1
View File
@@ -44,7 +44,7 @@
}
},
{
"Name": "edit",
"Name": "update",
"Method": "PUT",
"Title": "Update organisation details",
"Path": "/{id}",
+1 -1
View File
@@ -50,7 +50,7 @@
}
},
{
"Name": "edit",
"Name": "update",
"Method": "PUT",
"Title": "Update team details",
"Path": "/{teamID}",
+5 -71
View File
@@ -1,13 +1,7 @@
{
"Title": "Users",
"Interface": "User",
"Struct": [
{
"imports": [
"sqlxTypes github.com/jmoiron/sqlx/types"
]
}
],
"Struct": null,
"Parameters": null,
"Protocol": "",
"Authentication": [
@@ -57,27 +51,15 @@
"title": "Email",
"type": "string"
},
{
"name": "username",
"required": true,
"title": "Username",
"type": "string"
},
{
"name": "password",
"required": true,
"title": "Password",
"type": "string"
},
{
"name": "name",
"required": true,
"required": false,
"title": "Name",
"type": "string"
},
{
"name": "handle",
"required": true,
"required": false,
"title": "Handle",
"type": "string"
},
@@ -86,30 +68,12 @@
"required": false,
"title": "Kind (normal, bot)",
"type": "string"
},
{
"name": "meta",
"required": false,
"title": "Meta data",
"type": "sqlxTypes.JSONText"
},
{
"name": "satosaID",
"required": false,
"title": "Satosa ID",
"type": "string"
},
{
"name": "organisationID",
"required": false,
"title": "Organisation ID",
"type": "uint64"
}
]
}
},
{
"Name": "edit",
"Name": "update",
"Method": "PUT",
"Title": "Update user details",
"Path": "/{userID}",
@@ -129,18 +93,6 @@
"title": "Email",
"type": "string"
},
{
"name": "username",
"required": true,
"title": "Username",
"type": "string"
},
{
"name": "password",
"required": true,
"title": "Password",
"type": "string"
},
{
"name": "name",
"required": true,
@@ -149,7 +101,7 @@
},
{
"name": "handle",
"required": true,
"required": false,
"title": "Handle",
"type": "string"
},
@@ -158,24 +110,6 @@
"required": false,
"title": "Kind (normal, bot)",
"type": "string"
},
{
"name": "meta",
"required": false,
"title": "Meta data",
"type": "sqlxTypes.JSONText"
},
{
"name": "satosaID",
"required": false,
"title": "Satosa ID",
"type": "string"
},
{
"name": "organisationID",
"required": false,
"title": "Organisation ID",
"type": "uint64"
}
]
}
+3 -13
View File
@@ -321,14 +321,9 @@ An organisation may have many teams. Teams may have many channels available. Acc
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| email | string | POST | Email | N/A | YES |
| username | string | POST | Username | N/A | YES |
| password | string | POST | Password | N/A | YES |
| name | string | POST | Name | N/A | YES |
| handle | string | POST | Handle | N/A | YES |
| name | string | POST | Name | N/A | NO |
| handle | string | POST | Handle | N/A | NO |
| kind | string | POST | Kind (normal, bot) | N/A | NO |
| meta | sqlxTypes.JSONText | POST | Meta data | N/A | NO |
| satosaID | string | POST | Satosa ID | N/A | NO |
| organisationID | uint64 | POST | Organisation ID | N/A | NO |
## Update user details
@@ -344,14 +339,9 @@ An organisation may have many teams. Teams may have many channels available. Acc
| --------- | ---- | ------ | ----------- | ------- | --------- |
| userID | uint64 | PATH | User ID | N/A | YES |
| email | string | POST | Email | N/A | YES |
| username | string | POST | Username | N/A | YES |
| password | string | POST | Password | N/A | YES |
| name | string | POST | Name | N/A | YES |
| handle | string | POST | Handle | N/A | YES |
| handle | string | POST | Handle | N/A | NO |
| kind | string | POST | Kind (normal, bot) | N/A | NO |
| meta | sqlxTypes.JSONText | POST | Meta data | N/A | NO |
| satosaID | string | POST | Satosa ID | N/A | NO |
| organisationID | uint64 | POST | Organisation ID | N/A | NO |
## Read user details and memberships
+6 -6
View File
@@ -29,7 +29,7 @@ import (
type OrganisationAPI interface {
List(context.Context, *request.OrganisationList) (interface{}, error)
Create(context.Context, *request.OrganisationCreate) (interface{}, error)
Edit(context.Context, *request.OrganisationEdit) (interface{}, error)
Update(context.Context, *request.OrganisationUpdate) (interface{}, error)
Remove(context.Context, *request.OrganisationRemove) (interface{}, error)
Read(context.Context, *request.OrganisationRead) (interface{}, error)
Archive(context.Context, *request.OrganisationArchive) (interface{}, error)
@@ -39,7 +39,7 @@ type OrganisationAPI interface {
type Organisation struct {
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
Edit func(http.ResponseWriter, *http.Request)
Update func(http.ResponseWriter, *http.Request)
Remove func(http.ResponseWriter, *http.Request)
Read func(http.ResponseWriter, *http.Request)
Archive func(http.ResponseWriter, *http.Request)
@@ -61,11 +61,11 @@ func NewOrganisation(oh OrganisationAPI) *Organisation {
return oh.Create(r.Context(), params)
})
},
Edit: func(w http.ResponseWriter, r *http.Request) {
Update: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewOrganisationEdit()
params := request.NewOrganisationUpdate()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return oh.Edit(r.Context(), params)
return oh.Update(r.Context(), params)
})
},
Remove: func(w http.ResponseWriter, r *http.Request) {
@@ -98,7 +98,7 @@ func (oh *Organisation) MountRoutes(r chi.Router, middlewares ...func(http.Handl
r.Route("/organisations", func(r chi.Router) {
r.Get("/", oh.List)
r.Post("/", oh.Create)
r.Put("/{id}", oh.Edit)
r.Put("/{id}", oh.Update)
r.Delete("/{id}", oh.Remove)
r.Get("/{id}", oh.Read)
r.Post("/{id}/archive", oh.Archive)
+6 -6
View File
@@ -29,7 +29,7 @@ import (
type TeamAPI interface {
List(context.Context, *request.TeamList) (interface{}, error)
Create(context.Context, *request.TeamCreate) (interface{}, error)
Edit(context.Context, *request.TeamEdit) (interface{}, error)
Update(context.Context, *request.TeamUpdate) (interface{}, error)
Read(context.Context, *request.TeamRead) (interface{}, error)
Remove(context.Context, *request.TeamRemove) (interface{}, error)
Archive(context.Context, *request.TeamArchive) (interface{}, error)
@@ -43,7 +43,7 @@ type TeamAPI interface {
type Team struct {
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
Edit func(http.ResponseWriter, *http.Request)
Update func(http.ResponseWriter, *http.Request)
Read func(http.ResponseWriter, *http.Request)
Remove func(http.ResponseWriter, *http.Request)
Archive func(http.ResponseWriter, *http.Request)
@@ -69,11 +69,11 @@ func NewTeam(th TeamAPI) *Team {
return th.Create(r.Context(), params)
})
},
Edit: func(w http.ResponseWriter, r *http.Request) {
Update: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewTeamEdit()
params := request.NewTeamUpdate()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return th.Edit(r.Context(), params)
return th.Update(r.Context(), params)
})
},
Read: func(w http.ResponseWriter, r *http.Request) {
@@ -134,7 +134,7 @@ func (th *Team) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http
r.Route("/teams", func(r chi.Router) {
r.Get("/", th.List)
r.Post("/", th.Create)
r.Put("/{teamID}", th.Edit)
r.Put("/{teamID}", th.Update)
r.Get("/{teamID}", th.Read)
r.Delete("/{teamID}", th.Remove)
r.Post("/{teamID}/archive", th.Archive)
+6 -6
View File
@@ -29,7 +29,7 @@ import (
type UserAPI interface {
List(context.Context, *request.UserList) (interface{}, error)
Create(context.Context, *request.UserCreate) (interface{}, error)
Edit(context.Context, *request.UserEdit) (interface{}, error)
Update(context.Context, *request.UserUpdate) (interface{}, error)
Read(context.Context, *request.UserRead) (interface{}, error)
Remove(context.Context, *request.UserRemove) (interface{}, error)
Suspend(context.Context, *request.UserSuspend) (interface{}, error)
@@ -40,7 +40,7 @@ type UserAPI interface {
type User struct {
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
Edit func(http.ResponseWriter, *http.Request)
Update func(http.ResponseWriter, *http.Request)
Read func(http.ResponseWriter, *http.Request)
Remove func(http.ResponseWriter, *http.Request)
Suspend func(http.ResponseWriter, *http.Request)
@@ -63,11 +63,11 @@ func NewUser(uh UserAPI) *User {
return uh.Create(r.Context(), params)
})
},
Edit: func(w http.ResponseWriter, r *http.Request) {
Update: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewUserEdit()
params := request.NewUserUpdate()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return uh.Edit(r.Context(), params)
return uh.Update(r.Context(), params)
})
},
Read: func(w http.ResponseWriter, r *http.Request) {
@@ -107,7 +107,7 @@ func (uh *User) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http
r.Route("/users", func(r chi.Router) {
r.Get("/", uh.List)
r.Post("/", uh.Create)
r.Put("/{userID}", uh.Edit)
r.Put("/{userID}", uh.Update)
r.Get("/{userID}", uh.Read)
r.Delete("/{userID}", uh.Remove)
r.Post("/{userID}/suspend", uh.Suspend)
+1 -1
View File
@@ -42,7 +42,7 @@ func (ctrl *Organisation) Create(ctx context.Context, r *request.OrganisationCre
return ctrl.svc.org.With(ctx).Create(org)
}
func (ctrl *Organisation) Edit(ctx context.Context, r *request.OrganisationEdit) (interface{}, error) {
func (ctrl *Organisation) Update(ctx context.Context, r *request.OrganisationUpdate) (interface{}, error) {
org := &types.Organisation{
ID: r.ID,
Name: r.Name,
+6 -6
View File
@@ -121,17 +121,17 @@ func (o *OrganisationCreate) Fill(r *http.Request) (err error) {
var _ RequestFiller = NewOrganisationCreate()
// Organisation edit request parameters
type OrganisationEdit struct {
// Organisation update request parameters
type OrganisationUpdate struct {
ID uint64 `json:",string"`
Name string
}
func NewOrganisationEdit() *OrganisationEdit {
return &OrganisationEdit{}
func NewOrganisationUpdate() *OrganisationUpdate {
return &OrganisationUpdate{}
}
func (o *OrganisationEdit) Fill(r *http.Request) (err error) {
func (o *OrganisationUpdate) Fill(r *http.Request) (err error) {
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(r.Body).Decode(o)
@@ -167,7 +167,7 @@ func (o *OrganisationEdit) Fill(r *http.Request) (err error) {
return err
}
var _ RequestFiller = NewOrganisationEdit()
var _ RequestFiller = NewOrganisationUpdate()
// Organisation remove request parameters
type OrganisationRemove struct {
+6 -6
View File
@@ -123,18 +123,18 @@ func (t *TeamCreate) Fill(r *http.Request) (err error) {
var _ RequestFiller = NewTeamCreate()
// Team edit request parameters
type TeamEdit struct {
// Team update request parameters
type TeamUpdate struct {
TeamID uint64 `json:",string"`
Name string
Members []uint64 `json:",string"`
}
func NewTeamEdit() *TeamEdit {
return &TeamEdit{}
func NewTeamUpdate() *TeamUpdate {
return &TeamUpdate{}
}
func (t *TeamEdit) Fill(r *http.Request) (err error) {
func (t *TeamUpdate) Fill(r *http.Request) (err error) {
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(r.Body).Decode(t)
@@ -171,7 +171,7 @@ func (t *TeamEdit) Fill(r *http.Request) (err error) {
return err
}
var _ RequestFiller = NewTeamEdit()
var _ RequestFiller = NewTeamUpdate()
// Team read request parameters
type TeamRead struct {
+15 -71
View File
@@ -24,8 +24,6 @@ import (
"github.com/go-chi/chi"
"github.com/pkg/errors"
sqlxTypes "github.com/jmoiron/sqlx/types"
)
var _ = chi.URLParam
@@ -89,15 +87,10 @@ var _ RequestFiller = NewUserList()
// User create request parameters
type UserCreate struct {
Email string
Username string
Password string
Name string
Handle string
Kind string
Meta sqlxTypes.JSONText
SatosaID string
OrganisationID uint64 `json:",string"`
Email string
Name string
Handle string
Kind string
}
func NewUserCreate() *UserCreate {
@@ -135,14 +128,6 @@ func (u *UserCreate) Fill(r *http.Request) (err error) {
u.Email = val
}
if val, ok := post["username"]; ok {
u.Username = val
}
if val, ok := post["password"]; ok {
u.Password = val
}
if val, ok := post["name"]; ok {
u.Name = val
@@ -155,45 +140,26 @@ func (u *UserCreate) Fill(r *http.Request) (err error) {
u.Kind = val
}
if val, ok := post["meta"]; ok {
if u.Meta, err = parseJSONTextWithErr(val); err != nil {
return err
}
}
if val, ok := post["satosaID"]; ok {
u.SatosaID = val
}
if val, ok := post["organisationID"]; ok {
u.OrganisationID = parseUInt64(val)
}
return err
}
var _ RequestFiller = NewUserCreate()
// User edit request parameters
type UserEdit struct {
UserID uint64 `json:",string"`
Email string
Username string
Password string
Name string
Handle string
Kind string
Meta sqlxTypes.JSONText
SatosaID string
OrganisationID uint64 `json:",string"`
// User update request parameters
type UserUpdate struct {
UserID uint64 `json:",string"`
Email string
Name string
Handle string
Kind string
}
func NewUserEdit() *UserEdit {
return &UserEdit{}
func NewUserUpdate() *UserUpdate {
return &UserUpdate{}
}
func (u *UserEdit) Fill(r *http.Request) (err error) {
func (u *UserUpdate) Fill(r *http.Request) (err error) {
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(r.Body).Decode(u)
@@ -225,14 +191,6 @@ func (u *UserEdit) Fill(r *http.Request) (err error) {
u.Email = val
}
if val, ok := post["username"]; ok {
u.Username = val
}
if val, ok := post["password"]; ok {
u.Password = val
}
if val, ok := post["name"]; ok {
u.Name = val
@@ -245,25 +203,11 @@ func (u *UserEdit) Fill(r *http.Request) (err error) {
u.Kind = val
}
if val, ok := post["meta"]; ok {
if u.Meta, err = parseJSONTextWithErr(val); err != nil {
return err
}
}
if val, ok := post["satosaID"]; ok {
u.SatosaID = val
}
if val, ok := post["organisationID"]; ok {
u.OrganisationID = parseUInt64(val)
}
return err
}
var _ RequestFiller = NewUserEdit()
var _ RequestFiller = NewUserUpdate()
// User read request parameters
type UserRead struct {
+1 -1
View File
@@ -42,7 +42,7 @@ func (ctrl *Team) Create(ctx context.Context, r *request.TeamCreate) (interface{
return ctrl.svc.team.With(ctx).Create(org)
}
func (ctrl *Team) Edit(ctx context.Context, r *request.TeamEdit) (interface{}, error) {
func (ctrl *Team) Update(ctx context.Context, r *request.TeamUpdate) (interface{}, error) {
org := &types.Team{
ID: r.TeamID,
Name: r.Name,
+12 -24
View File
@@ -35,36 +35,24 @@ func (ctrl *User) List(ctx context.Context, r *request.UserList) (interface{}, e
func (ctrl *User) Create(ctx context.Context, r *request.UserCreate) (interface{}, error) {
user := &types.User{
Email: r.Email,
Username: r.Username,
Name: r.Name,
Handle: r.Handle,
Kind: r.Kind,
Meta: r.Meta,
SatosaID: r.SatosaID,
OrganisationID: r.OrganisationID,
}
if err := user.GeneratePassword(r.Password); err != nil {
return nil, err
Email: r.Email,
Name: r.Name,
Handle: r.Handle,
Kind: r.Kind,
}
return ctrl.user.With(ctx).Create(user)
}
func (ctrl *User) Edit(ctx context.Context, r *request.UserEdit) (interface{}, error) {
func (ctrl *User) Update(ctx context.Context, r *request.UserUpdate) (interface{}, error) {
user := &types.User{
ID: r.UserID,
Email: r.Email,
Username: r.Username,
Name: r.Name,
Handle: r.Handle,
Kind: r.Kind,
Meta: r.Meta,
SatosaID: r.SatosaID,
OrganisationID: r.OrganisationID,
}
if err := user.GeneratePassword(r.Password); err != nil {
return nil, err
ID: r.UserID,
Email: r.Email,
Name: r.Name,
Handle: r.Handle,
Kind: r.Kind,
}
return ctrl.user.With(ctx).Update(user)
}
+16 -2
View File
@@ -66,11 +66,25 @@ func (svc *team) Create(mod *types.Team) (*types.Team, error) {
return svc.team.Create(mod)
}
func (svc *team) Update(mod *types.Team) (*types.Team, error) {
func (svc *team) Update(mod *types.Team) (t *types.Team, err error) {
// @todo: permission check if current user can add/edit team
// @todo: make sure archived & deleted entries can not be edited
return svc.team.Update(mod)
return t, svc.db.Transaction(func() (err error) {
if t, err = svc.team.FindByID(mod.ID); err != nil {
return
}
// Assign changed values
t.Name = mod.Name
t.Handle = mod.Handle
if t, err = svc.team.Update(t); err != nil {
return err
}
return nil
})
}
func (svc *team) Delete(id uint64) error {
+19 -2
View File
@@ -150,8 +150,25 @@ func (svc *user) Create(input *types.User) (out *types.User, err error) {
})
}
func (svc *user) Update(mod *types.User) (*types.User, error) {
return svc.user.Update(mod)
func (svc *user) Update(mod *types.User) (u *types.User, err error) {
return u, svc.db.Transaction(func() (err error) {
if u, err = svc.user.FindByID(mod.ID); err != nil {
return
}
// Assign changed values
u.Email = mod.Email
u.Username = mod.Username
u.Name = mod.Name
u.Handle = mod.Handle
u.Kind = mod.Kind
if u, err = svc.user.Update(u); err != nil {
return err
}
return nil
})
}
func (svc *user) canLogin(u *types.User) bool {