From ae1ebf709f0dc7d5983fd741cebd2d2fc2c83814 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 18:12:02 +0200 Subject: [PATCH 01/10] Add background upload handler --- pkg/config/config.go | 2 + pkg/modules/background/handler/background.go | 50 +++++++++++++++----- pkg/modules/background/upload/upload.go | 35 ++++++++++++++ pkg/routes/routes.go | 9 ++++ 4 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 pkg/modules/background/upload/upload.go diff --git a/pkg/config/config.go b/pkg/config/config.go index 1c0dc8d2a..38cd8fe88 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -115,6 +115,7 @@ const ( AvatarGravaterExpiration Key = `avatar.gravatarexpiration` BackgroundsEnabled Key = `backgrounds.enabled` + BackgroundsUploadEnabled Key = `backgrounds.providers.upload.enabled` BackgroundsUnsplashEnabled Key = `backgrounds.providers.unsplash.enabled` BackgroundsUnsplashAccessToken Key = `backgrounds.providers.unsplash.accesstoken` BackgroundsUnsplashApplicationID Key = `backgrounds.providers.unsplash.applicationid` @@ -252,6 +253,7 @@ func InitDefaultConfig() { AvatarGravaterExpiration.setDefault(3600) // List Backgrounds BackgroundsEnabled.setDefault(false) + BackgroundsUploadEnabled.setDefault(false) BackgroundsUnsplashEnabled.setDefault(false) } diff --git a/pkg/modules/background/handler/background.go b/pkg/modules/background/handler/background.go index 58a094cc7..b6ce576fe 100644 --- a/pkg/modules/background/handler/background.go +++ b/pkg/modules/background/handler/background.go @@ -23,6 +23,7 @@ import ( "code.vikunja.io/api/pkg/modules/background" "code.vikunja.io/api/pkg/modules/background/unsplash" v1 "code.vikunja.io/api/pkg/routes/api/v1" + "code.vikunja.io/web" "code.vikunja.io/web/handler" "github.com/labstack/echo/v4" "net/http" @@ -62,35 +63,42 @@ func (bp *BackgroundProvider) SearchBackgrounds(c echo.Context) error { return c.JSON(http.StatusOK, result) } -// SetBackground sets an Image as list background -func (bp *BackgroundProvider) SetBackground(c echo.Context) error { - auth, err := v1.GetAuthFromClaims(c) +// This function does all kinds of preparations for setting and uploading a background +func (bp *BackgroundProvider) setBackgroundPreparations(c echo.Context) (list *models.List, auth web.Auth, err error) { + auth, err = v1.GetAuthFromClaims(c) if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Invalid auth token: "+err.Error()) + return nil, nil, echo.NewHTTPError(http.StatusBadRequest, "Invalid auth token: "+err.Error()) } - p := bp.Provider() - listID, err := strconv.ParseInt(c.Param("list"), 10, 64) if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Invalid list ID: "+err.Error()) + return nil, nil, echo.NewHTTPError(http.StatusBadRequest, "Invalid list ID: "+err.Error()) } // Check if the user has the right to change the list background - list := &models.List{ID: listID} + list = &models.List{ID: listID} can, err := list.CanUpdate(auth) if err != nil { - return handler.HandleHTTPError(err, c) + return } if !can { log.Infof("Tried to update list background of list %d while not having the rights for it (User: %v)", listID, auth) - return echo.NewHTTPError(http.StatusForbidden) + return list, auth, models.ErrGenericForbidden{} } // Load the list - if err := list.GetSimpleByID(); err != nil { + err = list.GetSimpleByID() + return +} + +// SetBackground sets an Image as list background +func (bp *BackgroundProvider) SetBackground(c echo.Context) error { + list, auth, err := bp.setBackgroundPreparations(c) + if err != nil { return handler.HandleHTTPError(err, c) } + p := bp.Provider() + image := &background.Image{} err = c.Bind(image) if err != nil { @@ -104,6 +112,26 @@ func (bp *BackgroundProvider) SetBackground(c echo.Context) error { return c.JSON(http.StatusOK, list) } +// UploadBackground uploads a background and passes the id of the uploaded file as an Image to the Set function of the BackgroundProvider. +func (bp *BackgroundProvider) UploadBackground(c echo.Context) error { + list, auth, err := bp.setBackgroundPreparations(c) + if err != nil { + return handler.HandleHTTPError(err, c) + } + + p := bp.Provider() + + // Get + upload the image + + image := &background.Image{ID: "1"} + + err = p.Set(image, list, auth) + if err != nil { + return handler.HandleHTTPError(err, c) + } + return c.JSON(http.StatusOK, list) +} + // GetListBackground serves a previously set background from a list // It has no knowledge of the provider that was responsible for setting the background. // @Summary Get the list background diff --git a/pkg/modules/background/upload/upload.go b/pkg/modules/background/upload/upload.go new file mode 100644 index 000000000..60b555b67 --- /dev/null +++ b/pkg/modules/background/upload/upload.go @@ -0,0 +1,35 @@ +// 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 upload + +import ( + "code.vikunja.io/api/pkg/models" + "code.vikunja.io/api/pkg/modules/background" + "code.vikunja.io/web" +) + +type Provider struct { +} + +// Search is only used to implement the interface +func (p *Provider) Search(search string, page int64) (result []*background.Image, err error) { + return +} + +func (p *Provider) Set(image *background.Image, list *models.List, auth web.Auth) (err error) { + +} diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 23a4a4077..73c3cd028 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -50,6 +50,7 @@ import ( "code.vikunja.io/api/pkg/modules/background" backgroundHandler "code.vikunja.io/api/pkg/modules/background/handler" "code.vikunja.io/api/pkg/modules/background/unsplash" + "code.vikunja.io/api/pkg/modules/background/upload" "code.vikunja.io/api/pkg/modules/migration" migrationHandler "code.vikunja.io/api/pkg/modules/migration/handler" "code.vikunja.io/api/pkg/modules/migration/todoist" @@ -454,6 +455,14 @@ func registerAPIRoutes(a *echo.Group) { // List Backgrounds if config.BackgroundsEnabled.GetBool() { a.GET("/lists/:list/background", backgroundHandler.GetListBackground) + if config.BackgroundsUploadEnabled.GetBool() { + uploadBackgroundProvider := &backgroundHandler.BackgroundProvider{ + Provider: func() background.Provider { + return &upload.Provider{} + }, + } + a.POST("/lists/:list/backgrounds/upload", uploadBackgroundProvider.SetBackground) + } if config.BackgroundsUnsplashEnabled.GetBool() { unsplashBackgroundProvider := &backgroundHandler.BackgroundProvider{ Provider: func() background.Provider { -- 2.40.1 From aba5bb6cf773e99813f5cd4281d60edf5e52dc24 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 18:14:50 +0200 Subject: [PATCH 02/10] Save uploaded backgrounds as file --- pkg/modules/background/handler/background.go | 16 +++++++++++++++- pkg/routes/routes.go | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pkg/modules/background/handler/background.go b/pkg/modules/background/handler/background.go index b6ce576fe..435f43d17 100644 --- a/pkg/modules/background/handler/background.go +++ b/pkg/modules/background/handler/background.go @@ -122,8 +122,22 @@ func (bp *BackgroundProvider) UploadBackground(c echo.Context) error { p := bp.Provider() // Get + upload the image + file, err := c.FormFile("background") + if err != nil { + return err + } + src, err := file.Open() + if err != nil { + return err + } + defer src.Close() - image := &background.Image{ID: "1"} + f, err := files.Create(src, file.Filename, uint64(file.Size), auth) + if err != nil { + return handler.HandleHTTPError(err, c) + } + + image := &background.Image{ID: strconv.FormatInt(f.ID, 10)} err = p.Set(image, list, auth) if err != nil { diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 73c3cd028..91856f44b 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -461,7 +461,7 @@ func registerAPIRoutes(a *echo.Group) { return &upload.Provider{} }, } - a.POST("/lists/:list/backgrounds/upload", uploadBackgroundProvider.SetBackground) + a.POST("/lists/:list/backgrounds/upload", uploadBackgroundProvider.UploadBackground) } if config.BackgroundsUnsplashEnabled.GetBool() { unsplashBackgroundProvider := &backgroundHandler.BackgroundProvider{ -- 2.40.1 From db237883a84646255675601ebe2e095831b2d849 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 18:17:37 +0200 Subject: [PATCH 03/10] Add docs --- pkg/modules/background/unsplash/unsplash.go | 2 +- pkg/modules/background/upload/upload.go | 14 ++++++++++++++ pkg/routes/routes.go | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pkg/modules/background/unsplash/unsplash.go b/pkg/modules/background/unsplash/unsplash.go index 6310a1e95..a76d544a5 100644 --- a/pkg/modules/background/unsplash/unsplash.go +++ b/pkg/modules/background/unsplash/unsplash.go @@ -220,7 +220,7 @@ func (p *Provider) Search(search string, page int64) (result []*background.Image // Set sets an unsplash photo as list background // @Summary Set an unsplash photo as list background -// @Description Sets a photo from unsplash as list background.1 +// @Description Sets a photo from unsplash as list background. // @tags list // @Accept json // @Produce json diff --git a/pkg/modules/background/upload/upload.go b/pkg/modules/background/upload/upload.go index 60b555b67..8fc25bd8f 100644 --- a/pkg/modules/background/upload/upload.go +++ b/pkg/modules/background/upload/upload.go @@ -30,6 +30,20 @@ func (p *Provider) Search(search string, page int64) (result []*background.Image return } +// Set handles setting a background through a file upload +// @Summary Upload a list background +// @Description Upload a list background. +// @tags list +// @Accept mpfd +// @Produce json +// @Param id path int true "List ID" +// @Param background formData string true "The file as single file." +// @Security JWTKeyAuth +// @Success 200 {object} models.Message "The background was set successfully." +// @Failure 403 {object} models.Message "No access to the list." +// @Failure 404 {object} models.Message "The list does not exist." +// @Failure 500 {object} models.Message "Internal error" +// @Router /lists/{id}/backgrounds/upload [put] func (p *Provider) Set(image *background.Image, list *models.List, auth web.Auth) (err error) { } diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 91856f44b..765b7d9ca 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -461,7 +461,7 @@ func registerAPIRoutes(a *echo.Group) { return &upload.Provider{} }, } - a.POST("/lists/:list/backgrounds/upload", uploadBackgroundProvider.UploadBackground) + a.PUT("/lists/:list/backgrounds/upload", uploadBackgroundProvider.UploadBackground) } if config.BackgroundsUnsplashEnabled.GetBool() { unsplashBackgroundProvider := &backgroundHandler.BackgroundProvider{ -- 2.40.1 From ad8ff0d8719cf34a366e74f71ef28e1ee848856a Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 18:19:59 +0200 Subject: [PATCH 04/10] Add file upload --- pkg/modules/background/upload/upload.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pkg/modules/background/upload/upload.go b/pkg/modules/background/upload/upload.go index 8fc25bd8f..aa77f5ccd 100644 --- a/pkg/modules/background/upload/upload.go +++ b/pkg/modules/background/upload/upload.go @@ -17,9 +17,11 @@ package upload import ( + "code.vikunja.io/api/pkg/files" "code.vikunja.io/api/pkg/models" "code.vikunja.io/api/pkg/modules/background" "code.vikunja.io/web" + "strconv" ) type Provider struct { @@ -45,5 +47,19 @@ func (p *Provider) Search(search string, page int64) (result []*background.Image // @Failure 500 {object} models.Message "Internal error" // @Router /lists/{id}/backgrounds/upload [put] func (p *Provider) Set(image *background.Image, list *models.List, auth web.Auth) (err error) { + // Remove the old background if one exists + if list.BackgroundFileID != 0 { + file := files.File{ID: list.BackgroundFileID} + if err := file.Delete(); err != nil { + return err + } + } + file := &files.File{} + file.ID, err = strconv.ParseInt(image.ID, 10, 64) + if err != nil { + return + } + + return models.SetListBackground(list.ID, file) } -- 2.40.1 From 5163cfa868810b95f9c81d7b7d86147620d0a1ea Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 18:35:49 +0200 Subject: [PATCH 05/10] Return list background type if it was uploaded --- pkg/models/list.go | 14 +++++++++++++- pkg/modules/background/upload/upload.go | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/models/list.go b/pkg/models/list.go index f54bd38b6..7195b8e45 100644 --- a/pkg/models/list.go +++ b/pkg/models/list.go @@ -66,6 +66,14 @@ type List struct { web.Rights `xorm:"-" json:"-"` } +// ListBackgroundType holds a list background type +type ListBackgroundType struct { + Type string +} + +// ListBackgroundUpload represents the list upload background type +const ListBackgroundUpload string = "upload" + // GetListsByNamespaceID gets all lists in a namespace func GetListsByNamespaceID(nID int64, doer *user.User) (lists []*List, err error) { if nID == -1 { @@ -175,11 +183,15 @@ func (l *List) ReadOne() (err error) { // Get any background information if there is one set if l.BackgroundFileID != 0 { - // Currently unsplash only + // Unsplash image l.BackgroundInformation, err = GetUnsplashPhotoByFileID(l.BackgroundFileID) if err != nil && !files.IsErrFileIsNotUnsplashFile(err) { return } + + if err != nil && files.IsErrFileIsNotUnsplashFile(err) { + l.BackgroundInformation = &ListBackgroundType{Type: ListBackgroundUpload} + } } return nil diff --git a/pkg/modules/background/upload/upload.go b/pkg/modules/background/upload/upload.go index aa77f5ccd..39871e187 100644 --- a/pkg/modules/background/upload/upload.go +++ b/pkg/modules/background/upload/upload.go @@ -61,5 +61,7 @@ func (p *Provider) Set(image *background.Image, list *models.List, auth web.Auth return } + list.BackgroundInformation = &models.ListBackgroundType{Type: models.ListBackgroundUpload} + return models.SetListBackground(list.ID, file) } -- 2.40.1 From 347dd564f143fefd7d71e60549032cb7c1a4784c Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 18:37:05 +0200 Subject: [PATCH 06/10] Fix lint --- pkg/modules/background/upload/upload.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/modules/background/upload/upload.go b/pkg/modules/background/upload/upload.go index 39871e187..aaf233782 100644 --- a/pkg/modules/background/upload/upload.go +++ b/pkg/modules/background/upload/upload.go @@ -24,6 +24,7 @@ import ( "strconv" ) +// Provider represents an upload provider type Provider struct { } -- 2.40.1 From 7d5fbdb30891bdea56ce5f9e63f50b28355bda52 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 18:38:29 +0200 Subject: [PATCH 07/10] Add config docs --- config.yml.sample | 3 +++ docs/content/doc/setup/config.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/config.yml.sample b/config.yml.sample index b5e80b3a8..eebd69ef9 100644 --- a/config.yml.sample +++ b/config.yml.sample @@ -185,6 +185,9 @@ backgrounds: # Whether to enable backgrounds for lists at all. enabled: false providers: + upload: + # Whethere to enable uploaded list backgrounds + enabled: false unsplash: # Whether to enable setting backgrounds from unsplash as list backgrounds enabled: false diff --git a/docs/content/doc/setup/config.md b/docs/content/doc/setup/config.md index 2eb7bcacd..2bf086e91 100644 --- a/docs/content/doc/setup/config.md +++ b/docs/content/doc/setup/config.md @@ -228,6 +228,9 @@ backgrounds: # Whether to enable backgrounds for lists at all. enabled: false providers: + upload: + # Whethere to enable uploaded list backgrounds + enabled: false unsplash: # Whether to enable setting backgrounds from unsplash as list backgrounds enabled: false -- 2.40.1 From 6d648f623edf1d5ea7ca75cbc37d0c603df38c61 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 18:42:35 +0200 Subject: [PATCH 08/10] Add upload background setting to info endpoint --- pkg/routes/api/v1/info.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/routes/api/v1/info.go b/pkg/routes/api/v1/info.go index f9034f8e7..503f28002 100644 --- a/pkg/routes/api/v1/info.go +++ b/pkg/routes/api/v1/info.go @@ -68,6 +68,9 @@ func Info(c echo.Context) error { } if config.BackgroundsEnabled.GetBool() { + if config.BackgroundsUploadEnabled.GetBool() { + info.EnabledBackgroundProviders = append(info.EnabledBackgroundProviders, "upload") + } if config.BackgroundsUnsplashEnabled.GetBool() { info.EnabledBackgroundProviders = append(info.EnabledBackgroundProviders, "unsplash") } -- 2.40.1 From 72c746f3bb334a34bb364d3cc020950b7b8d58c8 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 19:00:04 +0200 Subject: [PATCH 09/10] Fix error 500 if the uploaded background was not an unsplash one --- pkg/modules/background/unsplash/unsplash.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/modules/background/unsplash/unsplash.go b/pkg/modules/background/unsplash/unsplash.go index a76d544a5..e6c45c050 100644 --- a/pkg/modules/background/unsplash/unsplash.go +++ b/pkg/modules/background/unsplash/unsplash.go @@ -308,6 +308,9 @@ func Pingback(f *files.File) { // Check if the file is actually downloaded from unsplash unsplashPhoto, err := models.GetUnsplashPhotoByFileID(f.ID) if err != nil { + if files.IsErrFileIsNotUnsplashFile(err) { + return + } log.Errorf("Unsplash Pingback: %s", err.Error()) } -- 2.40.1 From cb2fa00860b1fc41e08ef7b3fd7e1ae844c7d66b Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2020 19:18:00 +0200 Subject: [PATCH 10/10] Add filesize check when uploading a new file --- pkg/modules/background/handler/background.go | 4 ++++ pkg/modules/background/upload/upload.go | 1 + 2 files changed, 5 insertions(+) diff --git a/pkg/modules/background/handler/background.go b/pkg/modules/background/handler/background.go index 435f43d17..0b5430c92 100644 --- a/pkg/modules/background/handler/background.go +++ b/pkg/modules/background/handler/background.go @@ -134,6 +134,10 @@ func (bp *BackgroundProvider) UploadBackground(c echo.Context) error { f, err := files.Create(src, file.Filename, uint64(file.Size), auth) if err != nil { + if files.IsErrFileIsTooLarge(err) { + return echo.ErrBadRequest + } + return handler.HandleHTTPError(err, c) } diff --git a/pkg/modules/background/upload/upload.go b/pkg/modules/background/upload/upload.go index aaf233782..d9b85b096 100644 --- a/pkg/modules/background/upload/upload.go +++ b/pkg/modules/background/upload/upload.go @@ -44,6 +44,7 @@ func (p *Provider) Search(search string, page int64) (result []*background.Image // @Security JWTKeyAuth // @Success 200 {object} models.Message "The background was set successfully." // @Failure 403 {object} models.Message "No access to the list." +// @Failure 403 {object} models.Message "File too large." // @Failure 404 {object} models.Message "The list does not exist." // @Failure 500 {object} models.Message "Internal error" // @Router /lists/{id}/backgrounds/upload [put] -- 2.40.1