mirror of
https://github.com/go-shiori/shiori.git
synced 2024-09-20 15:06:14 +08:00
domain validation
This commit is contained in:
parent
64f533d588
commit
b79340afa4
|
@ -30,7 +30,10 @@ func (d *AccountsDomain) ListAccounts(ctx context.Context) ([]model.AccountDTO,
|
|||
}
|
||||
|
||||
func (d *AccountsDomain) CreateAccount(ctx context.Context, account model.AccountDTO) (*model.AccountDTO, error) {
|
||||
// Hash password with bcrypt
|
||||
if err := account.IsValidCreate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(account.Password), 10)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error hashing provided password: %w", err)
|
||||
|
@ -71,6 +74,10 @@ func (d *AccountsDomain) DeleteAccount(ctx context.Context, id int) error {
|
|||
}
|
||||
|
||||
func (d *AccountsDomain) UpdateAccount(ctx context.Context, account model.AccountDTO) (*model.AccountDTO, error) {
|
||||
if err := account.IsValidUpdate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get account from database
|
||||
storedAccount, _, err := d.deps.Database.GetAccount(ctx, account.ID)
|
||||
if errors.Is(err, database.ErrNotFound) {
|
||||
|
|
|
@ -2,7 +2,6 @@ package api_v1
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
|
@ -57,21 +56,11 @@ func (r *AccountsAPIRoutes) listHandler(c *gin.Context) {
|
|||
}
|
||||
|
||||
type createAccountPayload struct {
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
IsVisitor bool `json:"is_visitor"`
|
||||
}
|
||||
|
||||
func (p *createAccountPayload) IsValid() error {
|
||||
if p.Username == "" {
|
||||
return fmt.Errorf("username should not be empty")
|
||||
}
|
||||
if p.Password == "" {
|
||||
return fmt.Errorf("password should not be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *createAccountPayload) ToAccountDTO() model.AccountDTO {
|
||||
return model.AccountDTO{
|
||||
Username: p.Username,
|
||||
|
@ -97,13 +86,12 @@ func (r *AccountsAPIRoutes) createHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := payload.IsValid(); err != nil {
|
||||
r.logger.WithError(err).Error("error validating payload")
|
||||
account, err := r.deps.Domains.Accounts.CreateAccount(c.Request.Context(), payload.ToAccountDTO())
|
||||
if err, isValidationErr := err.(model.ValidationError); isValidationErr {
|
||||
response.SendError(c, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
account, err := r.deps.Domains.Accounts.CreateAccount(c.Request.Context(), payload.ToAccountDTO())
|
||||
if err != nil {
|
||||
r.logger.WithError(err).Error("error creating account")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
|
@ -172,6 +160,11 @@ func (r *AccountsAPIRoutes) updateHandler(c *gin.Context) {
|
|||
payload.ID = model.DBID(accountID)
|
||||
|
||||
account, err := r.deps.Domains.Accounts.UpdateAccount(c.Request.Context(), payload)
|
||||
if err, isValidationErr := err.(model.ValidationError); isValidationErr {
|
||||
response.SendError(c, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
r.logger.WithError(err).Error("error updating account")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
|
|
|
@ -61,7 +61,7 @@ func (a Account) ToDTO() AccountDTO {
|
|||
type AccountDTO struct {
|
||||
ID DBID `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"-"` // Used only to store, not to retrieve
|
||||
Password string `json:"passowrd,omitempty"` // Used only to store, not to retrieve
|
||||
Owner *bool `json:"owner"`
|
||||
Config *UserConfig `json:"config"`
|
||||
}
|
||||
|
@ -69,3 +69,23 @@ type AccountDTO struct {
|
|||
func (adto *AccountDTO) IsOwner() bool {
|
||||
return adto.Owner != nil && *adto.Owner
|
||||
}
|
||||
|
||||
func (adto *AccountDTO) IsValidCreate() error {
|
||||
if adto.Username == "" {
|
||||
return NewValidationError("username", "username should not be empty")
|
||||
}
|
||||
|
||||
if adto.Password == "" {
|
||||
return NewValidationError("password", "password should not be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adto *AccountDTO) IsValidUpdate() error {
|
||||
if adto.Username == "" && adto.Password == "" && adto.Owner == nil && adto.Config == nil {
|
||||
return NewValidationError("account", "no fields to update")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
20
internal/model/validation.go
Normal file
20
internal/model/validation.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package model
|
||||
|
||||
// ValidationError represents a validation error.
|
||||
// This errors are used in the domain layer to indicate an error that is caused generally
|
||||
// by the user and has to be sent back via the API or appropriate channel.
|
||||
type ValidationError struct {
|
||||
Field string `json:"field"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (v ValidationError) Error() string {
|
||||
return v.Message
|
||||
}
|
||||
|
||||
func NewValidationError(field, message string) ValidationError {
|
||||
return ValidationError{
|
||||
Field: field,
|
||||
Message: message,
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue