diff --git a/docs/content/doc/usage/errors.md b/docs/content/doc/usage/errors.md
index 54d3f152f..f5325ddd7 100644
--- a/docs/content/doc/usage/errors.md
+++ b/docs/content/doc/usage/errors.md
@@ -16,152 +16,146 @@ This document describes the different errors Vikunja can return.
## Generic
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|--------------------------|
-| 0001 | 403 | Generic forbidden error. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 0001 | 403 | Generic forbidden error. |
## User
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|------------------------------------------------------------|
-| 1001 | 400 | A user with this username already exists. |
-| 1002 | 400 | A user with this email address already exists. |
-| 1004 | 400 | No username and password specified. |
-| 1005 | 404 | The user does not exist. |
-| 1006 | 400 | Could not get the user id. |
-| 1008 | 412 | No password reset token provided. |
-| 1009 | 412 | Invalid password reset token. |
-| 1010 | 412 | Invalid email confirm token. |
-| 1011 | 412 | Wrong username or password. |
-| 1012 | 412 | Email address of the user not confirmed. |
-| 1013 | 412 | New password is empty. |
-| 1014 | 412 | Old password is empty. |
-| 1015 | 412 | Totp is already enabled for this user. |
-| 1016 | 412 | Totp is not enabled for this user. |
-| 1017 | 412 | The provided Totp passcode is invalid. |
-| 1018 | 412 | The provided user avatar provider type setting is invalid. |
-| 1019 | 412 | No openid email address was provided. |
-| 1020 | 412 | This user account is disabled. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 1001 | 400 | A user with this username already exists. |
+| 1002 | 400 | A user with this email address already exists. |
+| 1004 | 400 | No username and password specified. |
+| 1005 | 404 | The user does not exist. |
+| 1006 | 400 | Could not get the user id. |
+| 1008 | 412 | No password reset token provided. |
+| 1009 | 412 | Invalid password reset token. |
+| 1010 | 412 | Invalid email confirm token. |
+| 1011 | 412 | Wrong username or password. |
+| 1012 | 412 | Email address of the user not confirmed. |
+| 1013 | 412 | New password is empty. |
+| 1014 | 412 | Old password is empty. |
+| 1015 | 412 | Totp is already enabled for this user. |
+| 1016 | 412 | Totp is not enabled for this user. |
+| 1017 | 412 | The provided Totp passcode is invalid. |
+| 1018 | 412 | The provided user avatar provider type setting is invalid. |
+| 1019 | 412 | No openid email address was provided. |
+| 1020 | 412 | This user account is disabled. |
## Validation
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|---------------------------------------------------------------------------------------------------------|
-| 2001 | 400 | ID cannot be empty or 0. |
-| 2002 | 400 | Some of the request data was invalid. The response contains an aditional array with all invalid fields. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 2001 | 400 | ID cannot be empty or 0. |
+| 2002 | 400 | Some of the request data was invalid. The response contains an aditional array with all invalid fields. |
## List
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|-------------------------------------------------------------------------------------------------------------------------------|
-| 3001 | 404 | The list does not exist. |
-| 3004 | 403 | The user needs to have read permissions on that list to perform that action. |
-| 3005 | 400 | The list title cannot be empty. |
-| 3006 | 404 | The list share does not exist. |
-| 3007 | 400 | A list with this identifier already exists. |
-| 3008 | 412 | The list is archived and can therefore only be accessed read only. This is also true for all tasks associated with this list. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 3001 | 404 | The list does not exist. |
+| 3004 | 403 | The user needs to have read permissions on that list to perform that action. |
+| 3005 | 400 | The list title cannot be empty. |
+| 3006 | 404 | The list share does not exist. |
+| 3007 | 400 | A list with this identifier already exists. |
+| 3008 | 412 | The list is archived and can therefore only be accessed read only. This is also true for all tasks associated with this list. |
## Task
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|----------------------------------------------------------------------------|
-| 4001 | 400 | The list task text cannot be empty. |
-| 4002 | 404 | The list task does not exist. |
-| 4003 | 403 | All bulk editing tasks must belong to the same list. |
-| 4004 | 403 | Need at least one task when bulk editing tasks. |
-| 4005 | 403 | The user does not have the right to see the task. |
-| 4006 | 403 | The user tried to set a parent task as the task itself. |
-| 4007 | 400 | The user tried to create a task relation with an invalid kind of relation. |
-| 4008 | 409 | The user tried to create a task relation which already exists. |
-| 4009 | 404 | The task relation does not exist. |
-| 4010 | 400 | Cannot relate a task with itself. |
-| 4011 | 404 | The task attachment does not exist. |
-| 4012 | 400 | The task attachment is too large. |
-| 4013 | 400 | The task sort param is invalid. |
-| 4014 | 400 | The task sort order is invalid. |
-| 4015 | 404 | The task comment does not exist. |
-| 4016 | 403 | Invalid task field. |
-| 4017 | 403 | Invalid task filter comparator. |
-| 4018 | 403 | Invalid task filter concatinator. |
-| 4019 | 403 | Invalid task filter value. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 4001 | 400 | The list task text cannot be empty. |
+| 4002 | 404 | The list task does not exist. |
+| 4003 | 403 | All bulk editing tasks must belong to the same list. |
+| 4004 | 403 | Need at least one task when bulk editing tasks. |
+| 4005 | 403 | The user does not have the right to see the task. |
+| 4006 | 403 | The user tried to set a parent task as the task itself. |
+| 4007 | 400 | The user tried to create a task relation with an invalid kind of relation. |
+| 4008 | 409 | The user tried to create a task relation which already exists. |
+| 4009 | 404 | The task relation does not exist. |
+| 4010 | 400 | Cannot relate a task with itself. |
+| 4011 | 404 | The task attachment does not exist. |
+| 4012 | 400 | The task attachment is too large. |
+| 4013 | 400 | The task sort param is invalid. |
+| 4014 | 400 | The task sort order is invalid. |
+| 4015 | 404 | The task comment does not exist. |
+| 4016 | 403 | Invalid task field. |
+| 4017 | 403 | Invalid task filter comparator. |
+| 4018 | 403 | Invalid task filter concatinator. |
+| 4019 | 403 | Invalid task filter value. |
## Namespace
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|-------------------------------------------------------------------------|
-| 5001 | 404 | The namspace does not exist. |
-| 5003 | 403 | The user does not have access to the specified namespace. |
-| 5006 | 400 | The namespace name cannot be empty. |
-| 5009 | 403 | The user needs to have namespace read access to perform that action. |
-| 5010 | 403 | This team does not have access to that namespace. |
-| 5011 | 409 | This user has already access to that namespace. |
-| 5012 | 412 | The namespace is archived and can therefore only be accessed read only. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 5001 | 404 | The namspace does not exist. |
+| 5003 | 403 | The user does not have access to the specified namespace. |
+| 5006 | 400 | The namespace name cannot be empty. |
+| 5009 | 403 | The user needs to have namespace read access to perform that action. |
+| 5010 | 403 | This team does not have access to that namespace. |
+| 5011 | 409 | This user has already access to that namespace. |
+| 5012 | 412 | The namespace is archived and can therefore only be accessed read only. |
## Team
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|-------------------------------------------------------------------|
-| 6001 | 400 | The team name cannot be emtpy. |
-| 6002 | 404 | The team does not exist. |
-| 6004 | 409 | The team already has access to that namespace or list. |
-| 6005 | 409 | The user is already a member of that team. |
-| 6006 | 400 | Cannot delete the last team member. |
-| 6007 | 403 | The team does not have access to the list to perform that action. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 6001 | 400 | The team name cannot be emtpy. |
+| 6002 | 404 | The team does not exist. |
+| 6004 | 409 | The team already has access to that namespace or list. |
+| 6005 | 409 | The user is already a member of that team. |
+| 6006 | 400 | Cannot delete the last team member. |
+| 6007 | 403 | The team does not have access to the list to perform that action. |
## User List Access
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|---------------------------------------------|
-| 7002 | 409 | The user already has access to that list. |
-| 7003 | 403 | The user does not have access to that list. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 7002 | 409 | The user already has access to that list. |
+| 7003 | 403 | The user does not have access to that list. |
## Label
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|----------------------------------------------|
-| 8001 | 403 | This label already exists on that task. |
-| 8002 | 404 | The label does not exist. |
-| 8003 | 403 | The user does not have access to this label. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 8001 | 403 | This label already exists on that task. |
+| 8002 | 404 | The label does not exist. |
+| 8003 | 403 | The user does not have access to this label. |
## Right
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|-----------------------|
-| 9001 | 403 | The right is invalid. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 9001 | 403 | The right is invalid. |
## Kanban
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|-----------------------------------------------------------------------------------------------|
-| 10001 | 404 | The bucket does not exist. |
-| 10002 | 400 | The bucket does not belong to that list. |
-| 10003 | 412 | You cannot remove the last bucket on a list. |
-| 10004 | 412 | You cannot add the task to this bucket as it already exceeded the limit of tasks it can hold. |
-| 10005 | 412 | There can be only one done bucket per list. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 10001 | 404 | The bucket does not exist. |
+| 10002 | 400 | The bucket does not belong to that list. |
+| 10003 | 412 | You cannot remove the last bucket on a list. |
+| 10004 | 412 | You cannot add the task to this bucket as it already exceeded the limit of tasks it can hold. |
+| 10005 | 412 | There can be only one done bucket per list. |
## Saved Filters
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|--------------------------------------------------|
-| 11001 | 404 | The saved filter does not exist. |
-| 11002 | 412 | Saved filters are not available for link shares. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 11001 | 404 | The saved filter does not exist. |
+| 11002 | 412 | Saved filters are not available for link shares. |
## Subscriptions
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|-------------------------------------------------------------------------|
-| 12001 | 412 | The subscription entity type is invalid. |
-| 12002 | 412 | The user is already subscribed to the entity itself or a parent entity. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 12001 | 412 | The subscription entity type is invalid. |
+| 12002 | 412 | The user is already subscribed to the entity itself or a parent entity. |
## Link Shares
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|--------------------------------------------------------------------------------|
-| 13001 | 412 | This link share requires a password for authentication, but none was provided. |
-| 13002 | 403 | The provided link share password was invalid. |
-
-## Time Ranges
-
-| ErrorCode | HTTP Status Code | Description |
-|-----------|------------------|-------------------------------------|
-| 14001 | 412 | The provided time range is invalid. |
+| ErrorCode | HTTP Status Code | Description |
+|-----------|------------------|-------------|
+| 13001 | 412 | This link share requires a password for authentication, but none was provided. |
+| 13002 | 403 | The provided link share password was invalid. |
diff --git a/pkg/modules/parse-time/errors.go b/pkg/modules/parse-time/errors.go
deleted file mode 100644
index 197648411..000000000
--- a/pkg/modules/parse-time/errors.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Vikunja is a to-do list application to facilitate your life.
-// Copyright 2018-2022 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 Affero General Public Licensee 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 Affero General Public Licensee for more details.
-//
-// You should have received a copy of the GNU Affero General Public Licensee
-// along with this program. If not, see .
-
-package parse_time
-
-import (
- "fmt"
- "net/http"
-
- "code.vikunja.io/web"
-)
-
-// ErrInvalidTimeRange represents a "InvalidTimeRange" kind of error. Used if the provided time range is invalid.
-type ErrInvalidTimeRange struct {
- Range string
-}
-
-// IsErrInvalidTimeRange checks if an error is a ErrInvalidTimeRange.
-func IsErrInvalidTimeRange(err error) bool {
- _, ok := err.(*ErrInvalidTimeRange)
- return ok
-}
-
-func (err *ErrInvalidTimeRange) Error() string {
- return fmt.Sprintf("Time range '%s' is invalid", err.Range)
-}
-
-// ErrCodeInvalidTimeRange holds the unique world-error code of this error
-const ErrCodeInvalidTimeRange = 14001
-
-// HTTPError holds the http error description
-func (err *ErrInvalidTimeRange) HTTPError() web.HTTPError {
- return web.HTTPError{
- HTTPCode: http.StatusPreconditionFailed,
- Code: ErrCodeInvalidTimeRange,
- Message: "The time range is invalid.",
- }
-}
diff --git a/pkg/modules/parse-time/parse.go b/pkg/modules/parse-time/parse.go
deleted file mode 100644
index 2efbd167a..000000000
--- a/pkg/modules/parse-time/parse.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Vikunja is a to-do list application to facilitate your life.
-// Copyright 2018-2022 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 Affero General Public Licensee 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 Affero General Public Licensee for more details.
-//
-// You should have received a copy of the GNU Affero General Public Licensee
-// along with this program. If not, see .
-
-package parse_time
-
-import (
- "strconv"
- "strings"
- "time"
-)
-
-func ParseTimeRange(timeRange string) (from time.Time, to time.Time, err error) {
- timeRange = strings.ReplaceAll(timeRange, " ", "")
-
- var parts []string
- var factor int
- if strings.Index(timeRange, "-") > 0 {
- parts = strings.Split(timeRange, "-")
- factor = -1
- } else {
- parts = strings.Split(timeRange, "+")
- factor = 1
- }
-
- if len(parts) != 2 {
- return from, to, &ErrInvalidTimeRange{Range: timeRange}
- }
-
- // Find the duration that is not "now"
- var dur string
- dur = parts[0]
- if dur == "now" {
- dur = parts[1]
- }
-
- to = time.Now()
-
- var diff time.Duration
- diff, err = parseTimeDuration(dur)
- if err != nil {
- return
- }
-
- from = time.Now().Add(diff * time.Duration(factor))
-
- // Make sure from is always before to
- if to.Unix() < from.Unix() {
- return to, from, nil
- }
-
- return
-}
-
-func parseTimeDuration(timeAmount string) (amount time.Duration, err error) {
- if strings.Index(timeAmount, "d") > -1 {
- var a int
- a, err = strconv.Atoi(strings.ReplaceAll(timeAmount, "d", ""))
- if err != nil {
- return
- }
-
- return time.Duration(a) * 24 * time.Hour, nil
- }
-
- return time.ParseDuration(timeAmount)
-}
diff --git a/pkg/modules/parse-time/parse_test.go b/pkg/modules/parse-time/parse_test.go
deleted file mode 100644
index 9ab3ca8c4..000000000
--- a/pkg/modules/parse-time/parse_test.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Vikunja is a to-do list application to facilitate your life.
-// Copyright 2018-2022 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 Affero General Public Licensee 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 Affero General Public Licensee for more details.
-//
-// You should have received a copy of the GNU Affero General Public Licensee
-// along with this program. If not, see .
-
-package parse_time
-
-import (
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestParseTimeRange(t *testing.T) {
- t.Run("last 7 days", func(t *testing.T) {
- from, to, err := ParseTimeRange("now - 7d")
-
- assert.NoError(t, err)
- assert.Equal(t, time.Now().Add(time.Hour*24*7*-1).Unix(), from.Unix())
- assert.Equal(t, time.Now().Unix(), to.Unix())
- })
- t.Run("last 7 days, but different", func(t *testing.T) {
- from, to, err := ParseTimeRange("7d - now")
-
- assert.NoError(t, err)
- assert.Equal(t, time.Now().Add(time.Hour*24*7*-1).Unix(), from.Unix())
- assert.Equal(t, time.Now().Unix(), to.Unix())
- })
- t.Run("last 24h", func(t *testing.T) {
- from, to, err := ParseTimeRange("24h - now")
-
- assert.NoError(t, err)
- assert.Equal(t, time.Now().Add(time.Hour*24*-1).Unix(), from.Unix())
- assert.Equal(t, time.Now().Unix(), to.Unix())
- })
- t.Run("next 7 days", func(t *testing.T) {
- from, to, err := ParseTimeRange("now + 7d")
-
- assert.NoError(t, err)
- assert.Equal(t, time.Now().Unix(), from.Unix())
- assert.Equal(t, time.Now().Add(time.Hour*24*7).Unix(), to.Unix())
- })
- t.Run("next 24h", func(t *testing.T) {
- from, to, err := ParseTimeRange("now + 24h")
-
- assert.NoError(t, err)
- assert.Equal(t, time.Now().Unix(), from.Unix())
- assert.Equal(t, time.Now().Add(time.Hour*24).Unix(), to.Unix())
- })
- t.Run("range with only now", func(t *testing.T) {
- _, _, err := ParseTimeRange("now")
- assert.Error(t, err)
- assert.True(t, IsErrInvalidTimeRange(err))
- })
- t.Run("range with only one duration part", func(t *testing.T) {
- _, _, err := ParseTimeRange("7d")
- assert.Error(t, err)
- assert.True(t, IsErrInvalidTimeRange(err))
- })
- t.Run("invalid date range", func(t *testing.T) {
- _, _, err := ParseTimeRange("now-7y")
- assert.Error(t, err)
- })
-}