Compare commits

...

3 Commits

Author SHA1 Message Date
Emil Tullstedt
8f46046255 replace shorturl errors with generated errors 2022-12-19 14:26:39 +01:00
Emil Tullstedt
be1984cd36 generate errors for ShortURL service using errata 2022-12-19 14:25:44 +01:00
Emil Tullstedt
dbbae9f944 Errors: Use errata to generate errors from HCL files 2022-12-19 14:25:19 +01:00
10 changed files with 151 additions and 17 deletions

View File

@@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models/errs"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
@@ -17,7 +18,7 @@ import (
func (hs *HTTPServer) createShortURL(c *models.ReqContext) response.Response {
cmd := dtos.CreateShortURLCmd{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Err(models.ErrShortURLBadRequest.Errorf("bad request data: %w", err))
return response.Err(errs.ErrShorturlBadRequest.Errorf("bad request data: %w", err))
}
hs.log.Debug("Received request to create short URL", "path", cmd.Path)
shortURL, err := hs.ShortURLService.CreateShortURL(c.Req.Context(), c.SignedInUser, cmd.Path)
@@ -45,7 +46,7 @@ func (hs *HTTPServer) redirectFromShortURL(c *models.ReqContext) {
shortURL, err := hs.ShortURLService.GetShortURLByUID(c.Req.Context(), c.SignedInUser, shortURLUID)
if err != nil {
if models.ErrShortURLNotFound.Is(err) {
if errs.ErrShorturlNotFound.Is(err) {
hs.log.Debug("Not redirecting short URL since not found")
return
}

7
pkg/models/errs/Makefile Normal file
View File

@@ -0,0 +1,7 @@
SRCS=$(wildcard *.hcl)
OBJS=$(SRCS:.hcl=.gen.go)
all: $(OBJS)
%.gen.go: %.hcl errutil.tmpl
eish generate --source=$< --template=./errutil.tmpl --package=errs > $@

View File

@@ -0,0 +1,39 @@
// Code generated by Errata. DO NOT EDIT.
// Errata Schema Version: {{ SchemaVersion }}
// Grafana errors schema version: 1
// Hash: {{ Hash }}
package {{ Package }}
import (
"github.com/grafana/grafana/pkg/util/errutil"
)
var (
{%- for code, error in Errors sorted %}
Err{{ code | constantize }} = errutil.NewBase(
{%- if error.Cause %}
errutil.Status{{ error.Cause }},
{%- else %}
errutil.StatusMissing, // Fixme: Set 'cause' to one of the statuses defined as "errutil.Status*".
{%- endif %}
{{ code | stringformat:"%q" }},
{%- if error.Message && !error.Labels.template %}
errutil.WithPublicMessage(`{{ error.Message | escape_backtick -}}`),
{%- endif %}
{%- if error.Labels.severity %}
errutil.WithLogLevel(errutil.Level{{ error.Labels.severity | capfirst }}),
{%- endif %}
{%- if error.Guide %}
errutil.WithGuide(`{{ error.Guide | escape_backtick -}}`),
{%- endif %}
){%- if error.Labels.template %}.MustTemplate(
{%- if error.Labels.logMessage %}
`{{ error.Labels.logMessage | escape_backtick -}}`,
errutil.WithPublic(`{{ error.Message | escape_backtick -}}`),
{%- else %}
`{{ error.Message | escape_backtick -}}`,
errutil.WithPublicFromLog(),
{%- endif %}
){%- endif %}
{%- endfor %}
)

3
pkg/models/errs/gen.go Normal file
View File

@@ -0,0 +1,3 @@
package errs
//go:generate make all

View File

@@ -0,0 +1,42 @@
// Code generated by Errata. DO NOT EDIT.
// Errata Schema Version: 0.1
// Grafana errors schema version: 1
// Hash: 41882bb99ce21663b620467357c47a06
package errs
import (
"github.com/grafana/grafana/pkg/util/errutil"
)
var (
ErrShorturlAbsolutePath = errutil.NewBase(
errutil.StatusValidationFailed,
"shorturl.absolutePath",
errutil.WithPublicMessage(`Path should be relative`),
errutil.WithGuide(`Try removing any prefixing ` + "`" + `/` + "`" + ` to your path.`),
)
ErrShorturlBadRequest = errutil.NewBase(
errutil.StatusBadRequest,
"shorturl.badRequest",
errutil.WithPublicMessage(`Bad request`),
)
ErrShorturlInternal = errutil.NewBase(
errutil.StatusInternal,
"shorturl.internal",
errutil.WithPublicMessage(`Internal server error`),
)
ErrShorturlInvalidPath = errutil.NewBase(
errutil.StatusValidationFailed,
"shorturl.invalidPath",
errutil.WithPublicMessage(`Invalid short URL path`),
errutil.WithGuide(`There is something wrong with the path you've submitted. It might
contain unsupported characters or path-components .. to move up in the
hierarchy, which is not supported by the shorturl service.
`),
)
ErrShorturlNotFound = errutil.NewBase(
errutil.StatusNotFound,
"shorturl.notFound",
errutil.WithPublicMessage(`Could not find the specified short URL`),
)
)

View File

@@ -0,0 +1,32 @@
version = "0.1"
error "shorturl.badRequest" {
message = "Bad request"
cause = "BadRequest"
}
error "shorturl.notFound" {
message = "Could not find the specified short URL"
cause = "NotFound"
}
error "shorturl.absolutePath" {
message = "Path should be relative"
cause = "ValidationFailed"
guide = "Try removing any prefixing `/` to your path."
}
error "shorturl.invalidPath" {
message = "Invalid short URL path"
cause = "ValidationFailed"
guide = <<EOF
There is something wrong with the path you've submitted. It might
contain unsupported characters or path-components .. to move up in the
hierarchy, which is not supported by the shorturl service.
EOF
}
error "shorturl.internal" {
message = "Internal server error"
cause = "Internal"
}

View File

@@ -2,16 +2,6 @@ package models
import (
"time"
"github.com/grafana/grafana/pkg/util/errutil"
)
var (
ErrShortURLBadRequest = errutil.NewBase(errutil.StatusBadRequest, "shorturl.bad-request")
ErrShortURLNotFound = errutil.NewBase(errutil.StatusNotFound, "shorturl.not-found")
ErrShortURLAbsolutePath = errutil.NewBase(errutil.StatusValidationFailed, "shorturl.absolute-path", errutil.WithPublicMessage("Path should be relative"))
ErrShortURLInvalidPath = errutil.NewBase(errutil.StatusValidationFailed, "shorturl.invalid-path", errutil.WithPublicMessage("Invalid short URL path"))
ErrShortURLInternal = errutil.NewBase(errutil.StatusInternal, "shorturl.internal")
)
type ShortUrl struct {

View File

@@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/models/errs"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
)
@@ -39,7 +40,7 @@ func (s ShortURLService) GetShortURLByUID(ctx context.Context, user *user.Signed
return err
}
if !exists {
return models.ErrShortURLNotFound.Errorf("short URL not found")
return errs.ErrShorturlNotFound.Errorf("short URL not found")
}
return nil
@@ -67,10 +68,10 @@ func (s ShortURLService) CreateShortURL(ctx context.Context, user *user.SignedIn
relPath = strings.TrimSpace(relPath)
if path.IsAbs(relPath) {
return nil, models.ErrShortURLAbsolutePath.Errorf("expected relative path: %s", relPath)
return nil, errs.ErrShorturlAbsolutePath.Errorf("expected relative path: %s", relPath)
}
if strings.Contains(relPath, "../") {
return nil, models.ErrShortURLInvalidPath.Errorf("path cannot contain '../': %s", relPath)
return nil, errs.ErrShorturlInvalidPath.Errorf("path cannot contain '../': %s", relPath)
}
now := time.Now().Unix()
@@ -87,7 +88,7 @@ func (s ShortURLService) CreateShortURL(ctx context.Context, user *user.SignedIn
return err
})
if err != nil {
return nil, models.ErrShortURLInternal.Errorf("failed to insert shorturl: %w", err)
return nil, errs.ErrShorturlInternal.Errorf("failed to insert shorturl: %w", err)
}
return &shortURL, nil

View File

@@ -5,6 +5,8 @@ import (
"testing"
"time"
"github.com/grafana/grafana/pkg/models/errs"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/db"
@@ -81,7 +83,7 @@ func TestShortURLService(t *testing.T) {
shortURL, err := service.GetShortURLByUID(context.Background(), user, "testnotfounduid")
require.Error(t, err)
require.True(t, models.ErrShortURLNotFound.Is(err))
require.True(t, errs.ErrShorturlNotFound.Is(err))
require.Nil(t, shortURL)
})
}

View File

@@ -15,6 +15,7 @@ type Base struct {
messageID string
publicMessage string
logLevel LogLevel
guide string
}
// NewBase initializes a [Base] that is used to construct [Error].
@@ -54,6 +55,17 @@ func WithLogLevel(lvl LogLevel) BaseOpt {
}
}
// WithGuide adds a longer text intended to support a user to resolve
// the error.
//
// Used as a functional option to [NewBase].
func WithGuide(guide string) BaseOpt {
return func(b Base) Base {
b.guide = guide
return b
}
}
// WithPublicMessage sets the default public message that will be used
// for errors based on this [Base].
//
@@ -171,6 +183,9 @@ type Error struct {
PublicPayload map[string]interface{}
// LogLevel provides a suggested level of logging for the error.
LogLevel LogLevel
// Guide is a longer text intended to support a user to resolve
// the error.
Guide string
}
// MarshalJSON returns an error, we do not want raw [Error]s being
@@ -229,6 +244,7 @@ type PublicError struct {
MessageID string `json:"messageId"`
Message string `json:"message,omitempty"`
Extra map[string]interface{} `json:"extra,omitempty"`
Guide string `json:"guide,omitempty"`
}
// Public returns a subset of the error with non-sensitive information
@@ -249,5 +265,6 @@ func (e Error) Public() PublicError {
MessageID: e.MessageID,
Message: message,
Extra: e.PublicPayload,
Guide: e.Guide,
}
}