From 261aaba315e6829a5c9ba328ebfcac001a14d6cc Mon Sep 17 00:00:00 2001 From: konrad Date: Thu, 12 Jul 2018 00:30:31 +0200 Subject: [PATCH] implemented namespace update via interface method --- models/error.go | 34 ++++++++- models/namespaces.go | 31 +++++---- models/namespaces_add_update.go | 69 ++++++++++--------- models/user_add_update.go | 3 +- routes/api/v1/lists_add_update.go | 99 +-------------------------- routes/api/v1/namespace_add_update.go | 73 -------------------- routes/crud/create.go | 3 - routes/crud/update.go | 13 +++- routes/routes.go | 2 +- 9 files changed, 103 insertions(+), 224 deletions(-) diff --git a/models/error.go b/models/error.go index 70cd4d71..902f52cb 100644 --- a/models/error.go +++ b/models/error.go @@ -320,4 +320,36 @@ func IsErrNamespaceNameCannotBeEmpty(err error) bool { func (err ErrNamespaceNameCannotBeEmpty) Error() string { return fmt.Sprintf("Namespace name cannot be emtpy [NamespaceID: %d, UserID: %d]", err.NamespaceID, err.UserID) -} \ No newline at end of file +} + +// ErrNamespaceOwnerCannotBeEmpty represents an error, where a namespace owner is empty. +type ErrNamespaceOwnerCannotBeEmpty struct { + NamespaceID int64 + UserID int64 +} + +// IsErrNamespaceOwnerCannotBeEmpty checks if an error is a ErrNamespaceDoesNotExist. +func IsErrNamespaceOwnerCannotBeEmpty(err error) bool { + _, ok := err.(ErrNamespaceOwnerCannotBeEmpty) + return ok +} + +func (err ErrNamespaceOwnerCannotBeEmpty) Error() string { + return fmt.Sprintf("Namespace owner cannot be emtpy [NamespaceID: %d, UserID: %d]", err.NamespaceID, err.UserID) +} + +// ErrNeedToBeNamespaceAdmin represents an error, where the user is not the admin of that namespace (used i.e. when deleting a namespace) +type ErrNeedToBeNamespaceAdmin struct { + NamespaceID int64 + UserID int64 +} + +// IsErrNeedToBeNamespaceAdmin checks if an error is a ErrNamespaceDoesNotExist. +func IsErrNeedToBeNamespaceAdmin(err error) bool { + _, ok := err.(ErrNeedToBeNamespaceAdmin) + return ok +} + +func (err ErrNeedToBeNamespaceAdmin) Error() string { + return fmt.Sprintf("You need to be namespace owner to do that [NamespaceID: %d, UserID: %d]", err.NamespaceID, err.UserID) +} diff --git a/models/namespaces.go b/models/namespaces.go index be326513..161b52ab 100644 --- a/models/namespaces.go +++ b/models/namespaces.go @@ -51,6 +51,19 @@ func (user *User) IsNamespaceAdmin(namespace *Namespace) (err error) { return ErrUserNeedsToBeNamespaceAdmin{UserID: user.ID, NamespaceID: namespace.ID} } +func (n *Namespace) IsAdmin(user *User) bool { + + // Owners always have admin rights + if user.ID == n.Owner.ID { + return true + } + + // Check if that user is in a team which has admin rights to that namespace + // TODO + + return false +} + // HasNamespaceAccess checks if the User has namespace read access func (user *User) HasNamespaceAccess(namespace *Namespace) (err error) { // Owners always have access @@ -65,26 +78,14 @@ func (user *User) HasNamespaceAccess(namespace *Namespace) (err error) { // CanWrite checks if a user has write access to a namespace func (n *Namespace) CanWrite(user *User) bool { - if err := user.HasNamespaceAccess(n); err != nil { - return false + // Owners always have access + if user.ID == n.Owner.ID { + return true } return true } -// HasNamespaceWriteAccess checks if a user has write access to a namespace -func (user *User) HasNamespaceWriteAccess(namespace *Namespace) (err error) { - - // Owners always have access - if user.ID == namespace.Owner.ID { - return nil - } - - // Check if the user is in a team which has write access to the namespace - - return ErrUserDoesNotHaveAccessToNamespace{UserID: user.ID, NamespaceID: namespace.ID} -} - // GetNamespaceByID returns a namespace object by its ID func GetNamespaceByID(id int64) (namespace Namespace, err error) { namespace.ID = id diff --git a/models/namespaces_add_update.go b/models/namespaces_add_update.go index 2d023ba6..d1545f75 100644 --- a/models/namespaces_add_update.go +++ b/models/namespaces_add_update.go @@ -1,36 +1,6 @@ package models -// CreateOrUpdateNamespace does what it says -func CreateOrUpdateNamespace(namespace *Namespace) (err error) { - // Check if the namespace exists - _, err = GetNamespaceByID(namespace.ID) - if err != nil { - return - } - - // Check if the User exists - namespace.Owner, _, err = GetUserByID(namespace.Owner.ID) - if err != nil { - return - } - namespace.OwnerID = namespace.Owner.ID - - if namespace.ID == 0 { - _, err = x.Insert(namespace) - } else { - _, err = x.ID(namespace.ID).Update(namespace) - } - - if err != nil { - return - } - - // Get the new one - *namespace, err = GetNamespaceByID(namespace.ID) - - return -} - +// Create implements the creation method via the interface func (n *Namespace) Create(doer *User, _ int64) (err error) { // Check if we have at least a name if n.Name == "" { @@ -48,3 +18,40 @@ func (n *Namespace) Create(doer *User, _ int64) (err error) { _, err = x.Insert(n) return } + +// Update implements the update method via the interface +func (n *Namespace) Update(id int64, doer *User) (err error) { + // Check if we have at least a name + if n.Name == "" { + return ErrNamespaceNameCannotBeEmpty{NamespaceID:id, UserID:doer.ID} + } + n.ID = id + + // Check if the namespace exists + currentNamespace, err := GetNamespaceByID(id) + if err != nil { + return + } + + // Check if the (new) owner exists + if currentNamespace.OwnerID != n.OwnerID { + n.Owner, _, err = GetUserByID(doer.ID) + if err != nil { + return + } + } + + // Check rights + user, _, err := GetUserByID(doer.ID) + if err != nil { + return + } + + if !currentNamespace.IsAdmin(&user) { + return ErrNeedToBeNamespaceAdmin{NamespaceID:id, UserID:doer.ID} + } + + // Do the actual update + _, err = x.ID(currentNamespace.ID).Update(n) + return +} \ No newline at end of file diff --git a/models/user_add_update.go b/models/user_add_update.go index 12027dd7..f3f23a0b 100644 --- a/models/user_add_update.go +++ b/models/user_add_update.go @@ -51,7 +51,8 @@ func CreateUser(user User) (newUser User, err error) { } // Create the user's namespace - err = CreateOrUpdateNamespace(&Namespace{Name: newUserOut.Username, Description: newUserOut.Username + "'s namespace.", Owner: newUserOut}) + newN := &Namespace{Name: newUserOut.Username, Description: newUserOut.Username + "'s namespace.", Owner: newUserOut} + err = newN.Create(&newUserOut, 0) if err != nil { return User{}, err } diff --git a/routes/api/v1/lists_add_update.go b/routes/api/v1/lists_add_update.go index 813709c6..6c30c8ee 100644 --- a/routes/api/v1/lists_add_update.go +++ b/routes/api/v1/lists_add_update.go @@ -1,7 +1,6 @@ package v1 import ( - "git.kolaente.de/konrad/list/models" "github.com/labstack/echo" "net/http" ) @@ -36,55 +35,7 @@ func AddList(c echo.Context) error { // "500": // "$ref": "#/responses/Message" - // Get the list - var list *models.List - - if err := c.Bind(&list); err != nil { - return c.JSON(http.StatusBadRequest, models.Message{"No list model provided."}) - } - - // Get the namespace ID - var err error - list.NamespaceID, err = models.GetIntURLParam("nID", c) - if err != nil { - return c.JSON(http.StatusBadRequest, models.Message{"Invalid namespace ID."}) - } - - // Get the current user for later checks - user, err := models.GetCurrentUser(c) - if err != nil { - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - list.Owner = user - - // Get the namespace - namespace, err := models.GetNamespaceByID(list.NamespaceID) - if err != nil { - if models.IsErrNamespaceDoesNotExist(err) { - return c.JSON(http.StatusNotFound, models.Message{"Namespace not found."}) - } - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - - // Check if the user has write acces to that namespace - err = user.HasNamespaceWriteAccess(&namespace) - if err != nil { - if models.IsErrUserDoesNotHaveAccessToNamespace(err) { - return c.JSON(http.StatusForbidden, models.Message{"You don't have access to this namespace."}) - } - if models.IsErrUserDoesNotHaveWriteAccessToNamespace(err) { - return c.JSON(http.StatusForbidden, models.Message{"You don't have write access to this namespace."}) - } - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - - // Create the new list - err = models.CreateOrUpdateList(list) - if err != nil { - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - - return c.JSON(http.StatusOK, list) + return echo.NewHTTPError(http.StatusNotImplemented) } // UpdateList ... @@ -116,51 +67,5 @@ func UpdateList(c echo.Context) error { // "500": // "$ref": "#/responses/Message" - // Get the list - var list *models.List - - if err := c.Bind(&list); err != nil { - return c.JSON(http.StatusBadRequest, models.Message{"No list model provided."}) - } - - // Get the list ID - var err error - list.ID, err = models.GetIntURLParam("id", c) - if err != nil { - return c.JSON(http.StatusBadRequest, models.Message{"Invalid ID."}) - } - - // Check if the list exists - // ID = 0 means new list, no error - var oldList models.List - if list.ID != 0 { - oldList, err = models.GetListByID(list.ID) - if err != nil { - if models.IsErrListDoesNotExist(err) { - return c.JSON(http.StatusBadRequest, models.Message{"The list does not exist."}) - } - return c.JSON(http.StatusInternalServerError, models.Message{"Could not check if the list exists."}) - } - } - - // Get the current user for later checks - user, err := models.GetCurrentUser(c) - if err != nil { - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - list.Owner = user - - // Check if the user owns the list - // TODO use list function for that - if user.ID != oldList.Owner.ID { - return c.JSON(http.StatusForbidden, models.Message{"You cannot edit a list you don't own."}) - } - - // Update the list - err = models.CreateOrUpdateList(list) - if err != nil { - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - - return c.JSON(http.StatusOK, list) + return echo.NewHTTPError(http.StatusNotImplemented) } diff --git a/routes/api/v1/namespace_add_update.go b/routes/api/v1/namespace_add_update.go index 40154d7c..1fc97a40 100644 --- a/routes/api/v1/namespace_add_update.go +++ b/routes/api/v1/namespace_add_update.go @@ -1,10 +1,8 @@ package v1 import ( - "git.kolaente.de/konrad/list/models" "github.com/labstack/echo" "net/http" - "strconv" ) // AddNamespace ... @@ -65,74 +63,3 @@ func UpdateNamespace(c echo.Context) error { return echo.NewHTTPError(http.StatusNotImplemented) } - -// AddOrUpdateNamespace Adds or updates a new namespace -func addOrUpdateNamespace(c echo.Context) error { - - // Get the namespace - var namespace *models.Namespace - - if err := c.Bind(&namespace); err != nil { - return c.JSON(http.StatusBadRequest, models.Message{"No namespace model provided."}) - } - - // Check if we have an ID other than the one in the struct - id := c.Param("id") - if id != "" { - // Make int - namespaceID, err := strconv.ParseInt(id, 10, 64) - - if err != nil { - return c.JSON(http.StatusBadRequest, models.Message{"Invalid ID."}) - } - namespace.ID = namespaceID - } - - // Check if the namespace exists - // ID = 0 means new namespace, no error - if namespace.ID != 0 { - _, err := models.GetNamespaceByID(namespace.ID) - if err != nil { - if models.IsErrNamespaceDoesNotExist(err) { - return c.JSON(http.StatusBadRequest, models.Message{"The namespace does not exist."}) - } - return c.JSON(http.StatusInternalServerError, models.Message{"Could not check if the namespace exists."}) - } - } - - // Get the current user for later checks - user, err := models.GetCurrentUser(c) - if err != nil { - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - namespace.Owner = user - - // update or create... - if namespace.ID == 0 { - err = models.CreateOrUpdateNamespace(namespace) - if err != nil { - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - } else { - // Check if the user has admin access to the namespace - oldNamespace, err := models.GetNamespaceByID(namespace.ID) - if err != nil { - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - err = user.IsNamespaceAdmin(&oldNamespace) - if err != nil { - if models.IsErrUserNeedsToBeNamespaceAdmin(err) { - return c.JSON(http.StatusForbidden, models.Message{"You need to be namespace admin to edit a namespace."}) - } - - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - - err = models.CreateOrUpdateNamespace(namespace) - if err != nil { - return c.JSON(http.StatusInternalServerError, models.Message{"An error occured."}) - } - } - - return c.JSON(http.StatusOK, namespace) -} diff --git a/routes/crud/create.go b/routes/crud/create.go index 6defe79b..23b5e7da 100644 --- a/routes/crud/create.go +++ b/routes/crud/create.go @@ -44,9 +44,6 @@ func (c *WebHandler) CreateWeb(ctx echo.Context) error { return echo.NewHTTPError(http.StatusForbidden, "You need to have write access on that list.") } - if models.IsErrNamespaceDoesNotExist(err) { - return echo.NewHTTPError(http.StatusBadRequest, "The namespace does not exist.") - } if models.IsErrNamespaceNameCannotBeEmpty(err) { return echo.NewHTTPError(http.StatusNotFound, "The namespace name cannot be empty.") } diff --git a/routes/crud/update.go b/routes/crud/update.go index c0434bb9..5f15d337 100644 --- a/routes/crud/update.go +++ b/routes/crud/update.go @@ -1,7 +1,6 @@ package crud import ( - "fmt" "git.kolaente.de/konrad/list/models" "github.com/labstack/echo" "net/http" @@ -29,11 +28,21 @@ func (c *WebHandler) UpdateWeb(ctx echo.Context) error { // Do the update err = c.CObject.Update(id, ¤tUser) if err != nil { - fmt.Println(err) if models.IsErrNeedToBeListAdmin(err) { return echo.NewHTTPError(http.StatusForbidden, "You need to be list admin to do that.") } + + if models.IsErrNamespaceDoesNotExist(err) { + return echo.NewHTTPError(http.StatusNotFound, "The namespace does not exist.") + } + if models.IsErrNamespaceNameCannotBeEmpty(err) { + return echo.NewHTTPError(http.StatusBadRequest, "The namespace name cannot be empty.") + } + if models.IsErrNamespaceOwnerCannotBeEmpty(err) { + return echo.NewHTTPError(http.StatusBadRequest, "The namespace owner cannot be empty.") + } + return echo.NewHTTPError(http.StatusInternalServerError) } diff --git a/routes/routes.go b/routes/routes.go index 81204dca..c3550b75 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -109,7 +109,7 @@ func RegisterRoutes(e *echo.Echo) { a.GET("/namespaces", namespaceHandler.ReadAllWeb) a.PUT("/namespaces", namespaceHandler.CreateWeb) a.GET("/namespaces/:id", apiv1.ShowNamespace) - a.POST("/namespaces/:id", apiv1.UpdateNamespace) + a.POST("/namespaces/:id", namespaceHandler.UpdateWeb) a.DELETE("/namespaces/:id", apiv1.DeleteNamespaceByID) a.GET("/namespaces/:id/lists", apiv1.GetListsByNamespaceID) }