2020-08-02 19:16:58 +02:00
// Vikunja is a to-do list application to facilitate your life.
2021-02-02 20:19:13 +01:00
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
2020-08-02 19:16:58 +02:00
//
// This program is free software: you can redistribute it and/or modify
2020-12-23 16:41:52 +01:00
// it under the terms of the GNU Affero General Public Licensee as published by
2020-08-02 19:16:58 +02:00
// 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
2020-12-23 16:41:52 +01:00
// GNU Affero General Public Licensee for more details.
2020-08-02 19:16:58 +02:00
//
2020-12-23 16:41:52 +01:00
// You should have received a copy of the GNU Affero General Public Licensee
2020-08-02 19:16:58 +02:00
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package v1
import (
2022-06-16 16:20:26 +02:00
"errors"
"fmt"
2020-10-11 22:10:03 +02:00
"net/http"
2022-01-16 12:05:56 +01:00
"github.com/labstack/echo/v4"
"github.com/tkuchiki/go-timezone"
2020-12-23 16:32:28 +01:00
2022-01-16 12:05:56 +01:00
"code.vikunja.io/api/pkg/db"
2020-08-02 19:16:58 +02:00
"code.vikunja.io/api/pkg/models"
user2 "code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
)
// UserAvatarProvider holds the user avatar provider type
type UserAvatarProvider struct {
2021-12-07 22:11:23 +01:00
// The avatar provider. Valid types are `gravatar` (uses the user email), `upload`, `initials`, `marble` (generates a random avatar for each user), `default`.
2020-08-02 19:16:58 +02:00
AvatarProvider string ` json:"avatar_provider" `
}
2020-12-19 00:21:17 +01:00
// UserSettings holds all user settings
type UserSettings struct {
2020-11-21 21:51:55 +01:00
// The new name of the current user.
Name string ` json:"name" `
2020-12-19 00:21:17 +01:00
// If enabled, sends email reminders of tasks to the user.
2021-04-07 18:28:58 +02:00
EmailRemindersEnabled bool ` json:"email_reminders_enabled" `
// If true, this user can be found by their name or parts of it when searching for it.
DiscoverableByName bool ` json:"discoverable_by_name" `
// If true, the user can be found when searching for their exact email.
DiscoverableByEmail bool ` json:"discoverable_by_email" `
2021-04-11 17:08:43 +02:00
// If enabled, the user will get an email for their overdue tasks each morning.
OverdueTasksRemindersEnabled bool ` json:"overdue_tasks_reminders_enabled" `
2022-06-16 16:20:26 +02:00
// The time when the daily summary of overdue tasks will be sent via email.
OverdueTasksRemindersTime string ` json:"overdue_tasks_reminders_time" valid:"time,required" `
2021-06-02 23:20:22 +02:00
// If a task is created without a specified list this value should be used. Applies
// to tasks made directly in API and from clients.
DefaultListID int64 ` json:"default_list_id" `
2021-06-03 18:11:44 +02:00
// The day when the week starts for this user. 0 = sunday, 1 = monday, etc.
2022-06-16 16:20:26 +02:00
WeekStart int ` json:"week_start" valid:"range(0|7)" `
2021-12-12 15:39:47 +01:00
// The user's language
Language string ` json:"language" `
2022-01-16 12:05:56 +01:00
// The user's time zone. Used to send task reminders in the time zone of the user.
Timezone string ` json:"timezone" `
2020-11-21 21:51:55 +01:00
}
2020-08-02 19:16:58 +02:00
// GetUserAvatarProvider returns the currently set user avatar
// @Summary Return user avatar setting
// @Description Returns the current user's avatar setting.
// @tags user
// @Accept json
// @Produce json
// @Security JWTKeyAuth
// @Success 200 {object} UserAvatarProvider
// @Failure 400 {object} web.HTTPError "Something's invalid."
// @Failure 500 {object} models.Message "Internal server error."
// @Router /user/settings/avatar [get]
func GetUserAvatarProvider ( c echo . Context ) error {
u , err := user2 . GetCurrentUser ( c )
if err != nil {
return handler . HandleHTTPError ( err , c )
}
2020-12-23 16:32:28 +01:00
s := db . NewSession ( )
defer s . Close ( )
user , err := user2 . GetUserWithEmail ( s , & user2 . User { ID : u . ID } )
2020-08-02 19:16:58 +02:00
if err != nil {
2020-12-23 16:32:28 +01:00
_ = s . Rollback ( )
return handler . HandleHTTPError ( err , c )
}
if err := s . Commit ( ) ; err != nil {
_ = s . Rollback ( )
2020-08-02 19:16:58 +02:00
return handler . HandleHTTPError ( err , c )
}
uap := & UserAvatarProvider { AvatarProvider : user . AvatarProvider }
return c . JSON ( http . StatusOK , uap )
}
// ChangeUserAvatarProvider changes the user's avatar provider
// @Summary Set the user's avatar
// @Description Changes the user avatar. Valid types are gravatar (uses the user email), upload, initials, default.
// @tags user
// @Accept json
// @Produce json
// @Security JWTKeyAuth
// @Param avatar body UserAvatarProvider true "The user's avatar setting"
2020-11-21 21:51:55 +01:00
// @Success 200 {object} models.Message
2020-08-02 19:16:58 +02:00
// @Failure 400 {object} web.HTTPError "Something's invalid."
// @Failure 500 {object} models.Message "Internal server error."
// @Router /user/settings/avatar [post]
func ChangeUserAvatarProvider ( c echo . Context ) error {
uap := & UserAvatarProvider { }
err := c . Bind ( uap )
if err != nil {
return echo . NewHTTPError ( http . StatusBadRequest , "Bad avatar type provided." )
}
u , err := user2 . GetCurrentUser ( c )
if err != nil {
return handler . HandleHTTPError ( err , c )
}
2020-12-23 16:32:28 +01:00
s := db . NewSession ( )
defer s . Close ( )
user , err := user2 . GetUserWithEmail ( s , & user2 . User { ID : u . ID } )
2020-08-02 19:16:58 +02:00
if err != nil {
2020-12-23 16:32:28 +01:00
_ = s . Rollback ( )
2020-08-02 19:16:58 +02:00
return handler . HandleHTTPError ( err , c )
}
user . AvatarProvider = uap . AvatarProvider
2020-12-23 16:32:28 +01:00
_ , err = user2 . UpdateUser ( s , user )
2020-08-02 19:16:58 +02:00
if err != nil {
2020-12-23 16:32:28 +01:00
_ = s . Rollback ( )
return handler . HandleHTTPError ( err , c )
}
if err := s . Commit ( ) ; err != nil {
_ = s . Rollback ( )
2020-08-02 19:16:58 +02:00
return handler . HandleHTTPError ( err , c )
}
return c . JSON ( http . StatusOK , & models . Message { Message : "Avatar was changed successfully." } )
}
2020-11-21 21:51:55 +01:00
2020-12-19 00:21:17 +01:00
// UpdateGeneralUserSettings is the handler to change general user settings
// @Summary Change general user settings of the current user.
2020-11-21 21:51:55 +01:00
// @tags user
// @Accept json
// @Produce json
// @Security JWTKeyAuth
2020-12-19 00:21:17 +01:00
// @Param avatar body UserSettings true "The updated user settings"
2020-11-21 21:51:55 +01:00
// @Success 200 {object} models.Message
// @Failure 400 {object} web.HTTPError "Something's invalid."
// @Failure 500 {object} models.Message "Internal server error."
2020-12-19 00:21:17 +01:00
// @Router /user/settings/general [post]
func UpdateGeneralUserSettings ( c echo . Context ) error {
us := & UserSettings { }
err := c . Bind ( us )
2020-11-21 21:51:55 +01:00
if err != nil {
2022-06-16 16:20:26 +02:00
var he * echo . HTTPError
if errors . As ( err , & he ) {
return echo . NewHTTPError ( http . StatusBadRequest , fmt . Sprintf ( "Invalid model provided. Error was: %s" , he . Message ) )
}
return echo . NewHTTPError ( http . StatusBadRequest , "Invalid model provided." )
}
err = c . Validate ( us )
if err != nil {
return echo . NewHTTPError ( http . StatusBadRequest , err )
2020-11-21 21:51:55 +01:00
}
u , err := user2 . GetCurrentUser ( c )
if err != nil {
return handler . HandleHTTPError ( err , c )
}
2020-12-23 16:32:28 +01:00
s := db . NewSession ( )
defer s . Close ( )
user , err := user2 . GetUserWithEmail ( s , & user2 . User { ID : u . ID } )
2020-11-21 21:51:55 +01:00
if err != nil {
2020-12-23 16:32:28 +01:00
_ = s . Rollback ( )
2020-11-21 21:51:55 +01:00
return handler . HandleHTTPError ( err , c )
}
2020-12-19 00:21:17 +01:00
user . Name = us . Name
user . EmailRemindersEnabled = us . EmailRemindersEnabled
2021-04-07 18:28:58 +02:00
user . DiscoverableByEmail = us . DiscoverableByEmail
user . DiscoverableByName = us . DiscoverableByName
2021-04-11 17:08:43 +02:00
user . OverdueTasksRemindersEnabled = us . OverdueTasksRemindersEnabled
2021-06-02 23:20:22 +02:00
user . DefaultListID = us . DefaultListID
2021-06-03 18:11:44 +02:00
user . WeekStart = us . WeekStart
2021-12-12 15:39:47 +01:00
user . Language = us . Language
2022-01-16 12:05:56 +01:00
user . Timezone = us . Timezone
2022-06-16 16:20:26 +02:00
user . OverdueTasksRemindersTime = us . OverdueTasksRemindersTime
2020-11-21 21:51:55 +01:00
2020-12-23 16:32:28 +01:00
_ , err = user2 . UpdateUser ( s , user )
2020-11-21 21:51:55 +01:00
if err != nil {
2020-12-23 16:32:28 +01:00
_ = s . Rollback ( )
return handler . HandleHTTPError ( err , c )
}
if err := s . Commit ( ) ; err != nil {
_ = s . Rollback ( )
2020-11-21 21:51:55 +01:00
return handler . HandleHTTPError ( err , c )
}
2020-12-19 00:21:17 +01:00
return c . JSON ( http . StatusOK , & models . Message { Message : "The settings were updated successfully." } )
2020-11-21 21:51:55 +01:00
}
2022-01-16 12:05:56 +01:00
// GetAvailableTimezones
// @Summary Get all available time zones on this vikunja instance
// @Description Because available time zones depend on the system Vikunja is running on, this endpoint returns a list of all valid time zones this particular Vikunja instance can handle. The list of time zones is not sorted, you should sort it on the client.
// @tags user
// @Accept json
// @Produce json
// @Security JWTKeyAuth
// @Success 200 {array} string "All available time zones."
// @Failure 500 {object} models.Message "Internal server error."
// @Router /user/timezones [get]
func GetAvailableTimezones ( c echo . Context ) error {
allTimezones := timezone . New ( ) . Timezones ( )
timezoneMap := make ( map [ string ] bool ) // to filter all duplicates
for _ , s := range allTimezones {
for _ , t := range s {
timezoneMap [ t ] = true
}
}
ts := [ ] string { }
for s := range timezoneMap {
ts = append ( ts , s )
}
return c . JSON ( http . StatusOK , ts )
}