implemented namespace update via interface method
This commit is contained in:
parent
0aa84e653f
commit
261aaba315
9 changed files with 103 additions and 224 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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.")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue