2020-02-07 16:27:45 +00:00
// Vikunja is a to-do list application to facilitate your life.
2023-09-01 06:32:28 +00:00
// Copyright 2018-present Vikunja and contributors. All rights reserved.
2018-11-26 20:17:33 +00:00
//
2019-12-04 19:39:56 +00:00
// This program is free software: you can redistribute it and/or modify
2020-12-23 15:41:52 +00:00
// it under the terms of the GNU Affero General Public Licensee as published by
2019-12-04 19:39:56 +00:00
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2018-11-26 20:17:33 +00:00
//
2019-12-04 19:39:56 +00:00
// 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 15:41:52 +00:00
// GNU Affero General Public Licensee for more details.
2018-11-26 20:17:33 +00:00
//
2020-12-23 15:41:52 +00:00
// You should have received a copy of the GNU Affero General Public Licensee
2019-12-04 19:39:56 +00:00
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2018-11-26 20:17:33 +00:00
2018-11-12 15:46:35 +00:00
// @title Vikunja API
2023-04-03 00:11:49 +00:00
// @description This is the documentation for the [Vikunja](https://vikunja.io) API. Vikunja is a cross-platform To-do-application with a lot of features, such as sharing projects with users or teams. <!-- ReDoc-Inject: <security-definitions> -->
2019-10-23 21:11:40 +00:00
// @description # Pagination
// @description Every endpoint capable of pagination will return two headers:
// @description * `x-pagination-total-pages`: The total number of available pages for this request
// @description * `x-pagination-result-count`: The number of items returned for this request.
2020-08-10 12:11:43 +00:00
// @description # Rights
2022-12-29 15:40:06 +00:00
// @description All endpoints which return a single item (project, task, etc.) - no array - will also return a `x-max-right` header with the max right the user has on this item as an int where `0` is `Read Only`, `1` is `Read & Write` and `2` is `Admin`.
2020-08-10 12:11:43 +00:00
// @description This can be used to show or hide ui elements based on the rights the user has.
2023-05-30 19:37:40 +00:00
// @description # Errors
// @description All errors have an error code and a human-readable error message in addition to the http status code. You should always check for the status code in the response, not only the http status code.
// @description Due to limitations in the swagger library we're using for this document, only one error per http status code is documented here. Make sure to check the [error docs](https://vikunja.io/docs/errors/) in Vikunja's documentation for a full list of available error codes.
2019-01-03 22:22:06 +00:00
// @description # Authorization
2019-10-16 20:52:29 +00:00
// @description **JWT-Auth:** Main authorization method, used for most of the requests. Needs `Authorization: Bearer <jwt-token>`-header to authenticate successfully.
2019-01-03 22:22:06 +00:00
// @description
2023-09-01 13:53:27 +00:00
// @description **API Token:** You can create scoped API tokens for your user and use the token to make authenticated requests in the context of that user. The token must be provided via an `Authorization: Bearer <token>` header, similar to jwt auth. See the documentation for the `api` group to manage token creation and revocation.
// @description
2023-04-03 00:11:49 +00:00
// @description **BasicAuth:** Only used when requesting tasks via CalDAV.
2019-01-03 22:22:06 +00:00
// @description <!-- ReDoc-Inject: <security-definitions> -->
2018-11-12 15:46:35 +00:00
// @BasePath /api/v1
2023-04-02 19:34:06 +00:00
// @license.url https://code.vikunja.io/api/src/branch/main/LICENSE
// @license.name AGPL-3.0-or-later
2019-01-03 22:22:06 +00:00
2023-04-02 19:34:06 +00:00
// @contact.url https://vikunja.io/contact/
2019-01-03 22:22:06 +00:00
// @contact.name General Vikunja contact
// @contact.email hello@vikunja.io
2018-11-12 15:46:35 +00:00
// @securityDefinitions.basic BasicAuth
2019-01-03 22:22:06 +00:00
// @securityDefinitions.apikey JWTKeyAuth
2018-11-12 15:46:35 +00:00
// @in header
// @name Authorization
2018-06-10 09:11:41 +00:00
2018-08-29 13:22:17 +00:00
package routes
2018-06-10 09:11:41 +00:00
import (
2021-08-03 21:43:18 +00:00
"errors"
2022-08-02 12:50:03 +00:00
"net/url"
2020-10-11 20:10:03 +00:00
"strings"
"time"
2019-07-06 20:12:26 +00:00
"code.vikunja.io/api/pkg/config"
2020-12-23 15:32:28 +00:00
"code.vikunja.io/api/pkg/db"
2018-11-30 23:26:56 +00:00
"code.vikunja.io/api/pkg/log"
2018-11-16 23:17:37 +00:00
"code.vikunja.io/api/pkg/models"
2020-11-21 16:38:58 +00:00
"code.vikunja.io/api/pkg/modules/auth"
"code.vikunja.io/api/pkg/modules/auth/openid"
2020-05-26 20:07:55 +00:00
"code.vikunja.io/api/pkg/modules/background"
backgroundHandler "code.vikunja.io/api/pkg/modules/background/handler"
"code.vikunja.io/api/pkg/modules/background/unsplash"
2020-06-11 17:31:37 +00:00
"code.vikunja.io/api/pkg/modules/background/upload"
2020-01-19 16:52:16 +00:00
"code.vikunja.io/api/pkg/modules/migration"
migrationHandler "code.vikunja.io/api/pkg/modules/migration/handler"
2020-12-23 15:32:28 +00:00
microsofttodo "code.vikunja.io/api/pkg/modules/migration/microsoft-todo"
2022-10-09 17:23:23 +00:00
"code.vikunja.io/api/pkg/modules/migration/ticktick"
2020-05-23 20:50:54 +00:00
"code.vikunja.io/api/pkg/modules/migration/todoist"
2020-12-23 15:32:28 +00:00
"code.vikunja.io/api/pkg/modules/migration/trello"
2022-10-09 17:23:23 +00:00
vikunja_file "code.vikunja.io/api/pkg/modules/migration/vikunja-file"
2018-10-31 12:42:38 +00:00
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
2019-05-22 17:48:48 +00:00
"code.vikunja.io/api/pkg/routes/caldav"
2020-06-19 18:47:15 +00:00
"code.vikunja.io/api/pkg/version"
2018-11-30 23:26:56 +00:00
"code.vikunja.io/web"
"code.vikunja.io/web/handler"
2021-08-03 21:43:18 +00:00
2020-06-19 18:47:15 +00:00
"github.com/getsentry/sentry-go"
sentryecho "github.com/getsentry/sentry-go/echo"
2019-05-07 19:42:24 +00:00
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
2019-01-25 11:40:54 +00:00
elog "github.com/labstack/gommon/log"
2022-10-09 17:23:23 +00:00
"github.com/ulule/limiter/v3"
2018-06-10 09:11:41 +00:00
)
// NewEcho registers a new Echo instance
func NewEcho ( ) * echo . Echo {
e := echo . New ( )
2018-11-03 15:05:45 +00:00
e . HideBanner = true
2019-01-25 11:40:54 +00:00
if l , ok := e . Logger . ( * elog . Logger ) ; ok {
2023-10-03 09:28:28 +00:00
if ! config . LogEnabled . GetBool ( ) || config . LogEcho . GetString ( ) == "off" {
2019-01-25 11:40:54 +00:00
l . SetLevel ( elog . OFF )
}
l . EnableColor ( )
l . SetHeader ( log . ErrFmt )
2023-10-03 09:28:28 +00:00
l . SetOutput ( log . GetLogWriter ( config . LogEcho . GetString ( ) , "echo" ) )
2019-01-25 11:40:54 +00:00
}
2018-06-10 09:11:41 +00:00
// Logger
2023-10-03 09:28:28 +00:00
if ! config . LogEnabled . GetBool ( ) || config . LogHTTP . GetString ( ) != "off" {
2019-01-25 11:40:54 +00:00
e . Use ( middleware . LoggerWithConfig ( middleware . LoggerConfig {
Format : log . WebFmt + "\n" ,
2023-10-03 09:28:28 +00:00
Output : log . GetLogWriter ( config . LogHTTP . GetString ( ) , "http" ) ,
2019-01-25 11:40:54 +00:00
} ) )
}
2018-06-10 09:11:41 +00:00
2020-06-19 18:47:15 +00:00
// panic recover
e . Use ( middleware . Recover ( ) )
if config . ServiceSentryDsn . GetString ( ) != "" {
if err := sentry . Init ( sentry . ClientOptions {
Dsn : config . ServiceSentryDsn . GetString ( ) ,
AttachStacktrace : true ,
Release : version . Version ,
} ) ; err != nil {
log . Criticalf ( "Sentry init failed: %s" , err )
}
defer sentry . Flush ( 5 * time . Second )
e . Use ( sentryecho . New ( sentryecho . Options {
Repanic : true ,
} ) )
e . HTTPErrorHandler = func ( err error , c echo . Context ) {
// Only capture errors not already handled by echo
2022-03-27 15:52:33 +00:00
var herr * echo . HTTPError
2023-03-13 09:52:52 +00:00
if errors . As ( err , & herr ) && herr . Code > 403 {
2020-06-19 18:47:15 +00:00
hub := sentryecho . GetHubFromContext ( c )
if hub != nil {
hub . WithScope ( func ( scope * sentry . Scope ) {
scope . SetExtra ( "url" , c . Request ( ) . URL )
hub . CaptureException ( err )
} )
} else {
sentry . CaptureException ( err )
log . Debugf ( "Could not add context for sending error '%s' to sentry" , err . Error ( ) )
}
log . Debugf ( "Error '%s' sent to sentry" , err . Error ( ) )
}
e . DefaultHTTPErrorHandler ( err , c )
}
}
2018-11-16 23:17:37 +00:00
// Validation
e . Validator = & CustomValidator { }
2019-03-24 09:13:40 +00:00
// Handler config
handler . SetAuthProvider ( & web . Auths {
2020-11-21 16:38:58 +00:00
AuthObject : auth . GetAuthFromClaims ,
2019-03-24 09:13:40 +00:00
} )
2019-07-20 18:12:10 +00:00
handler . SetLoggingProvider ( log . GetLogger ( ) )
2019-10-23 21:11:40 +00:00
handler . SetMaxItemsPerPage ( config . ServiceMaxItemsPerPage . GetInt ( ) )
2020-12-23 15:32:28 +00:00
handler . SetSessionFactory ( db . NewSession )
2019-03-24 09:13:40 +00:00
2018-06-10 09:11:41 +00:00
return e
}
// RegisterRoutes registers all routes for the application
func RegisterRoutes ( e * echo . Echo ) {
2019-07-06 20:12:26 +00:00
if config . ServiceEnableCaldav . GetBool ( ) {
2019-05-22 17:48:48 +00:00
// Caldav routes
wkg := e . Group ( "/.well-known" )
2022-03-30 18:25:56 +00:00
wkg . Use ( middleware . BasicAuth ( caldav . BasicAuth ) )
2019-05-22 17:48:48 +00:00
wkg . Any ( "/caldav" , caldav . PrincipalHandler )
wkg . Any ( "/caldav/" , caldav . PrincipalHandler )
c := e . Group ( "/dav" )
registerCalDavRoutes ( c )
}
2021-10-03 18:37:02 +00:00
// healthcheck
e . GET ( "/health" , HealthcheckHandler )
2022-05-23 20:49:28 +00:00
// static files
if static := config . ServiceStaticpath . GetString ( ) ; static != "" {
2023-05-30 16:55:47 +00:00
e . Use ( middleware . StaticWithConfig ( middleware . StaticConfig {
Root : static ,
HTML5 : true ,
} ) )
2022-05-23 20:49:28 +00:00
}
2018-09-07 20:49:16 +00:00
// CORS_SHIT
2020-01-26 19:09:54 +00:00
if config . CorsEnable . GetBool ( ) {
e . Use ( middleware . CORSWithConfig ( middleware . CORSConfig {
AllowOrigins : config . CorsOrigins . GetStringSlice ( ) ,
MaxAge : config . CorsMaxAge . GetInt ( ) ,
Skipper : func ( context echo . Context ) bool {
// Since it is not possible to register this middleware just for the api group,
// we just disable it when for caldav requests.
// Caldav requires OPTIONS requests to be answered in a specific manner,
// not doing this would break the caldav implementation
return strings . HasPrefix ( context . Path ( ) , "/dav" )
} ,
} ) )
}
2018-06-10 09:11:41 +00:00
// API Routes
a := e . Group ( "/api/v1" )
2023-08-31 15:02:25 +00:00
e . OnAddRouteHandler = func ( host string , route echo . Route , handler echo . HandlerFunc , middleware [ ] echo . MiddlewareFunc ) {
2023-09-01 06:52:57 +00:00
models . CollectRoutesForAPITokenUsage ( route )
2023-08-31 15:02:25 +00:00
}
2019-05-22 17:48:48 +00:00
registerAPIRoutes ( a )
}
func registerAPIRoutes ( a * echo . Group ) {
2018-06-10 09:11:41 +00:00
2020-01-26 19:53:47 +00:00
// This is the group with no auth
// It is its own group to be able to rate limit this based on different heuristics
n := a . Group ( "" )
setupRateLimit ( n , "ip" )
2022-08-02 12:50:03 +00:00
// Echo does not unescape url path params by default. To make sure values bound as :param in urls are passed
// properly to handlers, we use this middleware to unescape them.
// See https://kolaente.dev/vikunja/api/issues/1224
// See https://github.com/labstack/echo/issues/766
a . Use ( func ( next echo . HandlerFunc ) echo . HandlerFunc {
return func ( c echo . Context ) error {
params := make ( [ ] string , 0 , len ( c . ParamValues ( ) ) )
for _ , param := range c . ParamValues ( ) {
p , err := url . PathUnescape ( param )
if err != nil {
return err
}
params = append ( params , p )
}
c . SetParamValues ( params ... )
return next ( c )
}
} )
2019-01-03 22:22:06 +00:00
// Docs
2020-01-26 19:53:47 +00:00
n . GET ( "/docs.json" , apiv1 . DocsJSON )
n . GET ( "/docs" , apiv1 . RedocUI )
2018-09-17 16:34:46 +00:00
2018-12-12 22:50:35 +00:00
// Prometheus endpoint
2020-01-26 19:53:47 +00:00
setupMetrics ( n )
2018-12-12 22:50:35 +00:00
2021-11-14 19:42:33 +00:00
// Separate route for unauthenticated routes to enable rate limits for it
ur := a . Group ( "" )
rate := limiter . Rate {
Period : 60 * time . Second ,
Limit : 10 ,
}
rateLimiter := createRateLimiter ( rate )
ur . Use ( RateLimit ( rateLimiter , "ip" ) )
2020-11-21 16:38:58 +00:00
if config . AuthLocalEnabled . GetBool ( ) {
// User stuff
2021-11-14 19:42:33 +00:00
ur . POST ( "/login" , apiv1 . Login )
ur . POST ( "/register" , apiv1 . RegisterUser )
ur . POST ( "/user/password/token" , apiv1 . UserRequestResetPasswordToken )
ur . POST ( "/user/password/reset" , apiv1 . UserResetPassword )
ur . POST ( "/user/confirm" , apiv1 . UserConfirmEmail )
2020-11-21 16:38:58 +00:00
}
if config . AuthOpenIDEnabled . GetBool ( ) {
2021-11-14 19:42:33 +00:00
ur . POST ( "/auth/openid/:provider/callback" , openid . HandleCallback )
2020-11-21 16:38:58 +00:00
}
2018-06-10 09:11:41 +00:00
2020-11-28 23:08:30 +00:00
// Testing
if config . ServiceTestingtoken . GetString ( ) != "" {
n . PATCH ( "/test/:table" , apiv1 . HandleTesting )
}
2019-07-15 22:54:38 +00:00
// Info endpoint
2020-01-26 19:53:47 +00:00
n . GET ( "/info" , apiv1 . Info )
2019-07-15 22:54:38 +00:00
2020-03-01 20:30:37 +00:00
// Avatar endpoint
2020-12-18 22:11:11 +00:00
n . GET ( "/avatar/:username" , apiv1 . GetAvatar )
2020-03-01 20:30:37 +00:00
2019-08-31 20:56:41 +00:00
// Link share auth
if config . ServiceEnableLinkSharing . GetBool ( ) {
2021-11-14 19:42:33 +00:00
ur . POST ( "/shares/:share/auth" , apiv1 . AuthenticateLinkShare )
2019-08-31 20:56:41 +00:00
}
2022-12-28 10:32:12 +00:00
// ===== Routes with Authentication =====
2023-09-01 08:19:55 +00:00
a . Use ( SetupTokenMiddleware ( ) )
2018-11-30 23:26:56 +00:00
2019-07-21 21:27:30 +00:00
// Rate limit
2020-01-26 19:53:47 +00:00
setupRateLimit ( a , config . RateLimitKind . GetString ( ) )
2019-07-21 21:27:30 +00:00
2018-12-12 22:50:35 +00:00
// Middleware to collect metrics
2019-07-21 21:44:12 +00:00
setupMetricsMiddleware ( a )
2018-12-12 22:50:35 +00:00
2018-06-10 09:11:41 +00:00
a . POST ( "/tokenTest" , apiv1 . CheckToken )
2023-09-01 06:52:57 +00:00
a . GET ( "/routes" , models . GetAvailableAPIRoutesForToken )
2018-06-10 12:14:10 +00:00
2018-09-20 17:42:01 +00:00
// User stuff
2020-04-17 19:25:35 +00:00
u := a . Group ( "/user" )
u . GET ( "" , apiv1 . UserShow )
u . POST ( "/password" , apiv1 . UserChangePassword )
2022-12-29 17:53:52 +00:00
u . GET ( "s" , apiv1 . UserList )
2020-04-17 19:25:35 +00:00
u . POST ( "/token" , apiv1 . RenewToken )
u . POST ( "/settings/email" , apiv1 . UpdateUserEmail )
2020-08-02 17:16:58 +00:00
u . GET ( "/settings/avatar" , apiv1 . GetUserAvatarProvider )
u . POST ( "/settings/avatar" , apiv1 . ChangeUserAvatarProvider )
u . PUT ( "/settings/avatar/upload" , apiv1 . UploadAvatar )
2020-12-18 23:21:17 +00:00
u . POST ( "/settings/general" , apiv1 . UpdateGeneralUserSettings )
2021-09-04 19:26:31 +00:00
u . POST ( "/export/request" , apiv1 . RequestUserDataExport )
u . POST ( "/export/download" , apiv1 . DownloadUserDataExport )
2022-01-16 11:05:56 +00:00
u . GET ( "/timezones" , apiv1 . GetAvailableTimezones )
2022-03-30 18:25:56 +00:00
u . PUT ( "/settings/token/caldav" , apiv1 . GenerateCaldavToken )
u . GET ( "/settings/token/caldav" , apiv1 . GetCaldavTokens )
u . DELETE ( "/settings/token/caldav/:id" , apiv1 . DeleteCaldavToken )
2020-05-29 15:15:59 +00:00
if config . ServiceEnableTotp . GetBool ( ) {
u . GET ( "/settings/totp" , apiv1 . UserTOTP )
u . POST ( "/settings/totp/enroll" , apiv1 . UserTOTPEnroll )
u . POST ( "/settings/totp/enable" , apiv1 . UserTOTPEnable )
u . POST ( "/settings/totp/disable" , apiv1 . UserTOTPDisable )
u . GET ( "/settings/totp/qrcode" , apiv1 . UserTOTPQrCode )
}
2018-09-20 17:42:01 +00:00
2021-08-11 19:08:10 +00:00
// User deletion
if config . ServiceEnableUserDeletion . GetBool ( ) {
u . POST ( "/deletion/request" , apiv1 . UserRequestDeletion )
u . POST ( "/deletion/confirm" , apiv1 . UserConfirmDeletion )
u . POST ( "/deletion/cancel" , apiv1 . UserCancelDeletion )
}
2022-11-13 16:07:01 +00:00
projectHandler := & handler . WebHandler {
2018-11-30 23:26:56 +00:00
EmptyStruct : func ( ) handler . CObject {
2022-11-13 16:07:01 +00:00
return & models . Project { }
2018-10-11 15:53:59 +00:00
} ,
2018-07-07 12:19:34 +00:00
}
2022-11-13 16:07:01 +00:00
a . GET ( "/projects" , projectHandler . ReadAllWeb )
a . GET ( "/projects/:project" , projectHandler . ReadOneWeb )
a . POST ( "/projects/:project" , projectHandler . UpdateWeb )
a . DELETE ( "/projects/:project" , projectHandler . DeleteWeb )
2022-11-13 16:07:01 +00:00
a . PUT ( "/projects" , projectHandler . CreateWeb )
2022-11-13 16:43:45 +00:00
a . GET ( "/projects/:project/projectusers" , apiv1 . ListUsersForProject )
2018-06-12 16:07:47 +00:00
2019-08-31 20:56:41 +00:00
if config . ServiceEnableLinkSharing . GetBool ( ) {
2022-11-13 16:07:01 +00:00
projectSharingHandler := & handler . WebHandler {
2019-08-31 20:56:41 +00:00
EmptyStruct : func ( ) handler . CObject {
return & models . LinkSharing { }
} ,
}
2022-11-13 16:07:01 +00:00
a . PUT ( "/projects/:project/shares" , projectSharingHandler . CreateWeb )
a . GET ( "/projects/:project/shares" , projectSharingHandler . ReadAllWeb )
a . GET ( "/projects/:project/shares/:share" , projectSharingHandler . ReadOneWeb )
a . DELETE ( "/projects/:project/shares/:share" , projectSharingHandler . DeleteWeb )
2019-08-31 20:56:41 +00:00
}
2019-12-01 13:38:11 +00:00
taskCollectionHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . TaskCollection { }
} ,
}
2022-11-13 16:07:01 +00:00
a . GET ( "/projects/:project/tasks" , taskCollectionHandler . ReadAllWeb )
2019-12-01 13:38:11 +00:00
2020-04-19 07:27:28 +00:00
kanbanBucketHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . Bucket { }
} ,
}
2022-11-13 16:07:01 +00:00
a . GET ( "/projects/:project/buckets" , kanbanBucketHandler . ReadAllWeb )
a . PUT ( "/projects/:project/buckets" , kanbanBucketHandler . CreateWeb )
a . POST ( "/projects/:project/buckets/:bucket" , kanbanBucketHandler . UpdateWeb )
a . DELETE ( "/projects/:project/buckets/:bucket" , kanbanBucketHandler . DeleteWeb )
2020-04-19 07:27:28 +00:00
2022-11-13 16:07:01 +00:00
projectDuplicateHandler := & handler . WebHandler {
2020-06-30 20:53:14 +00:00
EmptyStruct : func ( ) handler . CObject {
2022-11-13 16:07:01 +00:00
return & models . ProjectDuplicate { }
2020-06-30 20:53:14 +00:00
} ,
}
2022-11-13 16:07:01 +00:00
a . PUT ( "/projects/:projectid/duplicate" , projectDuplicateHandler . CreateWeb )
2020-06-30 20:53:14 +00:00
2018-11-30 23:26:56 +00:00
taskHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
2019-08-14 20:19:04 +00:00
return & models . Task { }
2018-10-11 15:53:59 +00:00
} ,
2018-07-11 00:13:53 +00:00
}
2023-09-06 08:33:52 +00:00
a . PUT ( "/projects/:project/tasks" , taskHandler . CreateWeb )
2022-11-13 16:07:01 +00:00
a . GET ( "/tasks/:projecttask" , taskHandler . ReadOneWeb )
2019-12-01 13:38:11 +00:00
a . GET ( "/tasks/all" , taskCollectionHandler . ReadAllWeb )
2022-11-13 16:07:01 +00:00
a . DELETE ( "/tasks/:projecttask" , taskHandler . DeleteWeb )
a . POST ( "/tasks/:projecttask" , taskHandler . UpdateWeb )
2018-07-02 06:40:24 +00:00
2018-12-28 21:49:46 +00:00
bulkTaskHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . BulkTask { }
} ,
}
a . POST ( "/tasks/bulk" , bulkTaskHandler . UpdateWeb )
2019-01-08 19:13:07 +00:00
assigneeTaskHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
2019-08-14 20:19:04 +00:00
return & models . TaskAssginee { }
2019-01-08 19:13:07 +00:00
} ,
}
2022-11-13 16:07:01 +00:00
a . PUT ( "/tasks/:projecttask/assignees" , assigneeTaskHandler . CreateWeb )
a . DELETE ( "/tasks/:projecttask/assignees/:user" , assigneeTaskHandler . DeleteWeb )
a . GET ( "/tasks/:projecttask/assignees" , assigneeTaskHandler . ReadAllWeb )
2019-01-08 19:13:07 +00:00
bulkAssigneeHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . BulkAssignees { }
} ,
}
2022-11-13 16:07:01 +00:00
a . POST ( "/tasks/:projecttask/assignees/bulk" , bulkAssigneeHandler . CreateWeb )
2019-01-08 19:13:07 +00:00
2018-12-31 01:18:41 +00:00
labelTaskHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . LabelTask { }
} ,
}
2022-11-13 16:07:01 +00:00
a . PUT ( "/tasks/:projecttask/labels" , labelTaskHandler . CreateWeb )
a . DELETE ( "/tasks/:projecttask/labels/:label" , labelTaskHandler . DeleteWeb )
a . GET ( "/tasks/:projecttask/labels" , labelTaskHandler . ReadAllWeb )
2018-12-31 01:18:41 +00:00
2019-01-09 23:08:12 +00:00
bulkLabelTaskHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . LabelTaskBulk { }
} ,
}
2022-11-13 16:07:01 +00:00
a . POST ( "/tasks/:projecttask/labels/bulk" , bulkLabelTaskHandler . CreateWeb )
2019-01-09 23:08:12 +00:00
2019-09-25 18:44:41 +00:00
taskRelationHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . TaskRelation { }
} ,
}
a . PUT ( "/tasks/:task/relations" , taskRelationHandler . CreateWeb )
2021-02-18 22:35:20 +00:00
a . DELETE ( "/tasks/:task/relations/:relationKind/:otherTask" , taskRelationHandler . DeleteWeb )
2019-09-25 18:44:41 +00:00
2020-01-26 19:10:31 +00:00
if config . ServiceEnableTaskAttachments . GetBool ( ) {
taskAttachmentHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . TaskAttachment { }
} ,
}
a . GET ( "/tasks/:task/attachments" , taskAttachmentHandler . ReadAllWeb )
a . DELETE ( "/tasks/:task/attachments/:attachment" , taskAttachmentHandler . DeleteWeb )
a . PUT ( "/tasks/:task/attachments" , apiv1 . UploadTaskAttachment )
a . GET ( "/tasks/:task/attachments/:attachment" , apiv1 . GetTaskAttachment )
2019-10-16 20:52:29 +00:00
}
2020-02-19 21:57:56 +00:00
if config . ServiceEnableTaskComments . GetBool ( ) {
taskCommentHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . TaskComment { }
} ,
}
a . GET ( "/tasks/:task/comments" , taskCommentHandler . ReadAllWeb )
a . PUT ( "/tasks/:task/comments" , taskCommentHandler . CreateWeb )
a . DELETE ( "/tasks/:task/comments/:commentid" , taskCommentHandler . DeleteWeb )
a . POST ( "/tasks/:task/comments/:commentid" , taskCommentHandler . UpdateWeb )
a . GET ( "/tasks/:task/comments/:commentid" , taskCommentHandler . ReadOneWeb )
}
2018-12-31 01:18:41 +00:00
labelHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . Label { }
} ,
}
a . GET ( "/labels" , labelHandler . ReadAllWeb )
a . GET ( "/labels/:label" , labelHandler . ReadOneWeb )
a . PUT ( "/labels" , labelHandler . CreateWeb )
a . DELETE ( "/labels/:label" , labelHandler . DeleteWeb )
a . POST ( "/labels/:label" , labelHandler . UpdateWeb )
2022-11-13 16:07:01 +00:00
projectTeamHandler := & handler . WebHandler {
2018-11-30 23:26:56 +00:00
EmptyStruct : func ( ) handler . CObject {
2022-11-13 16:07:01 +00:00
return & models . TeamProject { }
2018-10-11 15:53:59 +00:00
} ,
2018-07-24 15:29:13 +00:00
}
2022-11-13 16:07:01 +00:00
a . GET ( "/projects/:project/teams" , projectTeamHandler . ReadAllWeb )
a . PUT ( "/projects/:project/teams" , projectTeamHandler . CreateWeb )
a . DELETE ( "/projects/:project/teams/:team" , projectTeamHandler . DeleteWeb )
a . POST ( "/projects/:project/teams/:team" , projectTeamHandler . UpdateWeb )
2018-07-24 15:29:13 +00:00
2022-11-13 16:07:01 +00:00
projectUserHandler := & handler . WebHandler {
2018-11-30 23:26:56 +00:00
EmptyStruct : func ( ) handler . CObject {
2022-11-13 16:07:01 +00:00
return & models . ProjectUser { }
2018-10-11 15:53:59 +00:00
} ,
2018-08-30 06:58:09 +00:00
}
2022-11-13 16:07:01 +00:00
a . GET ( "/projects/:project/users" , projectUserHandler . ReadAllWeb )
a . PUT ( "/projects/:project/users" , projectUserHandler . CreateWeb )
a . DELETE ( "/projects/:project/users/:user" , projectUserHandler . DeleteWeb )
a . POST ( "/projects/:project/users/:user" , projectUserHandler . UpdateWeb )
2018-08-30 06:58:09 +00:00
2020-09-26 21:02:17 +00:00
savedFiltersHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . SavedFilter { }
} ,
}
a . GET ( "/filters/:filter" , savedFiltersHandler . ReadOneWeb )
a . PUT ( "/filters" , savedFiltersHandler . CreateWeb )
a . DELETE ( "/filters/:filter" , savedFiltersHandler . DeleteWeb )
a . POST ( "/filters/:filter" , savedFiltersHandler . UpdateWeb )
2018-11-30 23:26:56 +00:00
teamHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
2018-10-11 15:53:59 +00:00
return & models . Team { }
} ,
2018-07-14 15:34:59 +00:00
}
a . GET ( "/teams" , teamHandler . ReadAllWeb )
2018-07-21 13:08:46 +00:00
a . GET ( "/teams/:team" , teamHandler . ReadOneWeb )
2018-07-14 15:34:59 +00:00
a . PUT ( "/teams" , teamHandler . CreateWeb )
2018-07-21 13:08:46 +00:00
a . POST ( "/teams/:team" , teamHandler . UpdateWeb )
a . DELETE ( "/teams/:team" , teamHandler . DeleteWeb )
2018-07-26 07:53:32 +00:00
2018-11-30 23:26:56 +00:00
teamMemberHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
2018-10-11 15:53:59 +00:00
return & models . TeamMember { }
} ,
2018-07-26 07:53:32 +00:00
}
a . PUT ( "/teams/:team/members" , teamMemberHandler . CreateWeb )
a . DELETE ( "/teams/:team/members/:user" , teamMemberHandler . DeleteWeb )
2020-08-05 15:21:17 +00:00
a . POST ( "/teams/:team/members/:user/admin" , teamMemberHandler . UpdateWeb )
2020-01-19 16:52:16 +00:00
2021-02-14 19:18:14 +00:00
// Subscriptions
subscriptionHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . Subscription { }
} ,
}
a . PUT ( "/subscriptions/:entity/:entityID" , subscriptionHandler . CreateWeb )
a . DELETE ( "/subscriptions/:entity/:entityID" , subscriptionHandler . DeleteWeb )
2021-02-21 14:50:34 +00:00
// Notifications
notificationHandler := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . DatabaseNotifications { }
} ,
}
a . GET ( "/notifications" , notificationHandler . ReadAllWeb )
a . POST ( "/notifications/:notificationid" , notificationHandler . UpdateWeb )
2020-01-19 16:52:16 +00:00
// Migrations
m := a . Group ( "/migration" )
2021-09-04 19:26:31 +00:00
registerMigrations ( m )
2020-01-19 16:52:16 +00:00
2022-11-13 16:07:01 +00:00
// Project Backgrounds
2021-09-04 19:26:31 +00:00
if config . BackgroundsEnabled . GetBool ( ) {
2022-11-13 16:07:01 +00:00
a . GET ( "/projects/:project/background" , backgroundHandler . GetProjectBackground )
a . DELETE ( "/projects/:project/background" , backgroundHandler . RemoveProjectBackground )
2021-09-04 19:26:31 +00:00
if config . BackgroundsUploadEnabled . GetBool ( ) {
uploadBackgroundProvider := & backgroundHandler . BackgroundProvider {
Provider : func ( ) background . Provider {
return & upload . Provider { }
} ,
}
2022-11-13 16:07:01 +00:00
a . PUT ( "/projects/:project/backgrounds/upload" , uploadBackgroundProvider . UploadBackground )
2021-09-04 19:26:31 +00:00
}
if config . BackgroundsUnsplashEnabled . GetBool ( ) {
unsplashBackgroundProvider := & backgroundHandler . BackgroundProvider {
Provider : func ( ) background . Provider {
return & unsplash . Provider { }
} ,
}
a . GET ( "/backgrounds/unsplash/search" , unsplashBackgroundProvider . SearchBackgrounds )
2022-11-13 16:07:01 +00:00
a . POST ( "/projects/:project/backgrounds/unsplash" , unsplashBackgroundProvider . SetBackground )
2021-09-04 19:26:31 +00:00
a . GET ( "/backgrounds/unsplash/images/:image/thumb" , unsplash . ProxyUnsplashThumb )
a . GET ( "/backgrounds/unsplash/images/:image" , unsplash . ProxyUnsplashImage )
}
}
2023-08-31 18:37:25 +00:00
// API Tokens
apiTokenProvider := & handler . WebHandler {
EmptyStruct : func ( ) handler . CObject {
return & models . APIToken { }
} ,
}
a . GET ( "/tokens" , apiTokenProvider . ReadAllWeb )
a . PUT ( "/tokens" , apiTokenProvider . CreateWeb )
a . DELETE ( "/tokens/:token" , apiTokenProvider . DeleteWeb )
2021-09-04 19:26:31 +00:00
}
func registerMigrations ( m * echo . Group ) {
2020-05-23 20:50:54 +00:00
// Todoist
if config . MigrationTodoistEnable . GetBool ( ) {
todoistMigrationHandler := & migrationHandler . MigrationWeb {
MigrationStruct : func ( ) migration . Migrator {
return & todoist . Migration { }
} ,
}
todoistMigrationHandler . RegisterRoutes ( m )
}
2020-05-26 20:07:55 +00:00
2020-12-17 13:44:04 +00:00
// Trello
if config . MigrationTrelloEnable . GetBool ( ) {
trelloMigrationHandler := & migrationHandler . MigrationWeb {
MigrationStruct : func ( ) migration . Migrator {
return & trello . Migration { }
} ,
}
trelloMigrationHandler . RegisterRoutes ( m )
}
2020-12-18 11:12:05 +00:00
// Microsoft Todo
if config . MigrationMicrosoftTodoEnable . GetBool ( ) {
microsoftTodoMigrationHandler := & migrationHandler . MigrationWeb {
MigrationStruct : func ( ) migration . Migrator {
return & microsofttodo . Migration { }
} ,
}
microsoftTodoMigrationHandler . RegisterRoutes ( m )
}
2022-10-09 16:56:37 +00:00
// Vikunja File Migrator
2021-09-04 19:26:31 +00:00
vikunjaFileMigrationHandler := & migrationHandler . FileMigratorWeb {
MigrationStruct : func ( ) migration . FileMigrator {
return & vikunja_file . FileMigrator { }
} ,
2020-05-26 20:07:55 +00:00
}
2021-09-04 19:26:31 +00:00
vikunjaFileMigrationHandler . RegisterRoutes ( m )
2022-10-09 16:56:37 +00:00
// TickTick File Migrator
tickTickFileMigrator := migrationHandler . FileMigratorWeb {
MigrationStruct : func ( ) migration . FileMigrator {
return & ticktick . Migrator { }
} ,
}
tickTickFileMigrator . RegisterRoutes ( m )
2018-06-10 09:11:41 +00:00
}
2019-05-22 17:48:48 +00:00
func registerCalDavRoutes ( c * echo . Group ) {
// Basic auth middleware
2022-03-30 18:25:56 +00:00
c . Use ( middleware . BasicAuth ( caldav . BasicAuth ) )
2019-05-22 17:48:48 +00:00
2022-11-13 16:07:01 +00:00
// THIS is the entry point for caldav clients, otherwise projects will show up double
2019-05-22 17:48:48 +00:00
c . Any ( "" , caldav . EntryHandler )
c . Any ( "/" , caldav . EntryHandler )
c . Any ( "/principals/*/" , caldav . PrincipalHandler )
2022-11-13 16:07:01 +00:00
c . Any ( "/projects" , caldav . ProjectHandler )
c . Any ( "/projects/" , caldav . ProjectHandler )
c . Any ( "/projects/:project" , caldav . ProjectHandler )
c . Any ( "/projects/:project/" , caldav . ProjectHandler )
c . Any ( "/projects/:project/:task" , caldav . TaskHandler ) // Mostly used for editing
2019-05-22 17:48:48 +00:00
}