diff --git a/config.yml.sample b/config.yml.sample index e13576f21..7d9484d33 100644 --- a/config.yml.sample +++ b/config.yml.sample @@ -34,6 +34,11 @@ service: enabletotp: true # If not empty, enables logging of crashes and unhandled errors in sentry. sentrydsn: '' + # If not empty, this will enable `/test/{table}` endpoints which allow to put any content in the database. + # Used to reset the db before frontend tests. Because this is quite a dangerous feature allowing for lots of harm, + # each request made to this endpoint neefs to provide an `Authorization: ` header with the token from below.
+ # **You should never use this unless you know exactly what you're doing** + testingtoken: '' database: # Database type to use. Supported types are mysql, postgres and sqlite. diff --git a/pkg/config/config.go b/pkg/config/config.go index 6dfd00442..298ec06f0 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -51,6 +51,7 @@ const ( ServiceEnableTaskComments Key = `service.enabletaskcomments` ServiceEnableTotp Key = `service.enabletotp` ServiceSentryDsn Key = `service.sentrydsn` + ServiceTestingtoken Key = `service.testingtoken` AuthLocalEnabled Key = `auth.local.enabled` AuthOpenIDEnabled Key = `auth.openid.enabled` diff --git a/pkg/db/dump.go b/pkg/db/dump.go index 70bd3f988..32a80898f 100644 --- a/pkg/db/dump.go +++ b/pkg/db/dump.go @@ -16,7 +16,10 @@ package db -import "encoding/json" +import ( + "encoding/json" + "xorm.io/xorm/schemas" +) // Dump dumps all database tables func Dump() (data map[string][]byte, err error) { @@ -52,3 +55,22 @@ func Restore(table string, contents []map[string]interface{}) (err error) { return } + +// RestoreAndTruncate removes all content from the table before restoring it from the contents map +func RestoreAndTruncate(table string, contents []map[string]interface{}) (err error) { + if _, err := x.IsTableExist(table); err != nil { + return err + } + + if x.Dialect().URI().DBType == schemas.SQLITE { + if _, err := x.Query("DELETE FROM " + table); err != nil { + return err + } + } else { + if _, err := x.Query("TRUNCATE TABLE ?", table); err != nil { + return err + } + } + + return Restore(table, contents) +} diff --git a/pkg/routes/api/v1/testing.go b/pkg/routes/api/v1/testing.go new file mode 100644 index 000000000..7c6807340 --- /dev/null +++ b/pkg/routes/api/v1/testing.go @@ -0,0 +1,56 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-2020 Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package v1 + +import ( + "bytes" + "code.vikunja.io/api/pkg/config" + "code.vikunja.io/api/pkg/db" + "encoding/json" + "github.com/labstack/echo/v4" + "net/http" +) + +func HandleTesting(c echo.Context) error { + token := c.Request().Header.Get("Authorization") + if token != config.ServiceTestingtoken.GetString() { + return echo.ErrForbidden + } + + table := c.Param("table") + + var buf bytes.Buffer + if _, err := buf.ReadFrom(c.Request().Body); err != nil { + return err + } + + content := []map[string]interface{}{} + err := json.Unmarshal(buf.Bytes(), &content) + if err != nil { + return c.JSON(http.StatusInternalServerError, err) + } + + err = db.RestoreAndTruncate(table, content) + if err != nil { + return c.JSON(http.StatusInternalServerError, map[string]interface{}{ + "error": true, + "message": err.Error(), + }) + } + + return c.JSON(http.StatusCreated, nil) +} diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 6de5a2569..83cccfcb5 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -235,6 +235,11 @@ func registerAPIRoutes(a *echo.Group) { n.POST("/auth/openid/:provider/callback", openid.HandleCallback) } + // Testing + if config.ServiceTestingtoken.GetString() != "" { + n.PATCH("/test/:table", apiv1.HandleTesting) + } + // Info endpoint n.GET("/info", apiv1.Info)