Added methods to give users access to a list
This commit is contained in:
parent
d31f16aff1
commit
b1c3e92f66
10 changed files with 185 additions and 0 deletions
|
@ -25,3 +25,17 @@ Authorization: Bearer {{auth_token}}
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
# Get all users who have access to that list
|
||||||
|
GET http://localhost:8080/api/v1/lists/10/users
|
||||||
|
Authorization: Bearer {{auth_token}}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# Give a user access to that list
|
||||||
|
PUT http://localhost:8080/api/v1/lists/1/users
|
||||||
|
Authorization: Bearer {{auth_token}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{"user_id":2, "right": 5}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
|
@ -495,3 +495,38 @@ func IsErrCannotDeleteLastTeamMember(err error) bool {
|
||||||
func (err ErrCannotDeleteLastTeamMember) Error() string {
|
func (err ErrCannotDeleteLastTeamMember) Error() string {
|
||||||
return fmt.Sprintf("This user is already a member of that team. [Team ID: %d, User ID: %d]", err.TeamID, err.UserID)
|
return fmt.Sprintf("This user is already a member of that team. [Team ID: %d, User ID: %d]", err.TeamID, err.UserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
// User <-> List errors
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
// ErrInvalidUserRight represents an error where a user right is invalid
|
||||||
|
type ErrInvalidUserRight struct {
|
||||||
|
Right UserRight
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrInvalidUserRight checks if an error is ErrInvalidUserRight.
|
||||||
|
func IsErrInvalidUserRight(err error) bool {
|
||||||
|
_, ok := err.(ErrInvalidUserRight)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrInvalidUserRight) Error() string {
|
||||||
|
return fmt.Sprintf("The right is invalid [Right: %d]", err.Right)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUserAlreadyHasAccess represents an error where a user already has access to a list/namespace
|
||||||
|
type ErrUserAlreadyHasAccess struct {
|
||||||
|
UserID int64
|
||||||
|
ListID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrUserAlreadyHasAccess checks if an error is ErrUserAlreadyHasAccess.
|
||||||
|
func IsErrUserAlreadyHasAccess(err error) bool {
|
||||||
|
_, ok := err.(ErrUserAlreadyHasAccess)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrUserAlreadyHasAccess) Error() string {
|
||||||
|
return fmt.Sprintf("This user already has access to that list. [User ID: %d, List ID: %d]", err.UserID, err.ListID)
|
||||||
|
}
|
||||||
|
|
20
models/list_users.go
Normal file
20
models/list_users.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
// ListUser represents a list <-> user relation
|
||||||
|
type ListUser struct {
|
||||||
|
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"namespace"`
|
||||||
|
UserID int64 `xorm:"int(11) not null" json:"user_id" param:"user"`
|
||||||
|
ListID int64 `xorm:"int(11) not null" json:"list_id" param:"list"`
|
||||||
|
Right TeamRight `xorm:"int(11)" json:"right"`
|
||||||
|
|
||||||
|
Created int64 `xorm:"created" json:"created"`
|
||||||
|
Updated int64 `xorm:"updated" json:"updated"`
|
||||||
|
|
||||||
|
CRUDable `xorm:"-" json:"-"`
|
||||||
|
Rights `xorm:"-" json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TableName is the table name for ListUser
|
||||||
|
func (ListUser) TableName() string {
|
||||||
|
return "users_list"
|
||||||
|
}
|
40
models/list_users_create.go
Normal file
40
models/list_users_create.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
// Create creates a new list <-> user relation
|
||||||
|
func (ul *ListUser) Create(user *User) (err error) {
|
||||||
|
|
||||||
|
// Check if the right is valid
|
||||||
|
if err := ul.Right.isValid(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the list exists
|
||||||
|
l, err := GetListByID(ul.ListID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the user exists
|
||||||
|
if _, _, err = GetUserByID(ul.UserID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the user already has access or is owner of that list
|
||||||
|
// We explicitly DONT check for teams here
|
||||||
|
if l.OwnerID == ul.UserID {
|
||||||
|
return ErrUserAlreadyHasAccess{UserID: ul.UserID, ListID: ul.ListID}
|
||||||
|
}
|
||||||
|
|
||||||
|
exist, err := x.Where("list_id = ? AND user_id = ?", ul.ListID, ul.UserID).Get(&ListUser{})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if exist {
|
||||||
|
return ErrUserAlreadyHasAccess{UserID: ul.UserID, ListID: ul.ListID}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert user <-> list relation
|
||||||
|
_, err = x.Insert(ul)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
23
models/list_users_readall.go
Normal file
23
models/list_users_readall.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
// ReadAll gets all users who have access to a list
|
||||||
|
func (ul *ListUser) ReadAll(user *User) (interface{}, error) {
|
||||||
|
// Check if the user has access to the list
|
||||||
|
l, err := GetListByID(ul.ListID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !l.CanRead(user) {
|
||||||
|
return nil, ErrNeedToHaveListReadAccess{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all users
|
||||||
|
all := []*User{}
|
||||||
|
err = x.
|
||||||
|
Select("users.*").
|
||||||
|
Join("INNER", "users_list", "user_id = users.id").
|
||||||
|
Where("users_list.list_id = ?", ul.ListID).
|
||||||
|
Find(&all)
|
||||||
|
|
||||||
|
return all, err
|
||||||
|
}
|
34
models/list_users_rights.go
Normal file
34
models/list_users_rights.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
// UserRight defines the rights users can have for lists/namespaces
|
||||||
|
type UserRight int
|
||||||
|
|
||||||
|
// define unknown user right
|
||||||
|
const (
|
||||||
|
UserRightUnknown = -1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enumerate all the user rights
|
||||||
|
const (
|
||||||
|
// Can read lists in a User
|
||||||
|
UserRightRead UserRight = iota
|
||||||
|
// Can write tasks in a User like lists and todo tasks. Cannot create new lists.
|
||||||
|
UserRightWrite
|
||||||
|
// Can manage a list/namespace, can do everything
|
||||||
|
UserRightAdmin
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r UserRight) isValid() error {
|
||||||
|
if r != UserRightAdmin && r != UserRightRead && r != UserRightWrite {
|
||||||
|
return ErrInvalidUserRight{r}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanCreate checks if the user can create a new user <-> list relation
|
||||||
|
func (lu *ListUser) CanCreate(doer *User) bool {
|
||||||
|
// Get the list and check if the user has write access on it
|
||||||
|
l, _ := GetListByID(lu.ListID)
|
||||||
|
return l.CanWrite(doer)
|
||||||
|
}
|
|
@ -40,6 +40,7 @@ func init() {
|
||||||
new(TeamList),
|
new(TeamList),
|
||||||
new(TeamNamespace),
|
new(TeamNamespace),
|
||||||
new(Namespace),
|
new(Namespace),
|
||||||
|
new(ListUser),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,13 @@ func (c *WebHandler) CreateWeb(ctx echo.Context) error {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, "This user is already a member of that team.")
|
return echo.NewHTTPError(http.StatusBadRequest, "This user is already a member of that team.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if models.IsErrUserAlreadyHasAccess(err) {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, "This user already has access to this list.")
|
||||||
|
}
|
||||||
|
if models.IsErrInvalidUserRight(err) {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, "The right is invalid.")
|
||||||
|
}
|
||||||
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError)
|
return echo.NewHTTPError(http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,10 @@ func (c *WebHandler) ReadAllWeb(ctx echo.Context) error {
|
||||||
|
|
||||||
lists, err := c.CObject.ReadAll(¤tUser)
|
lists, err := c.CObject.ReadAll(¤tUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if models.IsErrNeedToHaveListReadAccess(err) {
|
||||||
|
return echo.NewHTTPError(http.StatusForbidden, "You need to have read access to this list.")
|
||||||
|
}
|
||||||
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, "An error occured.")
|
return echo.NewHTTPError(http.StatusInternalServerError, "An error occured.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,13 @@ func RegisterRoutes(e *echo.Echo) {
|
||||||
a.PUT("/lists/:list/teams", listTeamHandler.CreateWeb)
|
a.PUT("/lists/:list/teams", listTeamHandler.CreateWeb)
|
||||||
a.DELETE("/lists/:list/teams/:team", listTeamHandler.DeleteWeb)
|
a.DELETE("/lists/:list/teams/:team", listTeamHandler.DeleteWeb)
|
||||||
|
|
||||||
|
listUserHandler := &crud.WebHandler{
|
||||||
|
CObject: &models.ListUser{},
|
||||||
|
}
|
||||||
|
a.GET("/lists/:list/users", listUserHandler.ReadAllWeb)
|
||||||
|
a.PUT("/lists/:list/users", listUserHandler.CreateWeb)
|
||||||
|
a.DELETE("/lists/:list/users/:user", listUserHandler.DeleteWeb)
|
||||||
|
|
||||||
namespaceHandler := &crud.WebHandler{
|
namespaceHandler := &crud.WebHandler{
|
||||||
CObject: &models.Namespace{},
|
CObject: &models.Namespace{},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue