fleet/errors/errors.go
Mike Arpaia 736bce5033 Email-based password reset (#54)
* No more hard deletes

* scaffolding for password reset endpoint

* Ensure password reset state is accounted for in VC checks

* password reset endpoints and data structures

* ability to change password with reset token

* smtp server connection pool management

* stubbing out the sending of the email

* adding mailhog via docker

* HTML emails with confgurable host name

* fixing typo in the comments

* Fixing merge which undid DatabaseError replacement

* documentation in the readme

* webpack shortcut for components

* removing a sneaky merge line that snuck in

* temporary email content api

* tests for password reset flow

* fixing go vet

* comments and making all db use `&value` rather than `reference`

* more correct usage of the errors library and moving email sending to it's own method

* using the wrong error

* fixing email mock object error

* less incorrect error usage

* rebasing and merging

* http constants for status code

* using ParseAndValidateJSON instead of BindJSON

* validate instead of binding in struct tags

* NewFromError instead of New
2016-08-12 12:20:29 -07:00

109 lines
3.2 KiB
Go

package errors
import (
"net/http"
"github.com/Sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"gopkg.in/go-playground/validator.v8"
)
// Kolide's internal representation for errors. It can be used to wrap another
// error (stored in Err), and additionally contains fields for public
// (PublicMessage) and private (PrivateMessage) error messages as well as the
// HTTP status code (StatusCode) corresponding to the error.
type KolideError struct {
Err error
StatusCode int
PublicMessage string
PrivateMessage string
}
// Implementation of error interface
func (e *KolideError) Error() string {
return e.PublicMessage
}
// Create a new KolideError specifying the public and private messages. The
// status code will be set to 500.
func New(publicMessage, privateMessage string) *KolideError {
return &KolideError{
StatusCode: http.StatusInternalServerError,
PublicMessage: publicMessage,
PrivateMessage: privateMessage,
}
}
// Create a new KolideError specifying the HTTP status, and public and private
// messages.
func NewWithStatus(status int, publicMessage, privateMessage string) *KolideError {
return &KolideError{
StatusCode: status,
PublicMessage: publicMessage,
PrivateMessage: privateMessage,
}
}
// Create a new KolideError from an error type. The public message and status
// code should be specified, while the private message will be drawn from
// err.Error()
func NewFromError(err error, status int, publicMessage string) *KolideError {
return &KolideError{
Err: err,
StatusCode: status,
PublicMessage: publicMessage,
PrivateMessage: err.Error(),
}
}
// Wrap a DB error with the extra KolideError decorations
func DatabaseError(err error) *KolideError {
return NewFromError(err, http.StatusInternalServerError, "Database error")
}
// Wrap a server error with the extra KolideError decorations
func InternalServerError(err error) *KolideError {
return NewFromError(err, http.StatusInternalServerError, "Internal server error")
}
// The status code returned for validation errors. Inspired by the Github API.
const StatusUnprocessableEntity = 422
// Handle an error, printing debug information, writing to the HTTP response as
// appropriate for the dynamic error type.
func ReturnError(c *gin.Context, err error) {
switch typedErr := err.(type) {
case *KolideError:
c.JSON(typedErr.StatusCode,
gin.H{"message": typedErr.PublicMessage})
logrus.WithError(typedErr.Err).Debug(typedErr.PrivateMessage)
case validator.ValidationErrors:
errors := make([](map[string]string), 0, len(typedErr))
for _, fieldErr := range typedErr {
m := make(map[string]string)
m["field"] = fieldErr.Name
m["code"] = "invalid"
m["message"] = fieldErr.Tag
errors = append(errors, m)
}
c.JSON(StatusUnprocessableEntity,
gin.H{"message": "Validation error",
"errors": errors,
})
logrus.WithError(typedErr).Debug("Validation error")
case gorm.Errors, *gorm.Errors:
c.JSON(http.StatusInternalServerError,
gin.H{"message": "Database error"})
logrus.WithError(typedErr).Debug(typedErr.Error())
default:
c.JSON(http.StatusInternalServerError,
gin.H{"message": "Unspecified error"})
logrus.WithError(typedErr).Debug("Unspecified error")
}
}