add(system): login/logout api, rename PK fields
This commit is contained in:
@@ -11,14 +11,14 @@
|
|||||||
"method": "GET",
|
"method": "GET",
|
||||||
"title": "Check JWT token",
|
"title": "Check JWT token",
|
||||||
"path": "/check",
|
"path": "/check",
|
||||||
"parameters": []
|
"parameters": {}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "logout",
|
"name": "logout",
|
||||||
"method": "DELETE",
|
"method": "DELETE",
|
||||||
"title": "Delete JWT token (Sign Out)",
|
"title": "Delete JWT token (Sign Out)",
|
||||||
"path": "/check",
|
"path": "/check",
|
||||||
"parameters": []
|
"parameters": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -381,6 +381,35 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"apis": [
|
"apis": [
|
||||||
|
{
|
||||||
|
"name": "login",
|
||||||
|
"method": "POST",
|
||||||
|
"title": "Login user",
|
||||||
|
"path": "/login",
|
||||||
|
"parameters": {
|
||||||
|
"post": [
|
||||||
|
{
|
||||||
|
"name": "username",
|
||||||
|
"type": "string",
|
||||||
|
"required": true,
|
||||||
|
"title": "Username"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "password",
|
||||||
|
"type": "string",
|
||||||
|
"required": true,
|
||||||
|
"title": "Password"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logout",
|
||||||
|
"method": "GET",
|
||||||
|
"title": "Delete JWT token (Sign Out)",
|
||||||
|
"path": "/logout",
|
||||||
|
"parameters": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "list",
|
"name": "list",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
|
|||||||
@@ -13,14 +13,14 @@
|
|||||||
"Method": "GET",
|
"Method": "GET",
|
||||||
"Title": "Check JWT token",
|
"Title": "Check JWT token",
|
||||||
"Path": "/check",
|
"Path": "/check",
|
||||||
"Parameters": null
|
"Parameters": {}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "logout",
|
"Name": "logout",
|
||||||
"Method": "DELETE",
|
"Method": "DELETE",
|
||||||
"Title": "Delete JWT token (Sign Out)",
|
"Title": "Delete JWT token (Sign Out)",
|
||||||
"Path": "/check",
|
"Path": "/check",
|
||||||
"Parameters": null
|
"Parameters": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,35 @@
|
|||||||
],
|
],
|
||||||
"Path": "/users",
|
"Path": "/users",
|
||||||
"APIs": [
|
"APIs": [
|
||||||
|
{
|
||||||
|
"Name": "login",
|
||||||
|
"Method": "POST",
|
||||||
|
"Title": "Login user",
|
||||||
|
"Path": "/login",
|
||||||
|
"Parameters": {
|
||||||
|
"post": [
|
||||||
|
{
|
||||||
|
"name": "username",
|
||||||
|
"required": true,
|
||||||
|
"title": "Username",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "password",
|
||||||
|
"required": true,
|
||||||
|
"title": "Password",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "logout",
|
||||||
|
"Method": "GET",
|
||||||
|
"Title": "Delete JWT token (Sign Out)",
|
||||||
|
"Path": "/logout",
|
||||||
|
"Parameters": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Name": "list",
|
"Name": "list",
|
||||||
"Method": "GET",
|
"Method": "GET",
|
||||||
|
|||||||
@@ -277,6 +277,34 @@ An organisation may have many teams. Teams may have many channels available. Acc
|
|||||||
|
|
||||||
# Users
|
# Users
|
||||||
|
|
||||||
|
## Login user
|
||||||
|
|
||||||
|
#### Method
|
||||||
|
|
||||||
|
| URI | Protocol | Method | Authentication |
|
||||||
|
| --- | -------- | ------ | -------------- |
|
||||||
|
| `/users/login` | HTTP/S | POST | Client ID, Session ID |
|
||||||
|
|
||||||
|
#### Request parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Method | Description | Default | Required? |
|
||||||
|
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||||
|
| username | string | POST | Username | N/A | YES |
|
||||||
|
| password | string | POST | Password | N/A | YES |
|
||||||
|
|
||||||
|
## Delete JWT token (Sign Out)
|
||||||
|
|
||||||
|
#### Method
|
||||||
|
|
||||||
|
| URI | Protocol | Method | Authentication |
|
||||||
|
| --- | -------- | ------ | -------------- |
|
||||||
|
| `/users/logout` | HTTP/S | GET | Client ID, Session ID |
|
||||||
|
|
||||||
|
#### Request parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Method | Description | Default | Required? |
|
||||||
|
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||||
|
|
||||||
## Search users (Directory)
|
## Search users (Directory)
|
||||||
|
|
||||||
#### Method
|
#### Method
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import (
|
|||||||
|
|
||||||
// Internal API interface
|
// Internal API interface
|
||||||
type UserAPI interface {
|
type UserAPI interface {
|
||||||
|
Login(context.Context, *request.UserLogin) (interface{}, error)
|
||||||
|
Logout(context.Context, *request.UserLogout) (interface{}, error)
|
||||||
List(context.Context, *request.UserList) (interface{}, error)
|
List(context.Context, *request.UserList) (interface{}, error)
|
||||||
Create(context.Context, *request.UserCreate) (interface{}, error)
|
Create(context.Context, *request.UserCreate) (interface{}, error)
|
||||||
Edit(context.Context, *request.UserEdit) (interface{}, error)
|
Edit(context.Context, *request.UserEdit) (interface{}, error)
|
||||||
@@ -38,6 +40,8 @@ type UserAPI interface {
|
|||||||
|
|
||||||
// HTTP API interface
|
// HTTP API interface
|
||||||
type User struct {
|
type User struct {
|
||||||
|
Login func(http.ResponseWriter, *http.Request)
|
||||||
|
Logout func(http.ResponseWriter, *http.Request)
|
||||||
List func(http.ResponseWriter, *http.Request)
|
List func(http.ResponseWriter, *http.Request)
|
||||||
Create func(http.ResponseWriter, *http.Request)
|
Create func(http.ResponseWriter, *http.Request)
|
||||||
Edit func(http.ResponseWriter, *http.Request)
|
Edit func(http.ResponseWriter, *http.Request)
|
||||||
@@ -49,6 +53,20 @@ type User struct {
|
|||||||
|
|
||||||
func NewUser(uh UserAPI) *User {
|
func NewUser(uh UserAPI) *User {
|
||||||
return &User{
|
return &User{
|
||||||
|
Login: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
params := request.NewUserLogin()
|
||||||
|
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
|
||||||
|
return uh.Login(r.Context(), params)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Logout: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
params := request.NewUserLogout()
|
||||||
|
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
|
||||||
|
return uh.Logout(r.Context(), params)
|
||||||
|
})
|
||||||
|
},
|
||||||
List: func(w http.ResponseWriter, r *http.Request) {
|
List: func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
params := request.NewUserList()
|
params := request.NewUserList()
|
||||||
@@ -105,6 +123,8 @@ func (uh *User) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http
|
|||||||
r.Group(func(r chi.Router) {
|
r.Group(func(r chi.Router) {
|
||||||
r.Use(middlewares...)
|
r.Use(middlewares...)
|
||||||
r.Route("/users", func(r chi.Router) {
|
r.Route("/users", func(r chi.Router) {
|
||||||
|
r.Post("/login", uh.Login)
|
||||||
|
r.Get("/logout", uh.Logout)
|
||||||
r.Get("/", uh.List)
|
r.Get("/", uh.List)
|
||||||
r.Post("/", uh.Create)
|
r.Post("/", uh.Create)
|
||||||
r.Put("/{userID}", uh.Edit)
|
r.Put("/{userID}", uh.Edit)
|
||||||
|
|||||||
@@ -30,6 +30,97 @@ var _ = chi.URLParam
|
|||||||
var _ = types.JSONText{}
|
var _ = types.JSONText{}
|
||||||
var _ = multipart.FileHeader{}
|
var _ = multipart.FileHeader{}
|
||||||
|
|
||||||
|
// User login request parameters
|
||||||
|
type UserLogin struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserLogin() *UserLogin {
|
||||||
|
return &UserLogin{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserLogin) Fill(r *http.Request) (err error) {
|
||||||
|
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
|
||||||
|
err = json.NewDecoder(r.Body).Decode(u)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case err == io.EOF:
|
||||||
|
err = nil
|
||||||
|
case err != nil:
|
||||||
|
return errors.Wrap(err, "error parsing http request body")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = r.ParseForm(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
get := map[string]string{}
|
||||||
|
post := map[string]string{}
|
||||||
|
urlQuery := r.URL.Query()
|
||||||
|
for name, param := range urlQuery {
|
||||||
|
get[name] = string(param[0])
|
||||||
|
}
|
||||||
|
postVars := r.Form
|
||||||
|
for name, param := range postVars {
|
||||||
|
post[name] = string(param[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := post["username"]; ok {
|
||||||
|
|
||||||
|
u.Username = val
|
||||||
|
}
|
||||||
|
if val, ok := post["password"]; ok {
|
||||||
|
|
||||||
|
u.Password = val
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ RequestFiller = NewUserLogin()
|
||||||
|
|
||||||
|
// User logout request parameters
|
||||||
|
type UserLogout struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserLogout() *UserLogout {
|
||||||
|
return &UserLogout{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserLogout) Fill(r *http.Request) (err error) {
|
||||||
|
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
|
||||||
|
err = json.NewDecoder(r.Body).Decode(u)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case err == io.EOF:
|
||||||
|
err = nil
|
||||||
|
case err != nil:
|
||||||
|
return errors.Wrap(err, "error parsing http request body")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = r.ParseForm(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
get := map[string]string{}
|
||||||
|
post := map[string]string{}
|
||||||
|
urlQuery := r.URL.Query()
|
||||||
|
for name, param := range urlQuery {
|
||||||
|
get[name] = string(param[0])
|
||||||
|
}
|
||||||
|
postVars := r.Form
|
||||||
|
for name, param := range postVars {
|
||||||
|
post[name] = string(param[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ RequestFiller = NewUserLogout()
|
||||||
|
|
||||||
// User list request parameters
|
// User list request parameters
|
||||||
type UserList struct {
|
type UserList struct {
|
||||||
Query string
|
Query string
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ func (ctrl *User) List(ctx context.Context, r *request.UserList) (interface{}, e
|
|||||||
return ctrl.user.With(ctx).Find(&types.UserFilter{Query: r.Query})
|
return ctrl.user.With(ctx).Find(&types.UserFilter{Query: r.Query})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctrl *User) Login(ctx context.Context, r *request.UserLogin) (interface{}, error) {
|
||||||
|
return nil, errors.New("Not implemented: User.Login")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctrl *User) Logout(ctx context.Context, r *request.UserLogout) (interface{}, error) {
|
||||||
|
return nil, errors.New("Not implemented: User.Logout")
|
||||||
|
}
|
||||||
|
|
||||||
func (ctrl *User) Create(ctx context.Context, r *request.UserCreate) (interface{}, error) {
|
func (ctrl *User) Create(ctx context.Context, r *request.UserCreate) (interface{}, error) {
|
||||||
user := &types.User{
|
user := &types.User{
|
||||||
Email: r.Email,
|
Email: r.Email,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
type (
|
type (
|
||||||
// Organisations - Organisations represent a top-level grouping entity. There may be many organisations defined in a single deployment.
|
// Organisations - Organisations represent a top-level grouping entity. There may be many organisations defined in a single deployment.
|
||||||
Organisation struct {
|
Organisation struct {
|
||||||
ID uint64 `json:"id" db:"id"`
|
ID uint64 `json:"organisationID,string" db:"id"`
|
||||||
FQN string `json:"fqn" db:"fqn"`
|
FQN string `json:"fqn" db:"fqn"`
|
||||||
Name string `json:"name" db:"name"`
|
Name string `json:"name" db:"name"`
|
||||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
type (
|
type (
|
||||||
// Teams - An organisation may have many teams. Teams may have many channels available. Access to channels may be shared between teams.
|
// Teams - An organisation may have many teams. Teams may have many channels available. Access to channels may be shared between teams.
|
||||||
Team struct {
|
Team struct {
|
||||||
ID uint64 `json:"id,string" db:"id"`
|
ID uint64 `json:"teamID,string" db:"id"`
|
||||||
Name string `json:"name" db:"name"`
|
Name string `json:"name" db:"name"`
|
||||||
Handle string `json:"handle" db:"handle"`
|
Handle string `json:"handle" db:"handle"`
|
||||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
User struct {
|
User struct {
|
||||||
ID uint64 `json:"id,string" db:"id"`
|
ID uint64 `json:"userID,string" db:"id"`
|
||||||
Username string `json:"username" db:"username"`
|
Username string `json:"username" db:"username"`
|
||||||
Email string `json:"email" db:"email"`
|
Email string `json:"email" db:"email"`
|
||||||
Name string `json:"name" db:"name"`
|
Name string `json:"name" db:"name"`
|
||||||
@@ -19,7 +19,7 @@ type (
|
|||||||
Meta types.JSONText `json:"-" db:"meta"`
|
Meta types.JSONText `json:"-" db:"meta"`
|
||||||
|
|
||||||
OrganisationID uint64 `json:"organisationID,string" db:"rel_organisation"`
|
OrganisationID uint64 `json:"organisationID,string" db:"rel_organisation"`
|
||||||
UserID uint64 `json:"userID,string" db:"rel_user_id"`
|
RelatedUserID uint64 `json:"relatedUserID,string" db:"rel_user_id"`
|
||||||
User *User `json:"user" db:"-"`
|
User *User `json:"user" db:"-"`
|
||||||
|
|
||||||
Password []byte `json:"-" db:"password"`
|
Password []byte `json:"-" db:"password"`
|
||||||
|
|||||||
Reference in New Issue
Block a user