Added validation for structs (#19)
This commit is contained in:
@ -267,6 +267,43 @@ func (err ErrIDCannotBeZero) HTTPError() HTTPError {
|
||||
return HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeIDCannotBeZero, Message: "The ID cannot be empty or 0."}
|
||||
}
|
||||
|
||||
// ErrInvalidData represents a "ErrInvalidData" kind of error. Used when a struct is invalid -> validation failed.
|
||||
type ErrInvalidData struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
// IsErrInvalidData checks if an error is a ErrIDCannotBeZero.
|
||||
func IsErrInvalidData(err error) bool {
|
||||
_, ok := err.(ErrInvalidData)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrInvalidData) Error() string {
|
||||
return fmt.Sprintf("Struct is invalid. %s", err.Message)
|
||||
}
|
||||
|
||||
// ErrCodeInvalidData holds the unique world-error code of this error
|
||||
const ErrCodeInvalidData = 2002
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrInvalidData) HTTPError() HTTPError {
|
||||
return HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeInvalidData, Message: err.Message}
|
||||
}
|
||||
|
||||
// ValidationHTTPError is the http error when a validation fails
|
||||
type ValidationHTTPError struct {
|
||||
HTTPError
|
||||
InvalidFields []string `json:"invalid_fields"`
|
||||
}
|
||||
|
||||
// Error implements the Error type (so we can return it as type error)
|
||||
func (err ValidationHTTPError) Error() string {
|
||||
theErr := ErrInvalidData{
|
||||
Message: err.Message,
|
||||
}
|
||||
return theErr.Error()
|
||||
}
|
||||
|
||||
// ===========
|
||||
// List errors
|
||||
// ===========
|
||||
|
@ -5,16 +5,16 @@ import "sort"
|
||||
// List represents a list of tasks
|
||||
type List struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"list"`
|
||||
Title string `xorm:"varchar(250)" json:"title"`
|
||||
Description string `xorm:"varchar(1000)" json:"description"`
|
||||
Title string `xorm:"varchar(250)" json:"title" valid:"required,runelength(5|250)"`
|
||||
Description string `xorm:"varchar(1000)" json:"description" valid:"runelength(0|1000)"`
|
||||
OwnerID int64 `xorm:"int(11) INDEX" json:"-"`
|
||||
NamespaceID int64 `xorm:"int(11) INDEX" json:"-" param:"namespace"`
|
||||
|
||||
Owner User `xorm:"-" json:"owner"`
|
||||
Tasks []*ListTask `xorm:"-" json:"tasks"`
|
||||
|
||||
Created int64 `xorm:"created" json:"created"`
|
||||
Updated int64 `xorm:"updated" json:"updated"`
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
|
||||
CRUDable `xorm:"-" json:"-"`
|
||||
Rights `xorm:"-" json:"-"`
|
||||
|
@ -3,15 +3,16 @@ package models
|
||||
// ListTask represents an task in a todolist
|
||||
type ListTask struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"listtask"`
|
||||
Text string `xorm:"varchar(250)" json:"text"`
|
||||
Description string `xorm:"varchar(250)" json:"description"`
|
||||
Text string `xorm:"varchar(250)" json:"text" valid:"required,runelength(5|250)"`
|
||||
Description string `xorm:"varchar(250)" json:"description" valid:"runelength(0|250)"`
|
||||
Done bool `xorm:"INDEX" json:"done"`
|
||||
DueDateUnix int64 `xorm:"int(11) INDEX" json:"dueDate"`
|
||||
ReminderUnix int64 `xorm:"int(11) INDEX" json:"reminderDate"`
|
||||
CreatedByID int64 `xorm:"int(11)" json:"-"` // ID of the user who put that task on the list
|
||||
ListID int64 `xorm:"int(11) INDEX" json:"listID" param:"list"`
|
||||
Created int64 `xorm:"created" json:"created"`
|
||||
Updated int64 `xorm:"updated" json:"updated"`
|
||||
ListID int64 `xorm:"int(11) INDEX" json:"listID" param:"list" valid:"required"`
|
||||
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
|
||||
CreatedBy User `xorm:"-" json:"createdBy"`
|
||||
|
||||
|
@ -5,10 +5,10 @@ type ListUser struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"namespace"`
|
||||
UserID int64 `xorm:"int(11) not null INDEX" json:"user_id" param:"user"`
|
||||
ListID int64 `xorm:"int(11) not null INDEX" json:"list_id" param:"list"`
|
||||
Right UserRight `xorm:"int(11) INDEX" json:"right"`
|
||||
Right UserRight `xorm:"int(11) INDEX" json:"right" valid:"length(0|2)"`
|
||||
|
||||
Created int64 `xorm:"created" json:"created"`
|
||||
Updated int64 `xorm:"updated" json:"updated"`
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
|
||||
CRUDable `xorm:"-" json:"-"`
|
||||
Rights `xorm:"-" json:"-"`
|
||||
|
@ -3,14 +3,14 @@ package models
|
||||
// Namespace holds informations about a namespace
|
||||
type Namespace struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"namespace"`
|
||||
Name string `xorm:"varchar(250)" json:"name"`
|
||||
Description string `xorm:"varchar(1000)" json:"description"`
|
||||
Name string `xorm:"varchar(250)" json:"name" valid:"required,runelength(5|250)"`
|
||||
Description string `xorm:"varchar(1000)" json:"description" valid:"runelength(0|250)"`
|
||||
OwnerID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||
|
||||
Owner User `xorm:"-" json:"owner"`
|
||||
|
||||
Created int64 `xorm:"created" json:"created"`
|
||||
Updated int64 `xorm:"updated" json:"updated"`
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
|
||||
CRUDable `xorm:"-" json:"-"`
|
||||
Rights `xorm:"-" json:"-"`
|
||||
|
@ -5,10 +5,10 @@ type NamespaceUser struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"namespace"`
|
||||
UserID int64 `xorm:"int(11) not null INDEX" json:"user_id" param:"user"`
|
||||
NamespaceID int64 `xorm:"int(11) not null INDEX" json:"namespace_id" param:"namespace"`
|
||||
Right UserRight `xorm:"int(11) INDEX" json:"right"`
|
||||
Right UserRight `xorm:"int(11) INDEX" json:"right" valid:"length(0|2)"`
|
||||
|
||||
Created int64 `xorm:"created" json:"created"`
|
||||
Updated int64 `xorm:"updated" json:"updated"`
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
|
||||
CRUDable `xorm:"-" json:"-"`
|
||||
Rights `xorm:"-" json:"-"`
|
||||
|
@ -5,10 +5,10 @@ type TeamList struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id"`
|
||||
TeamID int64 `xorm:"int(11) not null INDEX" json:"team_id" param:"team"`
|
||||
ListID int64 `xorm:"int(11) not null INDEX" json:"list_id" param:"list"`
|
||||
Right TeamRight `xorm:"int(11) INDEX" json:"right"`
|
||||
Right TeamRight `xorm:"int(11) INDEX" json:"right" valid:"length(0|2)"`
|
||||
|
||||
Created int64 `xorm:"created" json:"created"`
|
||||
Updated int64 `xorm:"updated" json:"updated"`
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
|
||||
CRUDable `xorm:"-" json:"-"`
|
||||
Rights `xorm:"-" json:"-"`
|
||||
|
@ -5,10 +5,10 @@ type TeamNamespace struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id"`
|
||||
TeamID int64 `xorm:"int(11) not null INDEX" json:"team_id" param:"team"`
|
||||
NamespaceID int64 `xorm:"int(11) not null INDEX" json:"namespace_id" param:"namespace"`
|
||||
Right TeamRight `xorm:"int(11) INDEX" json:"right"`
|
||||
Right TeamRight `xorm:"int(11) INDEX" json:"right" valid:"length(0|2)"`
|
||||
|
||||
Created int64 `xorm:"created" json:"created"`
|
||||
Updated int64 `xorm:"updated" json:"updated"`
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
|
||||
CRUDable `xorm:"-" json:"-"`
|
||||
Rights `xorm:"-" json:"-"`
|
||||
|
@ -3,15 +3,15 @@ package models
|
||||
// Team holds a team object
|
||||
type Team struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"team"`
|
||||
Name string `xorm:"varchar(250) not null" json:"name"`
|
||||
Description string `xorm:"varchar(250)" json:"description"`
|
||||
Name string `xorm:"varchar(250) not null" json:"name" valid:"required,runelength(5|250)"`
|
||||
Description string `xorm:"varchar(250)" json:"description" valid:"runelength(0|250)"`
|
||||
CreatedByID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||
|
||||
CreatedBy User `xorm:"-" json:"created_by"`
|
||||
Members []*TeamUser `xorm:"-" json:"members"`
|
||||
|
||||
Created int64 `xorm:"created" json:"created"`
|
||||
Updated int64 `xorm:"updated" json:"updated"`
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
|
||||
CRUDable `xorm:"-" json:"-"`
|
||||
Rights `xorm:"-" json:"-"`
|
||||
@ -42,8 +42,8 @@ type TeamMember struct {
|
||||
UserID int64 `xorm:"int(11) not null INDEX" json:"user_id" param:"user"`
|
||||
Admin bool `xorm:"tinyint(1) INDEX" json:"admin"`
|
||||
|
||||
Created int64 `xorm:"created" json:"created"`
|
||||
Updated int64 `xorm:"updated" json:"updated"`
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
|
||||
CRUDable `xorm:"-" json:"-"`
|
||||
Rights `xorm:"-" json:"-"`
|
||||
|
@ -15,16 +15,16 @@ type UserLogin struct {
|
||||
// User holds information about an user
|
||||
type User struct {
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id"`
|
||||
Username string `xorm:"varchar(250) not null unique" json:"username"`
|
||||
Username string `xorm:"varchar(250) not null unique" json:"username" valid:"length(5|250)"`
|
||||
Password string `xorm:"varchar(250) not null" json:"-"`
|
||||
Email string `xorm:"varchar(250)" json:"email"`
|
||||
Email string `xorm:"varchar(250)" json:"email" valid:"email,length(0|250)"`
|
||||
IsActive bool `json:"-"`
|
||||
|
||||
PasswordResetToken string `xorm:"varchar(450)" json:"-"`
|
||||
EmailConfirmToken string `xorm:"varchar(450)" json:"-"`
|
||||
|
||||
Created int64 `xorm:"created" json:"-"`
|
||||
Updated int64 `xorm:"updated" json:"-"`
|
||||
Created int64 `xorm:"created" json:"created" valid:"range(0|0)"`
|
||||
Updated int64 `xorm:"updated" json:"updated" valid:"range(0|0)"`
|
||||
}
|
||||
|
||||
// TableName returns the table name for users
|
||||
|
@ -17,6 +17,11 @@ func (c *WebHandler) CreateWeb(ctx echo.Context) error {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "No or invalid model provided.")
|
||||
}
|
||||
|
||||
// Validate the struct
|
||||
if err := ctx.Validate(currentStruct); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
// Get the user to pass for later checks
|
||||
currentUser, err := models.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
|
@ -18,6 +18,11 @@ func (c *WebHandler) UpdateWeb(ctx echo.Context) error {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "No or invalid model provided.")
|
||||
}
|
||||
|
||||
// Validate the struct
|
||||
if err := ctx.Validate(currentStruct); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
// Check if the user has the right to do that
|
||||
currentUser, err := models.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
|
@ -11,17 +11,42 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"github.com/labstack/echo"
|
||||
"github.com/labstack/echo/middleware"
|
||||
"github.com/swaggo/echo-swagger"
|
||||
|
||||
_ "code.vikunja.io/api/docs" // To generate swagger docs
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/routes/crud"
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/labstack/echo"
|
||||
"github.com/labstack/echo/middleware"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/swaggo/echo-swagger"
|
||||
)
|
||||
|
||||
// CustomValidator is a dummy struct to use govalidator with echo
|
||||
type CustomValidator struct{}
|
||||
|
||||
// Validate validates stuff
|
||||
func (cv *CustomValidator) Validate(i interface{}) error {
|
||||
if _, err := govalidator.ValidateStruct(i); err != nil {
|
||||
|
||||
var errs []string
|
||||
for field, e := range govalidator.ErrorsByField(err) {
|
||||
errs = append(errs, field+": "+e)
|
||||
}
|
||||
|
||||
httperr := models.ValidationHTTPError{
|
||||
models.HTTPError{
|
||||
Code: models.ErrCodeInvalidData,
|
||||
Message: "Invalid Data",
|
||||
},
|
||||
errs,
|
||||
}
|
||||
|
||||
return httperr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewEcho registers a new Echo instance
|
||||
func NewEcho() *echo.Echo {
|
||||
e := echo.New()
|
||||
@ -33,6 +58,9 @@ func NewEcho() *echo.Echo {
|
||||
Format: "${time_rfc3339_nano}: ${remote_ip} ${method} ${status} ${uri} ${latency_human} - ${user_agent}\n",
|
||||
}))
|
||||
|
||||
// Validation
|
||||
e.Validator = &CustomValidator{}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user