3
0

add(system): login/logout api, rename PK fields

This commit is contained in:
Tit Petric 2018-11-25 22:57:48 +01:00
parent 59a3fc85d3
commit 256a45bdb6
10 changed files with 213 additions and 8 deletions

View File

@ -11,14 +11,14 @@
"method": "GET",
"title": "Check JWT token",
"path": "/check",
"parameters": []
"parameters": {}
},
{
"name": "logout",
"method": "DELETE",
"title": "Delete JWT token (Sign Out)",
"path": "/check",
"parameters": []
"parameters": {}
}
]
},
@ -381,6 +381,35 @@
}
],
"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",
"method": "GET",

View File

@ -13,14 +13,14 @@
"Method": "GET",
"Title": "Check JWT token",
"Path": "/check",
"Parameters": null
"Parameters": {}
},
{
"Name": "logout",
"Method": "DELETE",
"Title": "Delete JWT token (Sign Out)",
"Path": "/check",
"Parameters": null
"Parameters": {}
}
]
}

View File

@ -17,6 +17,35 @@
],
"Path": "/users",
"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",
"Method": "GET",

View File

@ -277,6 +277,34 @@ An organisation may have many teams. Teams may have many channels available. Acc
# 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)
#### Method

View File

@ -27,6 +27,8 @@ import (
// Internal API 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)
Create(context.Context, *request.UserCreate) (interface{}, error)
Edit(context.Context, *request.UserEdit) (interface{}, error)
@ -38,6 +40,8 @@ type UserAPI interface {
// HTTP API interface
type User struct {
Login func(http.ResponseWriter, *http.Request)
Logout func(http.ResponseWriter, *http.Request)
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
Edit func(http.ResponseWriter, *http.Request)
@ -49,6 +53,20 @@ type User struct {
func NewUser(uh UserAPI) *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) {
defer r.Body.Close()
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.Use(middlewares...)
r.Route("/users", func(r chi.Router) {
r.Post("/login", uh.Login)
r.Get("/logout", uh.Logout)
r.Get("/", uh.List)
r.Post("/", uh.Create)
r.Put("/{userID}", uh.Edit)

View File

@ -30,6 +30,97 @@ var _ = chi.URLParam
var _ = types.JSONText{}
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
type UserList struct {
Query string

View File

@ -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})
}
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) {
user := &types.User{
Email: r.Email,

View File

@ -7,7 +7,7 @@ import (
type (
// Organisations - Organisations represent a top-level grouping entity. There may be many organisations defined in a single deployment.
Organisation struct {
ID uint64 `json:"id" db:"id"`
ID uint64 `json:"organisationID,string" db:"id"`
FQN string `json:"fqn" db:"fqn"`
Name string `json:"name" db:"name"`
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`

View File

@ -7,7 +7,7 @@ import (
type (
// Teams - An organisation may have many teams. Teams may have many channels available. Access to channels may be shared between teams.
Team struct {
ID uint64 `json:"id,string" db:"id"`
ID uint64 `json:"teamID,string" db:"id"`
Name string `json:"name" db:"name"`
Handle string `json:"handle" db:"handle"`
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`

View File

@ -9,7 +9,7 @@ import (
type (
User struct {
ID uint64 `json:"id,string" db:"id"`
ID uint64 `json:"userID,string" db:"id"`
Username string `json:"username" db:"username"`
Email string `json:"email" db:"email"`
Name string `json:"name" db:"name"`
@ -19,7 +19,7 @@ type (
Meta types.JSONText `json:"-" db:"meta"`
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:"-"`
Password []byte `json:"-" db:"password"`