Implemented Create and Update methods on list
This commit is contained in:
parent
9e8f13edf6
commit
b1de837c4f
12 changed files with 152 additions and 29 deletions
|
@ -145,6 +145,11 @@ Teams sind global, d.h. Ein Team kann mehrere Namespaces verwalten.
|
||||||
|
|
||||||
## Anderes
|
## Anderes
|
||||||
|
|
||||||
|
* [ ] Refactor!!!! Alle Funktionen raus, die nicht mehr grbaucht werden + Funktionen vereinfachen/zusammenführen.
|
||||||
|
Wenn ein Objekt 5x hin und hergereicht wird, und jedesmal nur geringfügig was dran geändert wird sollte das
|
||||||
|
doch auch in einer Funktion machbar sein.
|
||||||
|
* [ ] ganz viel in eigene neue Dateien + Packages auslagern, am besten eine package pro model mit allen methoden etc.
|
||||||
|
* [ ] Bessere Lösung der Rechteüberprüfung überlegen?
|
||||||
* [ ] CI aufsetzen
|
* [ ] CI aufsetzen
|
||||||
* [ ] Tests schreiben
|
* [ ] Tests schreiben
|
||||||
* [ ] Namen finden
|
* [ ] Namen finden
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
type CRUDable interface {
|
type CRUDable interface {
|
||||||
Create()
|
Create(*User) (error)
|
||||||
ReadOne(int64) error
|
ReadOne(int64) error
|
||||||
ReadAll(*User) (interface{}, error)
|
ReadAll(*User) (interface{}, error)
|
||||||
Update()
|
Update(int64, *User) error
|
||||||
Delete()
|
Delete()
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,19 +143,19 @@ func (err ErrListDoesNotExist) Error() string {
|
||||||
return fmt.Sprintf("List does not exist [ID: %d]", err.ID)
|
return fmt.Sprintf("List does not exist [ID: %d]", err.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrNeedToBeListOwner represents an error, where the user is not the owner of that list (used i.e. when deleting a list)
|
// ErrNeedToBeListAdmin represents an error, where the user is not the owner of that list (used i.e. when deleting a list)
|
||||||
type ErrNeedToBeListOwner struct {
|
type ErrNeedToBeListAdmin struct {
|
||||||
ListID int64
|
ListID int64
|
||||||
UserID int64
|
UserID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsErrListDoesNotExist checks if an error is a ErrListDoesNotExist.
|
// IsErrListDoesNotExist checks if an error is a ErrListDoesNotExist.
|
||||||
func IsErrNeedToBeListOwner(err error) bool {
|
func IsErrNeedToBeListAdmin(err error) bool {
|
||||||
_, ok := err.(ErrNeedToBeListOwner)
|
_, ok := err.(ErrNeedToBeListAdmin)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err ErrNeedToBeListOwner) Error() string {
|
func (err ErrNeedToBeListAdmin) Error() string {
|
||||||
return fmt.Sprintf("You need to be list owner to do that [ListID: %d, UserID: %d]", err.ListID, err.UserID)
|
return fmt.Sprintf("You need to be list owner to do that [ListID: %d, UserID: %d]", err.ListID, err.UserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,3 +289,4 @@ func IsErrUserDoesNotHaveWriteAccessToNamespace(err error) bool {
|
||||||
func (err ErrUserDoesNotHaveWriteAccessToNamespace) Error() string {
|
func (err ErrUserDoesNotHaveWriteAccessToNamespace) Error() string {
|
||||||
return fmt.Sprintf("You need to have write access to this namespace to do that [NamespaceID: %d, UserID: %d]", err.NamespaceID, err.UserID)
|
return fmt.Sprintf("You need to have write access to this namespace to do that [NamespaceID: %d, UserID: %d]", err.NamespaceID, err.UserID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,6 @@ package models
|
||||||
|
|
||||||
// CreateOrUpdateList updates a list or creates it if it doesn't exist
|
// CreateOrUpdateList updates a list or creates it if it doesn't exist
|
||||||
func CreateOrUpdateList(list *List) (err error) {
|
func CreateOrUpdateList(list *List) (err error) {
|
||||||
// Check if it exists
|
|
||||||
_, err = GetListByID(list.ID)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the user exists
|
|
||||||
list.Owner, _, err = GetUserByID(list.Owner.ID)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
list.OwnerID = list.Owner.ID
|
|
||||||
|
|
||||||
if list.ID == 0 {
|
if list.ID == 0 {
|
||||||
_, err = x.Insert(list)
|
_, err = x.Insert(list)
|
||||||
|
@ -30,3 +18,46 @@ func CreateOrUpdateList(list *List) (err error) {
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *List) Update(id int64, doer *User) (err error) {
|
||||||
|
l.ID = id
|
||||||
|
|
||||||
|
// Check if it exists
|
||||||
|
oldList, err := GetListByID(l.ID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check rights
|
||||||
|
user, _, err := GetUserByID(doer.ID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !oldList.IsAdmin(&user) {
|
||||||
|
return ErrNeedToBeListAdmin{ListID:id, UserID:user.ID}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateOrUpdateList(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *List) Create(doer *User) (err error) {
|
||||||
|
// Check rights
|
||||||
|
user, _, err := GetUserByID(doer.ID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the namespace of the list to check if the user can write to it
|
||||||
|
namespace, err := GetNamespaceByID(l.NamespaceID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !namespace.CanWrite(doer) {
|
||||||
|
return ErrUserDoesNotHaveWriteAccessToNamespace{UserID:user.ID, NamespaceID:namespace.ID}
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Owner.ID = user.ID
|
||||||
|
|
||||||
|
return CreateOrUpdateList(l)
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ func DeleteListByID(listID int64, doer *User) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if list.Owner.ID != doer.ID {
|
if list.Owner.ID != doer.ID {
|
||||||
return ErrNeedToBeListOwner{ListID: listID, UserID: doer.ID}
|
return ErrNeedToBeListAdmin{ListID: listID, UserID: doer.ID}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the list
|
// Delete the list
|
||||||
|
|
|
@ -16,8 +16,6 @@ func CreateOrUpdateListItem(item *ListItem) (newItem *ListItem, err error) {
|
||||||
}
|
}
|
||||||
item.CreatedByID = item.CreatedBy.ID
|
item.CreatedByID = item.CreatedBy.ID
|
||||||
|
|
||||||
// TODO: Check if the user has the right to add/update an item to that list
|
|
||||||
|
|
||||||
if item.ID != 0 {
|
if item.ID != 0 {
|
||||||
_, err = x.ID(item.ID).Update(item)
|
_, err = x.ID(item.ID).Update(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,6 +15,7 @@ type List struct {
|
||||||
Updated int64 `xorm:"updated" json:"updated"`
|
Updated int64 `xorm:"updated" json:"updated"`
|
||||||
|
|
||||||
CRUDable `xorm:"-" json:"-"`
|
CRUDable `xorm:"-" json:"-"`
|
||||||
|
Rights `xorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lists is a multiple of list
|
// Lists is a multiple of list
|
||||||
|
@ -73,3 +74,19 @@ func (l *List) ReadOne(id int64) (err error) {
|
||||||
*l, err = GetListByID(id)
|
*l, err = GetListByID(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *List) IsAdmin(user *User) bool {
|
||||||
|
// Owners are always admins
|
||||||
|
if l.Owner.ID == user.ID {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Team rights
|
||||||
|
// aka "is the user in a team which has admin rights?"
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// Check Namespace rights
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
|
@ -11,6 +11,9 @@ type Namespace struct {
|
||||||
|
|
||||||
Created int64 `xorm:"created" json:"created"`
|
Created int64 `xorm:"created" json:"created"`
|
||||||
Updated int64 `xorm:"updated" json:"updated"`
|
Updated int64 `xorm:"updated" json:"updated"`
|
||||||
|
|
||||||
|
CRUDable `xorm:"-" json:"-"`
|
||||||
|
Rights `xorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName makes beautiful table names
|
// TableName makes beautiful table names
|
||||||
|
@ -58,6 +61,14 @@ func (user *User) HasNamespaceAccess(namespace *Namespace) (err error) {
|
||||||
return ErrUserDoesNotHaveAccessToNamespace{UserID: user.ID, NamespaceID: namespace.ID}
|
return ErrUserDoesNotHaveAccessToNamespace{UserID: user.ID, NamespaceID: namespace.ID}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Namespace) CanWrite(user *User) bool {
|
||||||
|
if err := user.HasNamespaceAccess(n); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (user *User) HasNamespaceWriteAccess(namespace *Namespace) (err error) {
|
func (user *User) HasNamespaceWriteAccess(namespace *Namespace) (err error) {
|
||||||
|
|
||||||
// Owners always have access
|
// Owners always have access
|
||||||
|
|
|
@ -2,4 +2,6 @@ package models
|
||||||
|
|
||||||
type Rights interface {
|
type Rights interface {
|
||||||
IsAdmin(*User) bool
|
IsAdmin(*User) bool
|
||||||
|
CanWrite(*User) bool
|
||||||
|
CanRead(*User) bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,21 @@ import (
|
||||||
"git.kolaente.de/konrad/list/models"
|
"git.kolaente.de/konrad/list/models"
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This does web stuff, aka returns json etc. Uses CRUDable Methods to get the data
|
// This does web stuff, aka returns json etc. Uses CRUDable Methods to get the data
|
||||||
type CRUDWebHandler struct {
|
type CRUDWebHandler struct {
|
||||||
CObject interface{ models.CRUDable }
|
CObject interface{
|
||||||
|
models.CRUDable
|
||||||
|
models.Rights
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This does json, handles the request
|
// This does json, handles the request
|
||||||
func (c *CRUDWebHandler) ReadOneWeb(ctx echo.Context) error {
|
func (c *CRUDWebHandler) ReadOneWeb(ctx echo.Context) error {
|
||||||
|
|
||||||
// Get the ID
|
// Get the ID
|
||||||
id, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
|
id, err := models.GetIntURLParam("id", ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.JSON(http.StatusBadRequest, models.Message{"Invalid ID."})
|
return ctx.JSON(http.StatusBadRequest, models.Message{"Invalid ID."})
|
||||||
}
|
}
|
||||||
|
@ -37,7 +39,7 @@ func (c *CRUDWebHandler) ReadOneWeb(ctx echo.Context) error {
|
||||||
return ctx.JSON(http.StatusOK, c.CObject)
|
return ctx.JSON(http.StatusOK, c.CObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// ReadAllWeb returns all elements of a type
|
||||||
func (c *CRUDWebHandler) ReadAllWeb(ctx echo.Context) error {
|
func (c *CRUDWebHandler) ReadAllWeb(ctx echo.Context) error {
|
||||||
currentUser, err := models.GetCurrentUser(ctx)
|
currentUser, err := models.GetCurrentUser(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -52,3 +54,59 @@ func (c *CRUDWebHandler) ReadAllWeb(ctx echo.Context) error {
|
||||||
|
|
||||||
return ctx.JSON(http.StatusOK, lists)
|
return ctx.JSON(http.StatusOK, lists)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateWeb is the webhandler to update an object
|
||||||
|
func (c *CRUDWebHandler) UpdateWeb(ctx echo.Context) error {
|
||||||
|
// Get the object
|
||||||
|
if err := ctx.Bind(&c.CObject); err != nil {
|
||||||
|
return ctx.JSON(http.StatusBadRequest, models.Message{"No model provided."})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the ID
|
||||||
|
var err error
|
||||||
|
id, err := models.GetIntURLParam("id", ctx)
|
||||||
|
if err != nil {
|
||||||
|
return ctx.JSON(http.StatusBadRequest, models.Message{"Invalid ID."})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the user has the right to do that
|
||||||
|
currentUser, err := models.GetCurrentUser(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return ctx.JSON(http.StatusInternalServerError, models.Message{"Could not determine the current user."})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the update
|
||||||
|
err = c.CObject.Update(id, ¤tUser)
|
||||||
|
if err != nil {
|
||||||
|
if models.IsErrNeedToBeListAdmin(err) {
|
||||||
|
return echo.NewHTTPError(http.StatusForbidden, "You need to be list admin to do that.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.JSON(http.StatusOK, c.CObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateWeb is the handler to create an object
|
||||||
|
func (c *CRUDWebHandler) CreateWeb(ctx echo.Context) error {
|
||||||
|
// Get the object
|
||||||
|
if err := ctx.Bind(&c.CObject); err != nil {
|
||||||
|
return ctx.JSON(http.StatusBadRequest, models.Message{"No model provided."})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the user to pass for later checks
|
||||||
|
currentUser, err := models.GetCurrentUser(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, "Could not determine the current user.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create
|
||||||
|
err = c.CObject.Create(¤tUser)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.JSON(http.StatusOK, c.CObject)
|
||||||
|
}
|
|
@ -49,7 +49,7 @@ func DeleteListByID(c echo.Context) error {
|
||||||
|
|
||||||
err = models.DeleteListByID(itemID, &user)
|
err = models.DeleteListByID(itemID, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if models.IsErrNeedToBeListOwner(err) {
|
if models.IsErrNeedToBeListAdmin(err) {
|
||||||
return c.JSON(http.StatusForbidden, models.Message{"You need to be the list owner to delete a list."})
|
return c.JSON(http.StatusForbidden, models.Message{"You need to be the list owner to delete a list."})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ func RegisterRoutes(e *echo.Echo) {
|
||||||
}
|
}
|
||||||
a.GET("/lists", listHandler.ReadAllWeb)
|
a.GET("/lists", listHandler.ReadAllWeb)
|
||||||
a.GET("/lists/:id", listHandler.ReadOneWeb)
|
a.GET("/lists/:id", listHandler.ReadOneWeb)
|
||||||
a.POST("/lists/:id", apiv1.UpdateList)
|
a.POST("/lists/:id", listHandler.UpdateWeb)
|
||||||
a.PUT("/lists/:id", apiv1.AddListItem)
|
a.PUT("/lists/:id", apiv1.AddListItem)
|
||||||
a.DELETE("/lists/:id", apiv1.DeleteListByID)
|
a.DELETE("/lists/:id", apiv1.DeleteListByID)
|
||||||
|
|
||||||
|
@ -105,5 +105,5 @@ func RegisterRoutes(e *echo.Echo) {
|
||||||
a.POST("/namespaces/:id", apiv1.UpdateNamespace)
|
a.POST("/namespaces/:id", apiv1.UpdateNamespace)
|
||||||
a.DELETE("/namespaces/:id", apiv1.DeleteNamespaceByID)
|
a.DELETE("/namespaces/:id", apiv1.DeleteNamespaceByID)
|
||||||
a.GET("/namespaces/:id/lists", apiv1.GetListsByNamespaceID)
|
a.GET("/namespaces/:id/lists", apiv1.GetListsByNamespaceID)
|
||||||
a.PUT("/namespaces/:id/lists", apiv1.AddList)
|
a.PUT("/namespaces/:id/lists", listHandler.CreateWeb)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue