docs: remove docs files
Docs are now included in https://kolaente.dev/vikunja/website
This commit is contained in:
parent
96e8e2354f
commit
7a290116e8
50
.drone.yml
50
.drone.yml
@ -1317,53 +1317,6 @@ steps:
|
||||
# - mc cp ./dist/*.dmg scw-fr-par/vikunja-releases/desktop/$VERSION/
|
||||
# - mc cp ./dist/*.dmg.blockmap scw-fr-par/vikunja-releases/desktop/$VERSION/
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: deploy-docs
|
||||
|
||||
workspace:
|
||||
base: /go
|
||||
path: src/code.vikunja.io/api
|
||||
|
||||
clone:
|
||||
depth: 50
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
branch:
|
||||
- main
|
||||
|
||||
steps:
|
||||
- name: theme
|
||||
image: kolaente/toolbox
|
||||
pull: always
|
||||
commands:
|
||||
- mkdir docs/themes/vikunja -p
|
||||
- cd docs/themes/vikunja
|
||||
- wget https://dl.vikunja.io/theme/vikunja-theme.tar.gz
|
||||
- tar -xzf vikunja-theme.tar.gz
|
||||
|
||||
- name: build
|
||||
image: klakegg/hugo:0.111.3
|
||||
pull: always
|
||||
commands:
|
||||
- cd docs
|
||||
- hugo
|
||||
- mv public/docs/* public # Hugo seems to be not capable of setting a different theme for a home page, so we do this ugly hack to fix it.
|
||||
|
||||
- name: docker
|
||||
image: plugins/docker
|
||||
pull: always
|
||||
settings:
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
repo: vikunja/docs
|
||||
context: docs/
|
||||
dockerfile: docs/Dockerfile
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
@ -1380,7 +1333,6 @@ trigger:
|
||||
depends_on:
|
||||
- build-and-test
|
||||
- release
|
||||
- deploy-docs
|
||||
- docker-release
|
||||
- desktop-release
|
||||
|
||||
@ -1400,6 +1352,6 @@ steps:
|
||||
- failure
|
||||
---
|
||||
kind: signature
|
||||
hmac: 74414af8fe9d632c1620090f562b3acd32863b38da230fb1854b8bed45055feb
|
||||
hmac: 3cc4b45fcbbab5ccee14e5532b2d35f5db54cde29a8f6e854b563462e3bbb509
|
||||
|
||||
...
|
||||
|
@ -1,3 +0,0 @@
|
||||
FROM nginx
|
||||
ADD public /usr/share/nginx/html/docs
|
||||
ADD nginx.conf /etc/nginx/conf.d/default.conf
|
@ -1,63 +0,0 @@
|
||||
baseurl: https://vikunja.io/docs/
|
||||
title: Vikunja
|
||||
theme: vikunja
|
||||
enableRobotsTXT: true
|
||||
canonifyURLs: false
|
||||
|
||||
pygmentsUseClasses: true
|
||||
|
||||
permalinks:
|
||||
post: /:year/:month/:title/
|
||||
doc: /:slug/
|
||||
page: /:slug/
|
||||
default: /:slug/
|
||||
|
||||
params:
|
||||
description: The to-do app to organize your life
|
||||
author: The Vikunja Authors
|
||||
website: https://vikunja.io
|
||||
plausibleEnabled: true
|
||||
plausibleDomain: vikunja.io
|
||||
plausibleURL: https://analytics.kolaente.de
|
||||
|
||||
markup:
|
||||
goldmark:
|
||||
renderer:
|
||||
unsafe: true
|
||||
|
||||
menu:
|
||||
page:
|
||||
- name: Home
|
||||
url: https://vikunja.io/
|
||||
weight: 10
|
||||
- name: Features
|
||||
url: https://vikunja.io/features
|
||||
weight: 20
|
||||
- name: Download
|
||||
url: https://vikunja.io/download
|
||||
weight: 30
|
||||
- name: Blog
|
||||
url: https://vikunja.io/blog/
|
||||
weight: 35
|
||||
- name: Docs
|
||||
url: https://vikunja.io/docs
|
||||
weight: 40
|
||||
- name: Code
|
||||
url: https://code.vikunja.io/
|
||||
weight: 50
|
||||
- name: Community
|
||||
url: https://community.vikunja.io/
|
||||
weight: 60
|
||||
- name: Stickers
|
||||
url: https://vikunja.cloud/stickers?utm_source=io&utm_medium=io&utm_campaign=menu
|
||||
weight: 65
|
||||
- name: Get it Hosted
|
||||
url: https://vikunja.cloud/?utm_source=io&utm_medium=io&utm_campaign=menu
|
||||
weight: 70
|
||||
sidebar:
|
||||
- name: setup
|
||||
weight: 10
|
||||
- name: usage
|
||||
weight: 20
|
||||
- name: development
|
||||
weight: 30
|
@ -1,25 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Docs"
|
||||
draft: false
|
||||
url: "/docs"
|
||||
type: "doc"
|
||||
weight: 10
|
||||
---
|
||||
# Documentation
|
||||
|
||||
This is the documentation for Vikunja.
|
||||
You can find available articles in the menu on the left.
|
||||
|
||||
## About
|
||||
|
||||
To learn more about the what, why and how, take a look at [the features page](https://vikunja.io/en/features).
|
||||
|
||||
## Start
|
||||
|
||||
A good starting point if you want to install and host Vikunja on your server are [the install documentation]({{< ref "./setup/install.md">}})
|
||||
and [available configuration options]({{< ref "./setup/config.md">}}).
|
||||
|
||||
## Developing
|
||||
|
||||
If you want to start contributing to Vikunja, take a look at [the development docs]({{< ref "./development/development.md">}}).
|
@ -1,34 +0,0 @@
|
||||
---
|
||||
date: "2019-03-31:00:00+01:00"
|
||||
title: "Cli Commands"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Adding new cli commands
|
||||
|
||||
All cli-related functions are located in `pkg/cmd`.
|
||||
Each cli command usually calls a function in another package.
|
||||
For example, the `vikunja migrate` command calls `migration.Migrate()`.
|
||||
|
||||
Vikunja uses the amazing [cobra](https://github.com/spf13/cobra) library for its cli.
|
||||
Please refer to its documentation for information about how to use flags etc.
|
||||
|
||||
To add a new cli command, add something like the following:
|
||||
|
||||
```go
|
||||
func init() {
|
||||
rootCmd.AddCommand(myCmd)
|
||||
}
|
||||
|
||||
var myCmd = &cobra.Command{
|
||||
Use: "My-command",
|
||||
Short: "A short description about your command.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// Call other functions
|
||||
},
|
||||
}
|
||||
```
|
@ -1,41 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Configuration Options"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Configuration options
|
||||
|
||||
All configuration variables are declared in the `config` package.
|
||||
It uses [viper](https://github.com/spf13/viper) under the hood to handle setting defaults and parsing config files.
|
||||
Viper handles parsing all different configuration sources.
|
||||
|
||||
## Adding new config options
|
||||
|
||||
To make handling configuration parameters a bit easier, we introduced a `Key` string type in the `config` package which
|
||||
you can call directly to get a config value.
|
||||
|
||||
To add a new config option, you should add a new key const to `pkg/config/config.go` and possibly a default value.
|
||||
Default values should always enable the feature to work or turn it off completely if it always needs
|
||||
additional configuration.
|
||||
|
||||
Make sure to also add the new config option to the default config file (`config.yml.sample` at the root of the repository)
|
||||
with an explanatory comment to make sure it is well documented.
|
||||
Then run `mage generate-docs` to generate the configuration docs from the sample file.
|
||||
|
||||
## Getting Configuration Values
|
||||
|
||||
To retrieve a configured value call the key with a getter for the type you need.
|
||||
For example:
|
||||
|
||||
```go
|
||||
if config.CacheEnabled.GetBool() {
|
||||
// Do something with enabled caches
|
||||
}
|
||||
```
|
||||
|
||||
Take a look at the methods declared on the type to see what's available.
|
@ -1,33 +0,0 @@
|
||||
---
|
||||
title: "Cron Tasks"
|
||||
date: 2021-07-13T23:21:52+02:00
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# How to add a cron job task
|
||||
|
||||
Cron jobs are tasks which run on a predefined schedule.
|
||||
Vikunja uses these through a light wrapper package around the excellent [github.com/robfig/cron](https://github.com/robfig/cron) package.
|
||||
|
||||
The package exposes a `cron.Schedule` method with two arguments: The first one to define the schedule when the cron task should run, and the second one with the actual function to run at the schedule. You would then create a new function to register your the actual cron task in your package.
|
||||
|
||||
A basic function to register a cron task looks like this:
|
||||
|
||||
```go
|
||||
func RegisterSomeCronTask() {
|
||||
err := cron.Schedule("0 * * * *", func() {
|
||||
// Do something every hour
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Call the register method in the `FullInit()` method of the `init` package to actually register it.
|
||||
|
||||
## Schedule Syntax
|
||||
|
||||
The cron syntax uses the same on you may know from unix systems.
|
||||
|
||||
It is described in detail [here](https://pkg.go.dev/github.com/robfig/cron#hdr-CRON_Expression_Format).
|
@ -1,38 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Database"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Database
|
||||
|
||||
Vikunja uses [xorm](https://xorm.io/) as an abstraction layer to handle the database connection.
|
||||
Please refer to [their](https://xorm.io/docs/) documentation on how to exactly use it.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Using the database
|
||||
|
||||
When using the common web handlers, you get an `xorm.Session` to do database manipulations.
|
||||
In other packages, use the `db.NewSession()` method to get a new database session.
|
||||
|
||||
## Adding new database tables
|
||||
|
||||
To add a new table to the database, create the struct and [add a migration for it]({{< ref "db-migrations.md" >}}).
|
||||
|
||||
To learn more about how to configure your struct to create "good" tables, refer to [the xorm documentation](https://xorm.io/docs/).
|
||||
|
||||
In most cases you will also need to implement the `TableName() string` method on the new struct to make sure the table name matches the rest of the tables - plural.
|
||||
|
||||
## Adding data to test fixtures
|
||||
|
||||
Adding data for test fixtures can be done via `yaml` files in `pkg/models/fixtures`.
|
||||
|
||||
The name of the yaml file should match the table name in the database.
|
||||
Adding values to it is done via array definition inside it.
|
||||
|
||||
**Note**: Table and column names need to be in snake_case as that's what is used internally in the database and for mapping values from the database to xorm so your structs can use it.
|
@ -1,78 +0,0 @@
|
||||
---
|
||||
date: "2019-03-29:00:00+02:00"
|
||||
title: "Database Migrations"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Database Migrations
|
||||
|
||||
Vikunja runs all database migrations automatically on each start if needed.
|
||||
Additionally, they can also be run directly by using the `migrate` command.
|
||||
|
||||
We use [xormigrate](https://github.com/techknowlogick/xormigrate) to handle migrations,
|
||||
which is based on gormigrate.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Add a new migration
|
||||
|
||||
All migrations are stored in `pkg/migrations` and files should have the same name as their id.
|
||||
|
||||
Each migration should have a function to apply and roll it back, as well as a numeric id (the datetime)
|
||||
and a more in-depth description of what the migration actually does.
|
||||
|
||||
To easily get a new id, run the following on any unix system:
|
||||
|
||||
```
|
||||
date +%Y%m%d%H%M%S
|
||||
```
|
||||
|
||||
New migrations should be added via the `init()` function to the `migrations` variable.
|
||||
All migrations are sorted before being executed, since `init()` does not guarantee the order.
|
||||
|
||||
When you're adding a new struct, you also need to add it to the `models.GetTables()` function
|
||||
to ensure it will be created on new installations.
|
||||
|
||||
### Generating a new migration stub
|
||||
|
||||
You can easily generate a pre-filled migration stub by running `mage dev:make-migration`.
|
||||
It will ask you for a table name and generate an empty migration similar to the example shown below.
|
||||
|
||||
### Example
|
||||
|
||||
```go
|
||||
package migration
|
||||
|
||||
import (
|
||||
"github.com/go-xorm/xorm"
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
)
|
||||
|
||||
// Used for rollback
|
||||
type teamMembersMigration20190328074430 struct {
|
||||
Updated int64 `xorm:"updated"`
|
||||
}
|
||||
|
||||
func (teamMembersMigration20190328074430) TableName() string {
|
||||
return "team_members"
|
||||
}
|
||||
|
||||
func init() {
|
||||
migrations = append(migrations, &xormigrate.Migration{
|
||||
ID: "20190328074430",
|
||||
Description: "Remove updated from team_members",
|
||||
Migrate: func(tx *xorm.Engine) error {
|
||||
return dropTableColum(tx, "team_members", "updated")
|
||||
},
|
||||
Rollback: func(tx *xorm.Engine) error {
|
||||
return tx.Sync2(teamMembersMigration20190328074430{})
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
You should always copy the changed parts of the struct you're changing when adding migrations.
|
@ -1,106 +0,0 @@
|
||||
---
|
||||
date: "2022-09-21:00:00+02:00"
|
||||
title: "Development"
|
||||
toc: true
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
name: "Development"
|
||||
---
|
||||
|
||||
# Development
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## General
|
||||
|
||||
To contribute to Vikunja, fork the project and work on the main branch.
|
||||
Once you feel like your changes are ready, open a PR in the respective repo [on our Gitea instance](https://kolaente.dev/vikunja).
|
||||
We cannot accept PRs on mirror sites.
|
||||
|
||||
A maintainer will take a look and give you feedback. Once everyone is happy, the PR gets merged and released.
|
||||
|
||||
If you plan to do a bigger change, it is better to open an issue for discussion first.
|
||||
|
||||
The main repo is [`vikunja/vikunja`](https://kolaente.dev/vikunja/vikunja), it contains all code for the api, frontend and desktop applications.
|
||||
|
||||
## Where to file issues
|
||||
|
||||
You can file issues on [the Gitea repo](https://kolaente.dev/vikunja/vikunja) or [on the GitHub mirror](https://github.com/go-vikunja/vikunja), when you don't want to create an account on the Gitea instance.
|
||||
|
||||
Please note that due to a spam problem, we need to manually enable accounts on Gitea after you've registered there.
|
||||
To get that started, please reach out on another channel with your username.
|
||||
|
||||
Another option is [the community forum](https://community.vikunja.io), especially if you want to discuss a feature in more detail.
|
||||
|
||||
## API
|
||||
|
||||
You'll need at least Go 1.21 to build Vikunja's api.
|
||||
|
||||
A lot of developing tasks are automated using a Magefile, so make sure to [take a look at it]({{< ref "mage.md">}}).
|
||||
|
||||
Make sure to check the other doc articles for specific development tasks like [testing]({{< ref "test.md">}}),
|
||||
[database migrations]({{< ref "db-migrations.md" >}}) and the [project structure]({{< ref "structure.md" >}}).
|
||||
|
||||
## Frontend requirements
|
||||
|
||||
The code for the frontend is located in the `frontend` sub folder of the main repo.
|
||||
More instructions can be found in the repo's README.
|
||||
|
||||
You need to have [pnpm](https://pnpm.io/) and Node.JS in version 20 or higher installed.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
All Pull Requests must be made [on our Gitea instance](https://kolaente.dev/vikunja).
|
||||
We cannot accept PRs on mirror sites.
|
||||
|
||||
Please try to make your pull request easy to review.
|
||||
For that, please read the [*Best Practices for Faster Reviews*](https://github.com/kubernetes/community/blob/261cb0fd089b64002c91e8eddceebf032462ccd6/contributors/guide/pull-requests.md#best-practices-for-faster-reviews) guide.
|
||||
It has lots of useful tips for any project you may want to contribute to.
|
||||
Some of the key points:
|
||||
|
||||
- Make small pull requests.
|
||||
The smaller, the faster to review and the more likely it will be merged soon.
|
||||
- Don't make changes unrelated to your PR.
|
||||
Maybe there are typos on some comments, maybe refactoring would be welcome on a function…
|
||||
but if that is not related to your PR, please make *another* PR for that.
|
||||
- Split big pull requests into multiple small ones.
|
||||
An incremental change will be faster to review than a huge PR.
|
||||
- Allow edits by maintainers. This way, the maintainers will take care of merging the PR later on instead of you.
|
||||
|
||||
### PR title and summary
|
||||
|
||||
In the PR title, describe the problem you are fixing, not how you are fixing it.
|
||||
Use the first comment as a summary of your PR.
|
||||
In the PR summary, you can describe exactly how you are fixing this problem.
|
||||
Keep this summary up-to-date as the PR evolves.
|
||||
|
||||
If your PR changes the UI, you must add **after** screenshots in the PR summary.
|
||||
If your PR closes an issue, you must note that in a way that both GitHub and Gitea understand, i.e. by appending a paragraph like
|
||||
|
||||
```text
|
||||
Fixes/Closes/Resolves #<ISSUE_NR_X>.
|
||||
Fixes/Closes/Resolves #<ISSUE_NR_Y>.
|
||||
```
|
||||
|
||||
to your summary.
|
||||
Each issue that will be closed must stand on a separate line.
|
||||
|
||||
If your PR is related to a discussion in the forum, you must add a link to the forum discussion.
|
||||
|
||||
### Git flow
|
||||
|
||||
The `main` branch is the latest and bleeding edge branch with all changes. Unstable releases are automatically created from this branch.
|
||||
New Pull-Requests should be made against the `main` branch.
|
||||
|
||||
A release gets tagged from the main branch with the version name as tag name.
|
||||
|
||||
Backports and point-releases should go to a `release/version` branch, based on the tag they are building on top of.
|
||||
|
||||
## Conventional Commits
|
||||
|
||||
We're using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) because they simplify generating release notes a lot.
|
||||
|
||||
It is not required to use them when creating a PR, but appreciated.
|
@ -1,72 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Custom Errors"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Custom Errors
|
||||
|
||||
All custom errors are defined in `pkg/models/errors.go`.
|
||||
You should add new ones in this file.
|
||||
|
||||
Custom errors usually have fields for the http return code, a [Vikunja-specific error code]({{< ref "../usage/errors.md">}})
|
||||
and a human-readable error message about what went wrong.
|
||||
|
||||
An error consists of multiple functions and definitions:
|
||||
|
||||
```go
|
||||
// This struct holds any information about this specific error.
|
||||
// In this case, it contains the user ID of a nonexistent user.
|
||||
// This type should always be a struct, even if it has no values in it.
|
||||
|
||||
// ErrUserDoesNotExist represents a "UserDoesNotExist" kind of error.
|
||||
type ErrUserDoesNotExist struct {
|
||||
UserID int64
|
||||
}
|
||||
|
||||
// This function is mostly used in unit tests to check if a returned error is of that type.
|
||||
// Every error type should have one of these.
|
||||
// The name should always start with IsErr... followed by the name of the error.
|
||||
|
||||
// IsErrUserDoesNotExist checks if an error is a ErrUserDoesNotExist.
|
||||
func IsErrUserDoesNotExist(err error) bool {
|
||||
_, ok := err.(ErrUserDoesNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
// This is the definition of the actual error type.
|
||||
// Your error type is _required_ to implement this in order to be able to be returned as an "error" from functions.
|
||||
func (err ErrUserDoesNotExist) Error() string {
|
||||
return fmt.Sprintf("User does not exist [user id: %d]", err.UserID)
|
||||
}
|
||||
|
||||
// This const holds the Vikunja error code used to be able to identify this error without having to
|
||||
// rely on an error string.
|
||||
// This needs to be unique, so you should check whether the error code exists or not.
|
||||
// The general convention for error codes is as follows:
|
||||
// * Every "group" errors lives in a thousend something. For example all user issues are 1000-something, all
|
||||
// project errors are 3000-something and so on.
|
||||
// * New error codes should be the current max error code + 1. Don't take free numbers to prevent old errors
|
||||
// which are deprecated and removed from being "new ones". For example, if there are error codes 1001, 1002, 1004,
|
||||
// a new error should be 1005 and not 1003.
|
||||
|
||||
// ErrCodeUserDoesNotExist holds the unique world-error code of this error
|
||||
const ErrCodeUserDoesNotExist = 1005
|
||||
|
||||
// This is the implementation which returns an http error which is then passed to the client.
|
||||
// Here you define the http status code with which one the error will be returned, the Vikunja error code and
|
||||
// a human-readable error message.
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrUserDoesNotExist) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{
|
||||
HTTPCode: http.StatusNotFound,
|
||||
Code: ErrCodeUserDoesNotExist,
|
||||
Message: "The user does not exist.",
|
||||
}
|
||||
}
|
||||
```
|
@ -1,211 +0,0 @@
|
||||
---
|
||||
date: 2018-10-13T19:26:34+02:00
|
||||
title: "Events and Listeners"
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Events and Listeners
|
||||
|
||||
Vikunja provides a simple observer pattern mechanism through events and listeners.
|
||||
The basic principle of events is always the same: Something happens (=An event is fired) and something reacts to it (=A listener is called).
|
||||
|
||||
Vikunja supports this principle through the `events` package.
|
||||
It is built upon the excellent [watermill](https://watermill.io) library.
|
||||
|
||||
Currently, it only supports dispatching events through Go Channels which makes it configuration-less.
|
||||
More methods of dispatching events (like kafka or rabbitmq) are available in watermill and could be enabled with a PR.
|
||||
|
||||
This document explains how events and listeners work in Vikunja, how to use them and how to create new ones.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Events
|
||||
|
||||
### Definition
|
||||
|
||||
Each event has to implement this interface:
|
||||
|
||||
```go
|
||||
type Event interface {
|
||||
Name() string
|
||||
}
|
||||
```
|
||||
|
||||
An event can contain whatever data you need.
|
||||
|
||||
When an event is dispatched, all of the data it contains will be marshaled into json for dispatching.
|
||||
You then get the event with all its data back in the listener, see below.
|
||||
|
||||
#### Naming Convention
|
||||
|
||||
Event names should roughly have the entity they're dealing with on the left and the action on the right of the name, separated by `.`.
|
||||
There's no limit to how "deep" or specific an event name can be.
|
||||
|
||||
The name should have the most general concept it's describing at the left, getting more specific on the right of it.
|
||||
|
||||
#### Location
|
||||
|
||||
All events for a package should be declared in the `events.go` file of that package.
|
||||
|
||||
### Creating a New Event
|
||||
|
||||
The easiest way to create a new event is to generate it with mage:
|
||||
|
||||
```
|
||||
mage dev:make-event <event-name> <package>
|
||||
```
|
||||
|
||||
The function takes the name of the event as the first argument and the package where the event should be created as the second argument.
|
||||
Events will be appended to the `pkg/<module>/events.go` file.
|
||||
Both parameters are mandatory.
|
||||
|
||||
The event type name is automatically camel-cased and gets the `Event` suffix if the provided name does not already have one.
|
||||
The event name is derived from the type name and stripped of the `.event` suffix.
|
||||
|
||||
The generated event will look something like the example below.
|
||||
|
||||
### Dispatching events
|
||||
|
||||
To dispatch an event, simply call the `events.Dispatch` method and pass in the event as parameter.
|
||||
|
||||
### Example
|
||||
|
||||
The `TaskCreatedEvent` is declared in the `pkg/models/events.go` file as follows:
|
||||
|
||||
```go
|
||||
// TaskCreatedEvent represents an event where a task has been created
|
||||
type TaskCreatedEvent struct {
|
||||
Task *Task
|
||||
Doer web.Auth
|
||||
}
|
||||
|
||||
// Name defines the name for TaskCreatedEvent
|
||||
func (t *TaskCreatedEvent) Name() string {
|
||||
return "task.created"
|
||||
}
|
||||
```
|
||||
|
||||
It is dispatched in the `createTask` function of the `models` package:
|
||||
|
||||
```go
|
||||
func createTask(s *xorm.Session, t *Task, a web.Auth, updateAssignees bool) (err error) {
|
||||
|
||||
// ...
|
||||
|
||||
err = events.Dispatch(&TaskCreatedEvent{
|
||||
Task: t,
|
||||
Doer: a,
|
||||
})
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, the current task and doer are injected into it.
|
||||
|
||||
### Special Events
|
||||
|
||||
#### `BootedEvent`
|
||||
|
||||
Once Vikunja is fully initialized, right before the api web server is started, this event is fired.
|
||||
|
||||
## Listeners
|
||||
|
||||
A listener is a piece of code that gets executed asynchronously when an event is dispatched.
|
||||
|
||||
A single event can have multiple listeners who are independent of each other.
|
||||
|
||||
### Definition
|
||||
|
||||
All listeners must implement this interface:
|
||||
|
||||
```go
|
||||
// Listener represents something that listens to events
|
||||
type Listener interface {
|
||||
Handle(msg *message.Message) error
|
||||
Name() string
|
||||
}
|
||||
```
|
||||
|
||||
The `Handle` method is executed when the event this listener listens on is dispatched.
|
||||
* As the single parameter, it gets the payload of the event, which is the event struct when it was dispatched decoded as json object and passed as a slice of bytes.
|
||||
To use it you'll need to unmarshal it. Unfortunately there's no way to pass an already populated event object to the function because we would not know what type it has when parsing it.
|
||||
* If the handler returns an error, the listener is retried 5 times, with an exponential back-off period in between retries.
|
||||
If it still fails after the fifth retry, the event is nack'd and it's up to the event dispatcher to resend it.
|
||||
You can learn more about this mechanism in the [watermill documentation](https://watermill.io/docs/middlewares/#retry).
|
||||
|
||||
The `Name` method needs to return a unique listener name for this listener.
|
||||
It should follow the same convention as event names, see above.
|
||||
|
||||
### Creating a New Listener
|
||||
|
||||
The easiest way to create a new listener for an event is with mage:
|
||||
|
||||
```
|
||||
mage dev:make-listener <listener-name> <event-name> <package>
|
||||
```
|
||||
|
||||
This will create a new listener type in the `pkg/<package>/listeners.go` file and implement the `Handle` and `Name` methods.
|
||||
It will also pre-generate some boilerplate code to unmarshal the event from the payload.
|
||||
|
||||
Furthermore, it will register the listener for its event in the `RegisterListeners()` method of the same file.
|
||||
This function is called at startup and has to contain all events you want to listen for.
|
||||
|
||||
### Listening for Events
|
||||
|
||||
To listen for an event, you need to register the listener for the event it should be called for.
|
||||
This usually happens in the `RegisterListeners()` method in `pkg/<package>/listeners.go` which is called at start up.
|
||||
|
||||
The listener will never be executed if it hasn't been registered.
|
||||
|
||||
See the example below.
|
||||
|
||||
### Example
|
||||
|
||||
```go
|
||||
// RegisterListeners registers all event listeners
|
||||
func RegisterListeners() {
|
||||
events.RegisterListener((&ListCreatedEvent{}).Name(), &IncreaseListCounter{})
|
||||
}
|
||||
|
||||
// IncreaseTaskCounter represents a listener
|
||||
type IncreaseTaskCounter struct {}
|
||||
|
||||
// Name defines the name for the IncreaseTaskCounter listener
|
||||
func (s *IncreaseTaskCounter) Name() string {
|
||||
return "task.counter.increase"
|
||||
}
|
||||
|
||||
// Handle is executed when the event IncreaseTaskCounter listens on is fired
|
||||
func (s *IncreaseTaskCounter) Handle(payload message.Payload) (err error) {
|
||||
return keyvalue.IncrBy(metrics.TaskCountKey, 1)
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
When testing, you should call the `events.Fake()` method in the `TestMain` function of the package you want to test.
|
||||
This prevents any events from being fired and lets you assert an event has been dispatched like so:
|
||||
|
||||
```go
|
||||
events.AssertDispatched(t, &TaskCreatedEvent{})
|
||||
```
|
||||
|
||||
### Testing a listener
|
||||
|
||||
You can call an event listener manually with the `events.TestListener` method like so:
|
||||
|
||||
```go
|
||||
ev := &TaskCommentCreatedEvent{
|
||||
Task: &task,
|
||||
Doer: u,
|
||||
Comment: tc,
|
||||
}
|
||||
|
||||
events.TestListener(t, ev, &SendTaskCommentNotification{})
|
||||
```
|
||||
|
||||
This will call the listener's `Handle` method and assert it did not return an error when calling.
|
@ -1,33 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "New API Endpoints"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Add a new api endpoint/feature
|
||||
|
||||
Most of the api endpoints/features of Vikunja are using the [common web handler](https://code.vikunja.io/web).
|
||||
This is a library created by Vikunja in an effort to facilitate the creation of REST endpoints.
|
||||
|
||||
This works by abstracting the handling of CRUD-Requests, including rights check.
|
||||
|
||||
You can learn more about the web handler on [the project's repo](https://code.vikunja.io/web).
|
||||
|
||||
### Helper for pagination
|
||||
|
||||
Pagination limits can be calculated with a helper function, `getLimitFromPageIndex(pageIndex)`
|
||||
(only available in the `models` package) from any page number.
|
||||
It returns the `limit` (max-length) and `offset` parameters needed for SQL-Queries.
|
||||
|
||||
You can feed this function directly into xorm's `Limit`-Function like so:
|
||||
|
||||
```go
|
||||
projects := []*Project{}
|
||||
err := x.Limit(getLimitFromPageIndex(pageIndex, itemsPerPage)).Find(&projects)
|
||||
```
|
||||
|
||||
// TODO: Add a full example from start to finish, like a tutorial on how to create a new endpoint?
|
@ -1,174 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Magefile"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Mage
|
||||
|
||||
Vikunja uses [Mage](https://magefile.org/) to script common development tasks and even releasing.
|
||||
Mage is a pure go solution which allows for greater flexibility and things like better parallelization.
|
||||
|
||||
This document explains what tasks are available and what they do.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Installation
|
||||
|
||||
To use mage, you'll need to install the mage cli.
|
||||
To install it, run the following command:
|
||||
|
||||
```
|
||||
go install github.com/magefile/mage
|
||||
```
|
||||
|
||||
## Categories
|
||||
|
||||
There are multiple categories of subcommands in the magefile:
|
||||
|
||||
* `build`: Contains commands to build a single binary
|
||||
* `check`: Contains commands to statically check the source code
|
||||
* `release`: Contains commands to release Vikunja with everything that's required
|
||||
* `test`: Contains commands to run all kinds of tests
|
||||
* `dev`: Contains commands to run development tasks
|
||||
* `misc`: Commands which do not belong in either of the other categories
|
||||
|
||||
## CI
|
||||
|
||||
These tasks are automatically run in our CI every time someone pushes to main or you update a pull request:
|
||||
|
||||
* `mage lint`
|
||||
* `mage build:build`
|
||||
|
||||
## Build
|
||||
|
||||
### Build Vikunja
|
||||
|
||||
```
|
||||
mage build
|
||||
```
|
||||
|
||||
Builds a `vikunja`-binary in the root directory of the repo for the platform it is run on.
|
||||
|
||||
### clean
|
||||
|
||||
```
|
||||
mage build:clean
|
||||
```
|
||||
|
||||
Cleans all build and executable files
|
||||
|
||||
## Check
|
||||
|
||||
All check sub-commands exit with a status code of 1 if the check fails.
|
||||
|
||||
Various code-checks are available:
|
||||
|
||||
* `mage check:all`: Runs golangci and swagger documentation check
|
||||
* `mage lint`: Checks if the code follows the rules as defined in the `.golangci.yml` config file.
|
||||
* `mage lint:fix`: Fixes all code style issues which are easily fixable.
|
||||
|
||||
## Release
|
||||
|
||||
### Build Releases
|
||||
|
||||
```
|
||||
mage release
|
||||
```
|
||||
|
||||
Builds binaries for all platforms and zips them with a copy of the `templates/` folder.
|
||||
All built zip files are stored into `dist/zips/`. Binaries are stored in `dist/binaries/`,
|
||||
binaries bundled with `templates` are stored in `dist/releases/`.
|
||||
|
||||
All cross-platform binaries built using this series of commands are built with the help of
|
||||
[xgo](https://github.com/techknowlogick/xgo). The mage command will automatically install the
|
||||
binary to be able to use it.
|
||||
|
||||
`mage release:release` is a shortcut to execute `mage release:dirs release:windows release:linux release:darwin release:copy release:check release:os-package release:zip`.
|
||||
|
||||
* `mage release:dirs` creates all directories needed
|
||||
* `mage release:windows`/`release:linux`/`release:darwin` execute xgo to build for their respective platforms
|
||||
* `mage release:copy` bundles binaries with a copy of the `LICENSE` and sample config files to then be zipped
|
||||
* `mage release:check` creates sha256 checksums for each binary which will be included in the zip file
|
||||
* `mage release:os-package` bundles a binary with the `sha256` checksum file, a sample `config.yml` and a copy of the license in a folder for each architecture
|
||||
* `mage release:compress` compresses all build binaries with `upx` to save space
|
||||
* `mage release:zip` packages a zip file for the files created by `release:os-package`
|
||||
|
||||
### Build os packages
|
||||
|
||||
```
|
||||
mage release:packages
|
||||
```
|
||||
|
||||
Will build `.deb`, `.rpm` and `.apk` packages to `dist/os-packages`.
|
||||
|
||||
### Make a debian repo
|
||||
|
||||
```
|
||||
mage release:reprepro
|
||||
```
|
||||
|
||||
Takes an already built debian package and creates a debian repo structure around it.
|
||||
|
||||
Used to be run inside a [docker container](https://git.kolaente.de/konrad/reprepro-docker) in the CI process when releasing.
|
||||
|
||||
## Test
|
||||
|
||||
### unit
|
||||
|
||||
```
|
||||
mage test:unit
|
||||
```
|
||||
|
||||
Runs all tests except integration tests.
|
||||
|
||||
### coverage
|
||||
|
||||
```
|
||||
mage test:coverage
|
||||
```
|
||||
|
||||
Runs all tests except integration tests and generates a `coverage.html` file to inspect the code coverage.
|
||||
|
||||
### integration
|
||||
|
||||
```
|
||||
mage test:integration
|
||||
```
|
||||
|
||||
Runs all integration tests.
|
||||
|
||||
## Dev
|
||||
|
||||
### Create a new migration
|
||||
|
||||
```
|
||||
mage dev:create-migration
|
||||
```
|
||||
|
||||
Creates a new migration with the current date.
|
||||
Will ask for the name of the struct you want to create a migration for.
|
||||
|
||||
See also [migration docs]({{< ref "mage.md" >}}).
|
||||
|
||||
## Misc
|
||||
|
||||
### Format the code
|
||||
|
||||
```
|
||||
mage fmt
|
||||
```
|
||||
|
||||
Formats all source code using `go fmt`.
|
||||
|
||||
### Generate swagger definitions from code comments
|
||||
|
||||
```
|
||||
mage do-the-swag
|
||||
```
|
||||
|
||||
Generates swagger definitions from the comment annotations in the code.
|
@ -1,47 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Metrics"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Metrics
|
||||
|
||||
Metrics work by exposing a `/metrics` endpoint which can then be accessed by prometheus.
|
||||
|
||||
To keep the load on the database minimal, metrics are stored and updated in redis.
|
||||
The `metrics` package provides several functions to create and update metrics.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Exposing New Metrics
|
||||
|
||||
First, define a `const` with the metric key in redis. This is done in `pkg/metrics/metrics.go`.
|
||||
|
||||
To expose a new metric, you need to register it in the `init` function inside of the `metrics` package like so:
|
||||
|
||||
```go
|
||||
// Register total user count metric
|
||||
promauto.NewGaugeFunc(prometheus.GaugeOpts{
|
||||
Name: "vikunja_team_count", // The key of the metric. Must be unique.
|
||||
Help: "The total number of teams on this instance", // A description about the metric itself.
|
||||
}, func() float64 {
|
||||
count, _ := GetCount(TeamCountKey) // TeamCountKey is the const we defined earlier.
|
||||
return float64(count)
|
||||
})
|
||||
```
|
||||
|
||||
Then you'll need to set the metrics initial value on every startup of Vikunja.
|
||||
This is done in `pkg/routes/routes.go` to avoid cyclic imports.
|
||||
If metrics are enabled, it checks if a redis connection is available and then sets the initial values.
|
||||
A convenience function is available if the metric is based on a database struct.
|
||||
|
||||
Because metrics are stored in redis, you are responsible to increase or decrease these based on criteria you define.
|
||||
To do this, use `metrics.UpdateCount(value, key)` where `value` is the amount you want to change it (you can pass negative values to decrease it) and `key` it the redis key used to define the metric.
|
||||
|
||||
## Using it
|
||||
|
||||
A Prometheus config with a Grafana template is available at [our git repo](https://git.kolaente.de/vikunja/monitoring).
|
@ -1,131 +0,0 @@
|
||||
---
|
||||
date: "2020-01-19:16:00+02:00"
|
||||
title: "Migrations"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Writing a migrator for Vikunja
|
||||
|
||||
It is possible to migrate data from other to-do services to Vikunja.
|
||||
To make this easier, we have put together a few helpers which are documented on this page.
|
||||
|
||||
In general, each migrator implements a migrator interface which is then called from a client.
|
||||
The interface makes it possible to use helper methods which handle http and focus only on the implementation of the migrator itself.
|
||||
|
||||
There are two ways of migrating data from another service:
|
||||
|
||||
1. Through the auth-based flow where the user gives you access to their data at the third-party service through an oauth flow. You can then call the service's api on behalf of your user to get all the data. The Todoist, Trello and Microsoft To-Do Migrators use this pattern.
|
||||
2. A file migration where the user uploads a file obtained from some third-party service. In your migrator, you need to parse the file and create the projects, tasks etc. The Vikunja File Import uses this pattern.
|
||||
|
||||
To differentiate the two, there are two different interfaces you must implement.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Structure
|
||||
|
||||
All migrator implementations live in their own package in `pkg/modules/migration/<name-of-the-service>`.
|
||||
When creating a new migrator, you should place all related code inside that module.
|
||||
|
||||
## Migrator Interface
|
||||
|
||||
The migrator interface is defined as follows:
|
||||
|
||||
```go
|
||||
// Migrator is the basic migrator interface which is shared among all migrators
|
||||
type Migrator interface {
|
||||
// Name holds the name of the migration.
|
||||
// This is used to show the name to users and to keep track of users who already migrated.
|
||||
Name() string
|
||||
// Migrate is the interface used to migrate a user's tasks from another platform to Vikunja.
|
||||
// The user object is the user who's tasks will be migrated.
|
||||
Migrate(user *models.User) error
|
||||
// AuthURL returns a url for clients to authenticate against.
|
||||
// The use case for this are Oauth flows, where the server token should remain hidden and not
|
||||
// known to the frontend.
|
||||
AuthURL() string
|
||||
}
|
||||
```
|
||||
|
||||
## File Migrator Interface
|
||||
|
||||
```go
|
||||
// FileMigrator handles importing Vikunja data from a file. The implementation of it determines the format.
|
||||
type FileMigrator interface {
|
||||
// Name holds the name of the migration.
|
||||
// This is used to show the name to users and to keep track of users who already migrated.
|
||||
Name() string
|
||||
// Migrate is the interface used to migrate a user's tasks, projects and other things from a file to Vikunja.
|
||||
// The user object is the user who's tasks will be migrated.
|
||||
Migrate(user *user.User, file io.ReaderAt, size int64) error
|
||||
}
|
||||
```
|
||||
|
||||
## Defining http routes
|
||||
|
||||
Once your migrator implements the migration interface, it becomes possible to use the helper http handlers.
|
||||
Their usage is very similar to the [general web handler](https://kolaente.dev/vikunja/web#user-content-defining-routes-using-the-standard-web-handler):
|
||||
|
||||
The `RegisterRoutes(m)` method registers all routes with the scheme `/[MigratorName]/(auth|migrate|status)` for the
|
||||
authUrl, Status and Migrate methods.
|
||||
|
||||
```go
|
||||
// This is an example for the Wunderlist migrator
|
||||
if config.MigrationWunderlistEnable.GetBool() {
|
||||
wunderlistMigrationHandler := &migrationHandler.MigrationWeb{
|
||||
MigrationStruct: func() migration.Migrator {
|
||||
return &wunderlist.Migration{}
|
||||
},
|
||||
}
|
||||
wunderlistMigrationHandler.RegisterRoutes(m)
|
||||
}
|
||||
```
|
||||
|
||||
And for the file migrator:
|
||||
|
||||
```go
|
||||
vikunjaFileMigrationHandler := &migrationHandler.FileMigratorWeb{
|
||||
MigrationStruct: func() migration.FileMigrator {
|
||||
return &vikunja_file.FileMigrator{}
|
||||
},
|
||||
}
|
||||
vikunjaFileMigrationHandler.RegisterRoutes(m)
|
||||
```
|
||||
|
||||
You should also document the routes with [swagger annotations]({{< ref "swagger-docs.md" >}}).
|
||||
|
||||
## Insertion helper method
|
||||
|
||||
There is a method available in the `migration` package which takes a fully nested Vikunja structure and creates it with all relations.
|
||||
This means you start by adding a project, then add projects inside that project, then tasks in the lists and so on.
|
||||
In general, it is recommended to have one root project with all projects of the other service as child projects.
|
||||
|
||||
The root structure must be present as `[]*models.ProjectWithTasksAndBuckets`. It allows to represent all of Vikunja's hierarchy as a single data structure.
|
||||
|
||||
Then call the method like so:
|
||||
|
||||
```go
|
||||
fullVikunjaHierarchy, err := convertWunderlistToVikunja(wContent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = migration.InsertFromStructure(fullVikunjaHierarchy, user)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
If your migrator is an oauth-based one, you should add at least an option to enable or disable it.
|
||||
Chances are, you'll need some more options for things like client ID and secret (if the other service uses oAuth as an authentication flow).
|
||||
|
||||
The easiest way to implement an on/off switch is to check whether your migration service is enabled or not when registering the routes, and then simply don't registering the routes in case it is disabled.
|
||||
|
||||
File based migrators can always be enabled.
|
||||
|
||||
### Making the migrator public in `/info`
|
||||
|
||||
You should make your migrator available in the `/info` endpoint so that frontends can display options to enable them or not.
|
||||
To do this, add an entry to the `AvailableMigrators` field in `pkg/routes/api/v1/info.go`.
|
@ -1,119 +0,0 @@
|
||||
---
|
||||
date: 2021-02-07T19:26:34+02:00
|
||||
title: "Notifications"
|
||||
toc: true
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Notifications
|
||||
|
||||
Vikunja provides a simple abstraction to send notifications per mail and in the database.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Definition
|
||||
|
||||
Each notification has to implement this interface:
|
||||
|
||||
```go
|
||||
type Notification interface {
|
||||
ToMail() *Mail
|
||||
ToDB() interface{}
|
||||
Name() string
|
||||
}
|
||||
```
|
||||
|
||||
Both functions return the formatted messages for mail and database.
|
||||
|
||||
A notification will only be sent or recorded for those of the two methods which don't return `nil`.
|
||||
For example, if your notification should not be recorded in the database but only sent out per mail, it is enough to let the `ToDB` function return `nil`.
|
||||
|
||||
### Mail notifications
|
||||
|
||||
A list of chainable functions is available to compose a mail:
|
||||
|
||||
```go
|
||||
mail := NewMail().
|
||||
// The optional sender of the mail message.
|
||||
From("test@example.com").
|
||||
// The optional recipient of the mail message. Uses the mail address of the notifiable if omitted.
|
||||
To("test@otherdomain.com").
|
||||
// The subject of the mail to send.
|
||||
Subject("Testmail").
|
||||
// The greeting, or "intro" line of the mail.
|
||||
Greeting("Hi there,").
|
||||
// A line of text
|
||||
Line("This is a line of text").
|
||||
// An action can contain a title and a url. It gets rendered as a big button in the mail.
|
||||
// Note that you can have only one action per mail.
|
||||
// All lines added before an action will appear in the mail before the button, all lines
|
||||
// added afterwards will appear after it.
|
||||
Action("The Action", "https://example.com").
|
||||
// Another line of text.
|
||||
Line("This should be an outro line").
|
||||
```
|
||||
|
||||
If not provided, the `from` field of the mail contains the value configured in [`mailer.fromemail`](https://vikunja.io/docs/config-options/#fromemail).
|
||||
|
||||
### Database notifications
|
||||
|
||||
All data returned from the `ToDB()` method is serialized to json and saved into the database, along with the id of the notifiable, the name of the notification and a time stamp.
|
||||
If you don't use the database notification, the `Name()` function can return an empty string.
|
||||
|
||||
## Creating a new notification
|
||||
|
||||
The easiest way to generate a mail is by using the `mage dev:make-notification` command.
|
||||
|
||||
It takes the name of the notification and the package where the notification will be created.
|
||||
|
||||
## Notifiables
|
||||
|
||||
Notifiables can receive a notification.
|
||||
A notifiable is defined with this interface:
|
||||
|
||||
```go
|
||||
type Notifiable interface {
|
||||
// Should return the email address this notifiable has.
|
||||
RouteForMail() string
|
||||
// Should return the id of the notifiable entity
|
||||
RouteForDB() int64
|
||||
}
|
||||
```
|
||||
|
||||
The `User` type from the `user` package implements this interface.
|
||||
|
||||
## Sending a notification
|
||||
|
||||
Sending a notification is done with the `Notify` method from the `notifications` package.
|
||||
It takes a notifiable and a notification as input.
|
||||
|
||||
For example, the email confirm notification when a new user registers is sent like this:
|
||||
|
||||
```go
|
||||
n := &EmailConfirmNotification{
|
||||
User: update.User,
|
||||
IsNew: false,
|
||||
}
|
||||
|
||||
err = notifications.Notify(update.User, n)
|
||||
return
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
The `mail` package provides a `Fake()` method which you should call in the `MainTest` functions of your package.
|
||||
If it was called, no mails are being sent and you can instead assert they have been sent with the `AssertSent` method.
|
||||
|
||||
When testing, you should call the `notifications.Fake()` method in the `TestMain` function of the package you want to test.
|
||||
This prevents any notifications from being sent and lets you assert a notifications has been sent like this:
|
||||
|
||||
```go
|
||||
notifications.AssertSent(t, &ReminderDueNotification{})
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
Take a look at the [pkg/user/notifications.go](https://code.vikunja.io/api/src/branch/main/pkg/user/notifications.go) file for a good example.
|
@ -1,33 +0,0 @@
|
||||
---
|
||||
title: "Releasing a new Vikunja version"
|
||||
date: 2022-10-28T13:06:05+02:00
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Releasing a new Vikunja version
|
||||
|
||||
This checklist is a collection of all steps usually involved when releasing a new version of Vikunja.
|
||||
Not all steps are necessary for every release.
|
||||
|
||||
* Website update
|
||||
* New Features: If there are new features worth mentioning the feature page should be updated.
|
||||
* New Screenshots: If an overhaul of an existing feature happened so that it now looks different from the existing screenshot, a new one is required.
|
||||
* Generate changelogs (with git-cliff)
|
||||
* Tag a new version: Include the changelog for that version as the tag message
|
||||
* Once built: Prune the cloudflare cache so that the new versions show up at [dl.vikunja.io](https://dl.vikunja.io/)
|
||||
* Update the [Flathub desktop package](https://github.com/flathub/io.vikunja.Vikunja)
|
||||
* Release Highlights Blogpost
|
||||
* Include a section about Vikunja in general (totally fine to copy one from the earlier blog posts)
|
||||
* New Features & Improvements: Mention bigger features, potentially with screenshots. Things like refactoring are sometimes also worth mentioning.
|
||||
* Publish
|
||||
* Reddit
|
||||
* Twitter
|
||||
* Mastodon
|
||||
* Chat
|
||||
* Newsletter
|
||||
* Forum
|
||||
* If features in the release were sponsored, send an email to relevant stakeholders
|
||||
* Update Vikunja Cloud version and other instances
|
@ -1,170 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Project Structure"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Project structure
|
||||
|
||||
This document explains what each package does.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Root level
|
||||
|
||||
The root directory is where [the config file]({{< ref "../setup/config.md">}}), [Magefile]({{< ref "mage.md">}}), license, drone config,
|
||||
application entry point (`main.go`) and so on are located.
|
||||
|
||||
## pkg
|
||||
|
||||
This is where most of the magic happens. Most packages with actual code are located in this folder.
|
||||
|
||||
### caldav
|
||||
|
||||
This folder holds a simple caldav implementation which is responsible for the caldav feature.
|
||||
|
||||
### cmd
|
||||
|
||||
This package contains all cli-related files and functions.
|
||||
|
||||
To learn more about how to add a new command, see [the cli docs]({{< ref "cli.md">}}).
|
||||
|
||||
To learn more about how to use this cli, see [the cli usage docs]({{< ref "../usage/cli.md">}}).
|
||||
|
||||
### config
|
||||
|
||||
This package configures handling of Vikunja's runtime configuration.
|
||||
It sets default values and sets up viper and tells it where to look for config files, how to interpret which env variables
|
||||
for config etc.
|
||||
|
||||
See also the [docs about adding a new configuration parameter]({{< ref "config.md" >}}).
|
||||
|
||||
### cron
|
||||
|
||||
See [how to add a cron task]({{< ref "cron.md" >}}).
|
||||
|
||||
### db
|
||||
|
||||
This package contains the db connection handling and db fixtures for testing.
|
||||
Each other package gets its db connection object from this package.
|
||||
|
||||
### files
|
||||
|
||||
This package is responsible for all file-related things.
|
||||
This means it handles saving and retrieving files from the db and the underlying file system.
|
||||
|
||||
### integration
|
||||
|
||||
All integration tests live here.
|
||||
See [integration tests]({{< ref "test.md" >}}#integration-tests) for more details.
|
||||
|
||||
### log
|
||||
|
||||
Similar to `config`, this will set up the logging, based on different logging backends.
|
||||
This init is called in `main.go` after the config init is done.
|
||||
|
||||
### mail
|
||||
|
||||
This package handles all mail sending. To learn how to send a mail, see [notifications]({{< ref "notifications.md" >}}).
|
||||
|
||||
### metrics
|
||||
|
||||
This package handles all metrics which are exposed to the prometheus endpoint.
|
||||
To learn how it works and how to add new metrics, take a look at [how metrics work]({{< ref "metrics.md">}}).
|
||||
|
||||
### migration
|
||||
|
||||
This package handles all migrations.
|
||||
All migrations are stored and executed in this package.
|
||||
|
||||
To learn more, take a look at the [migrations docs]({{< ref "../development/db-migrations.md">}}).
|
||||
|
||||
### models
|
||||
|
||||
This is where most of the magic happens.
|
||||
When adding new features or upgrading existing ones, that most likely happens here.
|
||||
|
||||
Because this package is pretty huge, there are several documents and how-to's about it:
|
||||
|
||||
* [Adding a feature]({{< ref "feature.md">}})
|
||||
* [Making calls to the database]({{< ref "database.md">}})
|
||||
|
||||
### modules
|
||||
|
||||
Everything that can have multiple implementations (like a task migrator from a third-party task provider) lives in a
|
||||
respective sub package in this package.
|
||||
|
||||
#### auth
|
||||
|
||||
Contains openid related authentication.
|
||||
|
||||
#### avatar
|
||||
|
||||
Contains all possible avatar providers a user can choose to set their avatar.
|
||||
|
||||
#### background
|
||||
|
||||
All project background providers are in sub-packages of this package.
|
||||
|
||||
#### dump
|
||||
|
||||
Handles everything related to the `dump` and `restore` commands of Vikunja.
|
||||
|
||||
#### keyvalue
|
||||
|
||||
A simple key-value store with an implementation for memory and redis.
|
||||
Can be used to cache values.
|
||||
|
||||
#### migration
|
||||
|
||||
See [writing a migrator]({{< ref "migration.md" >}}).
|
||||
|
||||
### red (redis)
|
||||
|
||||
This package initializes a connection to a redis server.
|
||||
This initialization is automatically done at the startup of Vikunja.
|
||||
|
||||
It also has a function (`GetRedis()`) which returns a redis client object you can then use in your package
|
||||
to talk to redis.
|
||||
|
||||
It uses the [go-redis](https://github.com/go-redis/redis) library, please see their configuration on how to use it.
|
||||
|
||||
**Note**: Only use this package directly if you have to use a direct redis connection.
|
||||
In most cases, using the `keyvalue` package is a better fit.
|
||||
|
||||
### routes
|
||||
|
||||
This package defines all routes which are available for Vikunja clients to use.
|
||||
To add a new route, see [adding a new route]({{< ref "feature.md">}}).
|
||||
|
||||
#### api/v1
|
||||
|
||||
This is where all http-handler functions for the api are stored.
|
||||
Every handler function which does not use the standard web handler should live here.
|
||||
|
||||
### swagger
|
||||
|
||||
This is where the [generated]({{< ref "mage.md#generate-swagger-definitions-from-code-comments">}}) [api docs]({{< ref "../usage/api.md">}}) live.
|
||||
You usually don't need to touch this package.
|
||||
|
||||
### user
|
||||
|
||||
All user-related things like registration etc. live in this package.
|
||||
|
||||
### utils
|
||||
|
||||
A small package, containing some helper functions:
|
||||
|
||||
* `MakeRandomString`: Generates a random string of a given length.
|
||||
* `Sha256`: Calculates a sha256 hash from a given string.
|
||||
|
||||
See their function definitions for instructions on how to use them.
|
||||
|
||||
### version
|
||||
|
||||
The single purpose of this package is to hold the current Vikunja version which gets overridden through build flags each time `mage release` or `mage build` is run.
|
||||
It is a separate package to avoid import cycles with other packages.
|
@ -1,96 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Modifying Swagger API Docs"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Modifying swagger api docs
|
||||
|
||||
The api documentation is generated using [swaggo](https://github.com/swaggo/swag) from comments.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Documenting structs
|
||||
|
||||
You should always comment every field which will be exposed as a json in the api.
|
||||
These comments will show up in the documentation, it'll make it easier for developers using the api.
|
||||
|
||||
As an example, this is the definition of a project with all comments:
|
||||
|
||||
```go
|
||||
type Project struct {
|
||||
// The unique, numeric id of this project.
|
||||
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"project"`
|
||||
// The title of the project. You'll see this in the overview.
|
||||
Title string `xorm:"varchar(250) not null" json:"title" valid:"required,runelength(1|250)" minLength:"1" maxLength:"250"`
|
||||
// The description of the project.
|
||||
Description string `xorm:"longtext null" json:"description"`
|
||||
// The unique project short identifier. Used to build task identifiers.
|
||||
Identifier string `xorm:"varchar(10) null" json:"identifier" valid:"runelength(0|10)" minLength:"0" maxLength:"10"`
|
||||
// The hex color of this project
|
||||
HexColor string `xorm:"varchar(6) null" json:"hex_color" valid:"runelength(0|6)" maxLength:"6"`
|
||||
|
||||
OwnerID int64 `xorm:"bigint INDEX not null" json:"-"`
|
||||
ParentProjectID int64 `xorm:"bigint INDEX null" json:"parent_project_id"`
|
||||
ParentProject *Project `xorm:"-" json:"-"`
|
||||
|
||||
// The user who created this project.
|
||||
Owner *user.User `xorm:"-" json:"owner" valid:"-"`
|
||||
|
||||
// Whether a project is archived.
|
||||
IsArchived bool `xorm:"not null default false" json:"is_archived" query:"is_archived"`
|
||||
|
||||
// The id of the file this project has set as background
|
||||
BackgroundFileID int64 `xorm:"null" json:"-"`
|
||||
// Holds extra information about the background set since some background providers require attribution or similar. If not null, the background can be accessed at /projects/{projectID}/background
|
||||
BackgroundInformation interface{} `xorm:"-" json:"background_information"`
|
||||
// Contains a very small version of the project background to use as a blurry preview until the actual background is loaded. Check out https://blurha.sh/ to learn how it works.
|
||||
BackgroundBlurHash string `xorm:"varchar(50) null" json:"background_blur_hash"`
|
||||
|
||||
// True if a project is a favorite. Favorite projects show up in a separate parent project. This value depends on the user making the call to the api.
|
||||
IsFavorite bool `xorm:"-" json:"is_favorite"`
|
||||
|
||||
// The subscription status for the user reading this project. You can only read this property, use the subscription endpoints to modify it.
|
||||
// Will only returned when retrieving one project.
|
||||
Subscription *Subscription `xorm:"-" json:"subscription,omitempty"`
|
||||
|
||||
// The position this project has when querying all projects. See the tasks.position property on how to use this.
|
||||
Position float64 `xorm:"double null" json:"position"`
|
||||
|
||||
// A timestamp when this project was created. You cannot change this value.
|
||||
Created time.Time `xorm:"created not null" json:"created"`
|
||||
// A timestamp when this project was last updated. You cannot change this value.
|
||||
Updated time.Time `xorm:"updated not null" json:"updated"`
|
||||
|
||||
web.CRUDable `xorm:"-" json:"-"`
|
||||
web.Rights `xorm:"-" json:"-"`
|
||||
}
|
||||
```
|
||||
|
||||
## Documenting api Endpoints
|
||||
|
||||
All api routes should be documented with a comment above the handler function.
|
||||
When generating the api docs with mage, the swagger cli will pick these up and put them in a neat document.
|
||||
|
||||
A comment looks like this:
|
||||
|
||||
```go
|
||||
// @Summary Login
|
||||
// @Description Logs a user in. Returns a JWT-Token to authenticate further requests.
|
||||
// @tags user
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param credentials body user.Login true "The login credentials"
|
||||
// @Success 200 {object} auth.Token
|
||||
// @Failure 400 {object} models.Message "Invalid user password model."
|
||||
// @Failure 412 {object} models.Message "Invalid totp passcode."
|
||||
// @Failure 403 {object} models.Message "Invalid username or password."
|
||||
// @Router /login [post]
|
||||
func Login(c echo.Context) error {
|
||||
// Handler logic
|
||||
}
|
||||
```
|
@ -1,109 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Testing"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Testing
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## API Tests
|
||||
|
||||
The following parts are about the kinds of tests in the API package and how to run them.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
To run any kind of test, you need to specify Vikunja's [root path](https://vikunja.io/docs/config-options/#rootpath).
|
||||
This is required to make sure all test fixtures are correctly loaded.
|
||||
|
||||
The easies way to do that is to set the environment variable `VIKUNJA_SERVICE_ROOTPATH` to the path where you cloned the working directory.
|
||||
|
||||
### Unit tests
|
||||
|
||||
To run unit tests with [mage]({{< ref "mage.md">}}), execute
|
||||
|
||||
```
|
||||
mage test:unit
|
||||
```
|
||||
|
||||
In Vikunja, everything that is not an integration test counts as unit test - even if it accesses the db.
|
||||
This definition is a bit blurry, but we haven't found a better one yet.
|
||||
|
||||
### Integration tests
|
||||
|
||||
All integration tests live in `pkg/integrations`.
|
||||
You can run them by executing `mage test:integration`.
|
||||
|
||||
The integration tests use the same config and fixtures as the unit tests and therefore have the same options available,
|
||||
see at the beginning of this document.
|
||||
|
||||
To run integration tests, use `mage test:integration`.
|
||||
|
||||
### Running tests with config
|
||||
|
||||
You can run tests with all available config variables if you want, enabling you to run tests for a lot of scenarios.
|
||||
We use this in CI to run all tests with different databases.
|
||||
|
||||
To use the normal config set the environment variable `VIKUNJA_TESTS_USE_CONFIG=1`.
|
||||
|
||||
### Showing sql queries
|
||||
|
||||
When the environment variable `UNIT_TESTS_VERBOSE=1` is set, all sql queries will be shown during the test run.
|
||||
|
||||
### Fixtures
|
||||
|
||||
All tests are run against a set of db fixtures.
|
||||
These fixtures are defined in `pkg/models/fixtures` in YAML-Files which represent the database structure.
|
||||
|
||||
When you add a new test case which requires new database entries to test against, update these files.
|
||||
|
||||
#### Initializing db fixtures when writing tests
|
||||
|
||||
All db fixtures for all tests live in the `pkg/db/fixtures/` folder as yaml files.
|
||||
Each file has the same name as the table the fixtures are for.
|
||||
You should put new fixtures in this folder.
|
||||
|
||||
When initializing db fixtures, you are responsible for defining which tables your package needs in your test init function.
|
||||
Usually, this is done as follows (this code snippet is taken from the `user` package):
|
||||
|
||||
```go
|
||||
err = db.InitTestFixtures("users")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
In your actual tests, you then load the fixtures into the in-memory db like so:
|
||||
|
||||
```go
|
||||
db.LoadAndAssertFixtures(t)
|
||||
```
|
||||
|
||||
This will load all fixtures you defined in your test init method.
|
||||
You should always use this method to load fixtures, the only exception is when your package tests require extra test
|
||||
fixtures other than db fixtures (like files).
|
||||
|
||||
## Frontend tests
|
||||
|
||||
The frontend has end to end tests with Cypress that use a Vikunja instance and drive a browser against it.
|
||||
Check out the docs [in the frontend repo](https://kolaente.dev/vikunja/vikunja/src/branch/main/frontend/cypress/README.md) about how they work and how to get them running.
|
||||
|
||||
### Unit Tests
|
||||
|
||||
To run the frontend unit tests, run
|
||||
|
||||
```
|
||||
pnpm run test:unit
|
||||
```
|
||||
|
||||
The frontend also has a watcher available that re-runs all unit tests every time you change something.
|
||||
To use it, simply run
|
||||
|
||||
```
|
||||
pnpm run test:unit-watch
|
||||
```
|
@ -1,75 +0,0 @@
|
||||
---
|
||||
title: "German Translation Instructions"
|
||||
date: 2021-06-23T23:47:34+02:00
|
||||
draft: false
|
||||
---
|
||||
|
||||
# German Translation Instructions
|
||||
|
||||
<div class="notification is-warning">
|
||||
<b>NOTE:</b> This document contains translation instructions specific to the german translation of Vikunja.
|
||||
For instructions applicable to all languages, check out the <a href="{{< ref "./translations.md">}}">general translation instructions</a>.
|
||||
</div>
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Allgemein
|
||||
|
||||
Anrede: Wenig förmlich:
|
||||
|
||||
* “Du”-Form
|
||||
* Keine “Amtsdeusch“-Umschreibungen, einfach so als ob man den Nutzer direkt persönlich ansprechen würde
|
||||
|
||||
Genauer definiert:
|
||||
|
||||
* “falsch” anstatt “nicht korrekt/inkorrekt”
|
||||
* “Wende dich an …” anstatt “kontaktiere …”
|
||||
* In derselben Zeit übersetzen (sonst wird aus dem englischen “is“ das deutsche “war”)
|
||||
* Richtige Anführungszeichen verwenden. Also `„“` statt `''` oder `'` oder ` oder ´
|
||||
* `„` für beginnende Anführungszeichen, `“` für schließende Anführungszeichen
|
||||
|
||||
Es gelten Artikel und Worttrennungen aus dem [Duden](https://duden.de).
|
||||
|
||||
## Formulierungen
|
||||
|
||||
* `Account` statt `Konto`.
|
||||
* `TOTP` immer als ein Wort und Groß.
|
||||
* `CalDAV` immer so.
|
||||
* `löschen` oder `entfernen` je nach Kontext. Wenn etwas *gelöscht* wird, existiert das gelöschte Objekt und danach
|
||||
nicht mehr und hat evtl. andere Objekte mitgelöscht (z.B. eine Aufgabe). Wird etwas *entfernt*, bezieht sich das
|
||||
meistens auf die Beziehung zu einem anderen Objekt. Das entfernte Objekt existiert danach immernoch, z.B. beim
|
||||
Entfernen eine:r Nutzer:in aus einem Team.
|
||||
* Analog zu `löschen` oder `entfernen` gilt ähnliches für `hinzufügen` oder `erstellen`. Eine Aufgabe wird *erstellt*,
|
||||
aber ein:e Nutzer:in nur zu einem Team *hinzugefügt*.
|
||||
* `Anmeldename` anstatt `Benutzer:innenname`
|
||||
|
||||
## Formulierungen in Modals und Buttons
|
||||
|
||||
Es sollten die gleichen Formulierungen auf Buttons und Modals verwendet werden.
|
||||
|
||||
Beispiel: Wenn der Button mit `löschen` beschriftet ist, sollte im Modal die Frage
|
||||
lauten `Willst du das wirklich löschen?` und nicht `Willst du das wirklich entfernen?`. Gleiches gilt für
|
||||
Erfolgs/Fehlermeldungen nach der Aktion.
|
||||
|
||||
## Gendern
|
||||
|
||||
Wo möglich, sollte eine geschlechtsneutrale Anrede verwendet werden. Falls diese sehr umständlich würden (siehe oben
|
||||
„Amtsdeutsch-Umschreibungen“), soll mit *Doppelpunkt* gegendert werden.
|
||||
|
||||
Beispiel: „Benutzer:in“
|
||||
|
||||
## Trennungen
|
||||
|
||||
* E-Mail-Adresse (siehe Duden)
|
||||
|
||||
## Wörter und Ausdrücke
|
||||
|
||||
| Englisches Original | Verwendung in deutscher Übersetzung |
|
||||
| ------------------- | -------------------- |
|
||||
| Bucket | Spalte |
|
||||
| Link Share | Linkfreigabe |
|
||||
| Username | Anmeldename |
|
||||
|
||||
## Weiterführende Links
|
||||
|
||||
* https://docs.translatehouse.org/projects/localization-guide/en/latest/guide/translation_guidelines_german.html
|
@ -1,54 +0,0 @@
|
||||
---
|
||||
title: "Translations"
|
||||
date: 2021-06-23T22:52:06+02:00
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "development"
|
||||
---
|
||||
|
||||
# Translations
|
||||
|
||||
This document provides documentation about how to translate Vikunja.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Where to translate
|
||||
|
||||
Translation happens at [crowdin](https://crowdin.com/project/vikunja).
|
||||
|
||||
Currently, only the frontend (and by extension, the desktop app) is translatable.
|
||||
|
||||
## Translation Instructions
|
||||
|
||||
> These are the instructions for translating Vikunja in another language.
|
||||
> For information about how to add new translation strings, see below.
|
||||
|
||||
For all languages these translation guidelines should be applied when translating:
|
||||
|
||||
* Use a less-formal style, as if you were talking to a friend.
|
||||
* If the source string contains characters like `&` or `…`, the translated string should contain them as well.
|
||||
|
||||
More specific instructions for some languages can be found below.
|
||||
|
||||
### Wrong translation strings
|
||||
|
||||
If you encounter a wrong original translation string while translating, please don't correct it in the translation.
|
||||
Instead, translate it to reflect the original meaning in the translated string but add a comment under the source string to discuss potential changes.
|
||||
|
||||
### Language-specific instructions
|
||||
|
||||
* [German]({{< ref "./translation-instructions-german.md">}})
|
||||
|
||||
## How to add new translation strings
|
||||
|
||||
All translation strings are stored in `src/i18n/lang/`.
|
||||
New strings should be added only in the `en.json` file.
|
||||
Strings in other languages will be synced through [crowdin](https://crowdin.com/project/vikunja) and should not be added directly as a PR/commit in the frontend repo.
|
||||
|
||||
## Requesting a new language
|
||||
|
||||
If you want to start translating Vikunja in a language not yet available in Vikunja, please request the language through the crowdin interface.
|
||||
If you have issues with this or need a discussion before doing so, please [contact us](https://vikunja.io/contact/) or [start a discussion in the forum](https://community.vikunja.io).
|
||||
|
||||
Once at least 50% of all translation strings are translated and approved, they will be added and distributed with the Vikunja frontend for users to select and use Vikunja with them.
|
@ -1,59 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "What to backup"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# What to backup
|
||||
|
||||
There are two parts you need to back up: The database and attachment files.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Files
|
||||
|
||||
To back up attachments and other files, it is enough to copy them [from the attachments folder]({{< ref "config.md" >}}#basepath) to some other place.
|
||||
|
||||
## Database
|
||||
|
||||
### MySQL
|
||||
|
||||
To create a backup from mysql use the `mysqldump` command:
|
||||
|
||||
```
|
||||
mysqldump -u <user> -p -h <db-host> <database> > vkunja-backup.sql
|
||||
```
|
||||
|
||||
You will be prompted for the password of the mysql user.
|
||||
|
||||
To restore it, simply pipe it back into the `mysql` command:
|
||||
|
||||
```
|
||||
mysql -u <user> -p -h <db-host> <database> < vkunja-backup.sql
|
||||
```
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
To create a backup from PostgreSQL use the `pg_dump` command:
|
||||
|
||||
```
|
||||
pg_dump -U <user> -h <db-host> <database> > vikunja-backup.sql
|
||||
```
|
||||
|
||||
You might be prompted for the password of the database user.
|
||||
|
||||
To restore it, simply pipe it back into the `psql` command:
|
||||
|
||||
```
|
||||
psql -U <user> -h <db-host> <database> < vikunja-backup.sql
|
||||
```
|
||||
|
||||
For more information, please visit the [relevant PostgreSQL documentation](https://www.postgresql.org/docs/12/backup-dump.html).
|
||||
|
||||
### SQLite
|
||||
|
||||
To back up sqllite databases, it is enough to copy the [database file]({{< ref "config.md" >}}#path) to somewhere else.
|
@ -1,46 +0,0 @@
|
||||
---
|
||||
date: "2022-09-21:00:00+02:00"
|
||||
title: "Build from sources"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# Build Vikunja from source
|
||||
|
||||
To fully build Vikunja from source files, you need to build the api and frontend.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## General Preparations
|
||||
|
||||
1. Make sure you have git installed
|
||||
2. Clone the repo with `git clone https://code.vikunja.io/vikunja` and switch into the directory.
|
||||
3. Check out the version you want to build with `git checkout VERSION` - replace `VERSION` with the version want to use. If you don't do this, you'll build the [latest unstable build]({{< ref "versions.md">}}), which might contain bugs.
|
||||
|
||||
## Frontend
|
||||
|
||||
The code for the frontend is located in the `frontend/` sub folder of the main repo.
|
||||
|
||||
1. Make sure you have [pnpm](https://pnpm.io/installation) properly installed on your system.
|
||||
2. Install all dependencies with `pnpm install`
|
||||
3. Build the frontend with `pnpm run build`. This will result in a static js bundle in the `dist/` folder.
|
||||
4. You can either deploy that static js bundle directly, or read on to learn how to bundle it all up in a static binary with the api.
|
||||
|
||||
## API
|
||||
|
||||
The Vikunja API has no other dependencies than go itself.
|
||||
That means compiling it boils down to these steps:
|
||||
|
||||
1. Make sure [Go](https://golang.org/doc/install) is properly installed on your system. You'll need at least Go `1.21`.
|
||||
2. Make sure [Mage](https://magefile.org) is properly installed on your system.
|
||||
3. If you did not build the frontend in the steps before, you need to either do that or create a dummy index file with `mkdir -p frontend/dist && touch frontend/dist/index.html`.
|
||||
4. Run `mage build` in the source of the main repo. This will build a binary in the root of the repo which will be able to run on your system.
|
||||
|
||||
### Build for different architectures
|
||||
|
||||
To build for other platforms and architectures than the one you're currently on, simply run `mage release` or `mage release:{linux|windows|darwin}`.
|
||||
|
||||
More options are available, please refer to the [magefile docs]({{< ref "../development/mage.md">}}) for more details.
|
File diff suppressed because it is too large
Load Diff
@ -1,30 +0,0 @@
|
||||
---
|
||||
title: "Desktop Packages"
|
||||
date: 2024-02-11T15:58:18+01:00
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# Desktop Packages
|
||||
|
||||
Vikunja is available as an electron-based desktop application for Linux and Windows.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Download the latest release for your platform from [the download page](https://dl.vikunja.io/desktop/).
|
||||
* For Windows, choose the file with the `.exe` or `.msi` file ending
|
||||
* For a Linux-based operating system, choose a file with an ending for your operating system - we have builds for Alpine, AppImage, Arch Linux, Debian-based systems, FreeBSD, Fedora and Snap.
|
||||
2. Run the downloaded package in the same way you would normally install a package for your OS.
|
||||
|
||||
## Flatpack
|
||||
|
||||
Vikunja Desktop can be installed via the [Flathub](https://flathub.org/apps/io.vikunja.Vikunja).
|
||||
|
||||
To install it, run the following command:
|
||||
|
||||
```
|
||||
flatpak install flathub io.vikunja.Vikunja
|
||||
```
|
@ -1,226 +0,0 @@
|
||||
---
|
||||
date: "2020-05-24:00:00+02:00"
|
||||
title: "Docker Walkthrough"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# Setup with docker from start to finish
|
||||
|
||||
This tutorial assumes basic knowledge of docker.
|
||||
It is aimed at beginners and should get you up and running quickly.
|
||||
|
||||
We'll use [docker compose](https://docs.docker.com/compose/) to make handling the bunch of containers easier.
|
||||
|
||||
> If you have any issues setting up vikunja, please don't hesitate to reach out to us via [matrix](https://riot.im/app/#/room/!dCRiCiLaCCFVNlDnYs:matrix.org?via=matrix.org), the [community forum](https://community.vikunja.io/) or even [email](mailto:hello@vikunja.io).
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Preparations (optional)
|
||||
|
||||
Create a directory for the project where all data and the compose file will live in.
|
||||
|
||||
## Create all necessary files
|
||||
|
||||
Create a `docker-compose.yml` file with the following contents in your directory:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
vikunja:
|
||||
image: vikunja/vikunja
|
||||
environment:
|
||||
VIKUNJA_SERVICE_PUBLICURL: http://<the public url where vikunja is reachable>
|
||||
VIKUNJA_DATABASE_HOST: db
|
||||
VIKUNJA_DATABASE_PASSWORD: changeme
|
||||
VIKUNJA_DATABASE_TYPE: mysql
|
||||
VIKUNJA_DATABASE_USER: vikunja
|
||||
VIKUNJA_DATABASE_DATABASE: vikunja
|
||||
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
|
||||
ports:
|
||||
- 3456:3456
|
||||
volumes:
|
||||
- ./files:/app/vikunja/files
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
db:
|
||||
image: mariadb:10
|
||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: supersecret
|
||||
MYSQL_USER: vikunja
|
||||
MYSQL_PASSWORD: changeme
|
||||
MYSQL_DATABASE: vikunja
|
||||
volumes:
|
||||
- ./db:/var/lib/mysql
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h localhost -u $$MYSQL_USER --password=$$MYSQL_PASSWORD"]
|
||||
interval: 2s
|
||||
start_period: 30s
|
||||
```
|
||||
|
||||
This defines two services, each with their own container:
|
||||
|
||||
* A Vikunja service which runs the vikunja api and hosts its frontend.
|
||||
* A database container which will store all projects, tasks, etc. We're using mariadb here, but you're free to use mysql or postgres if you want.
|
||||
|
||||
If you already have a proxy on your host, you may want to check out the [reverse proxy examples]({{< ref "reverse-proxies.md" >}}) to use that.
|
||||
By default, Vikunja will be exposed on port 3456 on the host.
|
||||
|
||||
To change to something different, you'll need to change the `ports` section in the service definition.
|
||||
The number before the colon is the host port - This is where you can reach vikunja from the outside once all is up and running.
|
||||
|
||||
You'll need to change the value of the `VIKUNJA_SERVICE_PUBLICURL` environment variable to the public port or hostname where Vikunja is reachable.
|
||||
|
||||
## Ensure adequate file permissions
|
||||
|
||||
Vikunja runs as user `1000` and no group by default.
|
||||
|
||||
To be able to upload task attachments or change the background of project, Vikunja must be able to write into the `files` directory.
|
||||
To do this, create the folder and chown it before starting the stack:
|
||||
|
||||
```
|
||||
mkdir $PWD/files
|
||||
chown 1000 $PWD/files
|
||||
```
|
||||
|
||||
## Run it
|
||||
|
||||
Run `sudo docker-compose up` in your directory and take a look at the output you get.
|
||||
When first started, Vikunja will set up the database and run all migrations etc.
|
||||
Once it is ready, you should see a message like this one in your console:
|
||||
|
||||
```
|
||||
vikunja_1 | 2024-02-09T14:44:06.990677157+01:00: INFO ▶ cmd/func29 05d Vikunja version 0.23.0
|
||||
vikunja_1 | ⇨ http server started on [::]:3456
|
||||
```
|
||||
|
||||
This indicates all setup has been successful.
|
||||
If you get any errors, see below:
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
Vikunja might not run on the first try.
|
||||
There are a few potential issues that could be causing this.
|
||||
|
||||
#### No connection to the database
|
||||
|
||||
Indicated by an error message like this one from the api container:
|
||||
|
||||
```
|
||||
2020/05/23 15:37:59 Config File "config" Not Found in "[/app/vikunja /etc/vikunja /app/vikunja/.config/vikunja]"
|
||||
2020/05/23 15:37:59 Using default config.
|
||||
2020-05-23T15:37:59.974435725Z: CRITICAL ▶ migration/Migrate 002 Migration failed: dial tcp 172.19.0.2:3306: connect: connection refused
|
||||
```
|
||||
|
||||
Especially when using mysql, this can happen on first start, because the mysql database container will take a few seconds to start.
|
||||
Vikunja does not know the container is not ready, therefore it will just try to connect to the db, fail since it is not ready and exit.
|
||||
|
||||
If you're using the docker compose example from above, you may notice the `restart: unless-stopped` option at the api service.
|
||||
This tells docker to restart the api container if it exits, unless you explicitly stop it.
|
||||
Therefore, it should "magically fix itself" by automatically restarting the container.
|
||||
|
||||
After a few seconds (or minutes) you should see a log message like this one from the mariadb container:
|
||||
|
||||
```
|
||||
2020-05-24 11:42:15 0 [Note] mysqld: ready for connections.
|
||||
Version: '10.4.12-MariaDB-1:10.4.12+maria~bionic' socket: '/var/run/mysqld/mysqld.sock' port: 3306 mariadb.org binary distribution
|
||||
```
|
||||
|
||||
The next restart of Vikunja should be successful.
|
||||
If not, there might be a different error or a bug with Vikunja, please reach out to us in that case.
|
||||
|
||||
(If you have an idea about how we could improve this, we'd like to hear it!)
|
||||
|
||||
#### Migration failed: commands out of sync
|
||||
|
||||
If you get an error like this one:
|
||||
|
||||
```
|
||||
2020/05/23 15:53:38 Config File "config" Not Found in "[/app/vikunja /etc/vikunja /app/vikunja/.config/vikunja]"
|
||||
2020/05/23 15:53:38 Using default config.
|
||||
2020-05-23T15:53:38.762747276Z: CRITICAL ▶ migration/Migrate 002 Migration failed: commands out of sync. Did you run multiple statements at once?
|
||||
```
|
||||
|
||||
This is a mysql issue.
|
||||
Currently, we don't have a better solution than to completely wipe the database files and start over.
|
||||
To do this, first stop everything by running `sudo docker-compose down`, then remove the `db/` folder in your current folder with `sudo rm -rf db` and start the whole stack again with `sudo docker-compose up -d`.
|
||||
|
||||
## Try it
|
||||
|
||||
Head over to `http://<host-ip or url>/api/v1/info` in a browser.
|
||||
You should see something like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "v0.23.0",
|
||||
"frontend_url": "https://try.vikunja.io/",
|
||||
"motd": "",
|
||||
"link_sharing_enabled": true,
|
||||
"max_file_size": "20MB",
|
||||
"registration_enabled": true,
|
||||
"available_migrators": [
|
||||
"vikunja-file",
|
||||
"ticktick",
|
||||
"todoist"
|
||||
],
|
||||
"task_attachments_enabled": true,
|
||||
"enabled_background_providers": [
|
||||
"upload",
|
||||
"unsplash"
|
||||
],
|
||||
"totp_enabled": false,
|
||||
"legal": {
|
||||
"imprint_url": "",
|
||||
"privacy_policy_url": ""
|
||||
},
|
||||
"caldav_enabled": true,
|
||||
"auth": {
|
||||
"local": {
|
||||
"enabled": true
|
||||
},
|
||||
"openid_connect": {
|
||||
"enabled": false,
|
||||
"providers": null
|
||||
}
|
||||
},
|
||||
"email_reminders_enabled": true,
|
||||
"user_deletion_enabled": true,
|
||||
"task_comments_enabled": true,
|
||||
"demo_mode_enabled": true,
|
||||
"webhooks_enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
This shows you can reach the api through the api proxy.
|
||||
|
||||
Now head over to `http://<host-ip or url>/` which should show the login mask.
|
||||
|
||||
## Make it persistent
|
||||
|
||||
Currently, Vikunja runs in foreground in your terminal.
|
||||
For a real-world scenario this is not the best way.
|
||||
|
||||
Back in your terminal, stop the stack by pressing `CTRL-C` on your keyboard.
|
||||
Then run `sudo docker-compose up -d` in your again.
|
||||
The `-d` flag at the end of the command will tell docker to run the containers in the background.
|
||||
If you need to check the logs after that, you can run `sudo docker-compose logs`.
|
||||
|
||||
Vikunja does not have any default users, you'll need to register and account.
|
||||
After that, you can use it.
|
||||
|
||||
## Tear it all down
|
||||
|
||||
If you want to completely stop all containers run `sudo docker-compose down` in your terminal.
|
||||
|
||||
## Improve this guide
|
||||
|
||||
We'll happily accept suggestions and improvements for this guide.
|
||||
Please [reach out to us](https://vikunja.io/contact/) if you have any.
|
@ -1,354 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Full docker example"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# Full docker example
|
||||
|
||||
This docker compose configuration will run Vikunja with a mariadb database.
|
||||
It uses a proxy configuration to make it available under a domain.
|
||||
|
||||
For all available configuration options, see [configuration]({{< ref "config.md">}}).
|
||||
|
||||
After registering all your users, you might also want to [disable the user registration]({{<ref "config.md">}}#enableregistration).
|
||||
|
||||
<div class="notification is-warning">
|
||||
<b>NOTE:</b> If you intend to run Vikunja with mysql and/or to use non-latin characters
|
||||
<a href="{{< ref "utf-8.md">}}">make sure your db is utf-8 compatible</a>.<br/>
|
||||
All examples on this page already reflect this and do not require additional work.
|
||||
</div>
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## File permissions
|
||||
|
||||
Vikunja runs as user `1000` and no group by default.
|
||||
You can use Docker's [`--user`](https://docs.docker.com/engine/reference/run/#user) flag to change that.
|
||||
|
||||
You must ensure Vikunja is able to write into the `files` directory.
|
||||
To do this, create the folder and chown it before starting the stack:
|
||||
|
||||
```
|
||||
mkdir $PWD/files
|
||||
chown 1000 $PWD/files
|
||||
```
|
||||
|
||||
You'll need to do this before running any of the examples on this page.
|
||||
|
||||
Vikunja will not try to acquire ownership of the files folder, as that would mean it had to run as root.
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
Vikunja supports postgres, mysql and sqlite as a database backend. The examples on this page use mysql with a mariadb container.
|
||||
To use postgres as a database backend, change the `db` section of the examples to this:
|
||||
|
||||
```yaml
|
||||
db:
|
||||
image: postgres:16
|
||||
environment:
|
||||
POSTGRES_PASSWORD: changeme
|
||||
POSTGRES_USER: vikunja
|
||||
volumes:
|
||||
- ./db:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -h localhost -U $$POSTGRES_USER"]
|
||||
interval: 2s
|
||||
```
|
||||
|
||||
You'll also need to change the `VIKUNJA_DATABASE_TYPE` to `postgres` on the api container declaration.
|
||||
|
||||
## Sqlite
|
||||
|
||||
Vikunja supports postgres, mysql and sqlite as a database backend. The examples on this page use mysql with a mariadb container.
|
||||
To use sqlite as a database backend, change the `api` section of the examples to this:
|
||||
|
||||
```yaml
|
||||
vikunja:
|
||||
image: vikunja/vikunja
|
||||
environment:
|
||||
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
|
||||
VIKUNJA_SERVICE_PUBLICURL: http://<your public frontend url with slash>/
|
||||
# Note the default path is /app/vikunja/vikunja.db.
|
||||
# This config variable moves it to a different folder so you can use a volume and
|
||||
# store the database file outside the container so state is persisted even if the container is destroyed.
|
||||
VIKUNJA_DATABASE_PATH: /db/vikunja.db
|
||||
ports:
|
||||
- 3456:3456
|
||||
volumes:
|
||||
- ./files:/app/vikunja/files
|
||||
- ./db:/db
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
The default path Vikunja uses for sqlite is relative to the binary, which in the docker container would be `/app/vikunja/vikunja.db`.
|
||||
The `VIKUNJA_DATABASE_PATH` environment variable moves changes it so that the database file is stored in a volume at `/db`, to persist state across restarts.
|
||||
|
||||
You'll also need to remove or change the `VIKUNJA_DATABASE_TYPE` to `sqlite` on the container declaration.
|
||||
|
||||
You can also remove the db section.
|
||||
|
||||
To run the container, you need to create the directories first and make sure they have all required permissions:
|
||||
|
||||
```
|
||||
mkdir $PWD/files $PWD/db
|
||||
chown 1000 $PWD/files $PWD/db
|
||||
```
|
||||
|
||||
<div class="notification is-warning">
|
||||
<b>NOTE:</b> If you'll use your instance with more than a handful of users, we recommend using mysql or postgres.
|
||||
</div>
|
||||
|
||||
## Example without any proxy
|
||||
|
||||
This example lets you host Vikunja without any reverse proxy in front of it.
|
||||
This is the absolute minimum configuration you need to get something up and running.
|
||||
If you want to make Vikunja available on a domain or need tls termination, check out one of the other examples.
|
||||
|
||||
Note that you need to change the [`VIKUNJA_SERVICE_PUBLICURL`]({{< ref "config.md" >}}#publicurl) environment variable to the public ip or hostname including the port (the docker host you're running this on) is reachable at, prefixed with `http://`.
|
||||
Because the browser you'll use to access the Vikunja frontend uses that url to make the requests, it has to be able to reach it from the outside.
|
||||
|
||||
<div class="notification is-warning">
|
||||
<b>NOTE:</b> You must ensure Vikunja has write permissions on the `files` directory before starting the stack.
|
||||
To do this, <a href="#file-permissions">check out the related commands here</a>.
|
||||
</div>
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
vikunja:
|
||||
image: vikunja/vikunja
|
||||
environment:
|
||||
VIKUNJA_SERVICE_PUBLICURL: http://<the public ip or host where vikunja is reachable>
|
||||
VIKUNJA_DATABASE_HOST: db
|
||||
VIKUNJA_DATABASE_PASSWORD: changeme
|
||||
VIKUNJA_DATABASE_TYPE: mysql
|
||||
VIKUNJA_DATABASE_USER: vikunja
|
||||
VIKUNJA_DATABASE_DATABASE: vikunja
|
||||
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
|
||||
ports:
|
||||
- 3456:3456
|
||||
volumes:
|
||||
- ./files:/app/vikunja/files
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
db:
|
||||
image: mariadb:10
|
||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: supersecret
|
||||
MYSQL_USER: vikunja
|
||||
MYSQL_PASSWORD: changeme
|
||||
MYSQL_DATABASE: vikunja
|
||||
volumes:
|
||||
- ./db:/var/lib/mysql
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h localhost -u $$MYSQL_USER --password=$$MYSQL_PASSWORD"]
|
||||
interval: 2s
|
||||
start_period: 30s
|
||||
```
|
||||
|
||||
## Example with Traefik 2
|
||||
|
||||
This example assumes [traefik](https://traefik.io) version 2 installed and configured to [use docker as a configuration provider](https://docs.traefik.io/providers/docker/).
|
||||
|
||||
We also make a few assumptions here which you'll most likely need to adjust for your traefik setup:
|
||||
|
||||
* Your domain is `vikunja.example.com`
|
||||
* The entrypoint you want to make vikunja available from is called `https`
|
||||
* The tls cert resolver is called `acme`
|
||||
|
||||
<div class="notification is-warning">
|
||||
<b>NOTE:</b> You must ensure Vikunja has write permissions on the `files` directory before starting the stack.
|
||||
To do this, <a href="#file-permissions">check out the related commands here</a>.
|
||||
</div>
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
vikunja:
|
||||
image: vikunja/vikunja
|
||||
environment:
|
||||
VIKUNJA_SERVICE_PUBLICURL: http://<the public url where vikunja is reachable>
|
||||
VIKUNJA_DATABASE_HOST: db
|
||||
VIKUNJA_DATABASE_PASSWORD: changeme
|
||||
VIKUNJA_DATABASE_TYPE: mysql
|
||||
VIKUNJA_DATABASE_USER: vikunja
|
||||
VIKUNJA_DATABASE_DATABASE: vikunja
|
||||
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
|
||||
volumes:
|
||||
- ./files:/app/vikunja/files
|
||||
networks:
|
||||
- web
|
||||
- default
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=web"
|
||||
- "traefik.http.routers.vikunja.rule=Host(`vikunja.example.com`)"
|
||||
- "traefik.http.routers.vikunja.entrypoints=https"
|
||||
- "traefik.http.routers.vikunja.tls.certResolver=acme"
|
||||
db:
|
||||
image: mariadb:10
|
||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: supersupersecret
|
||||
MYSQL_USER: vikunja
|
||||
MYSQL_PASSWORD: changeme
|
||||
MYSQL_DATABASE: vikunja
|
||||
volumes:
|
||||
- ./db:/var/lib/mysql
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h localhost -u $$MYSQL_USER --password=$$MYSQL_PASSWORD"]
|
||||
interval: 2s
|
||||
start_period: 30s
|
||||
|
||||
networks:
|
||||
web:
|
||||
external: true
|
||||
```
|
||||
|
||||
## Example with Caddy v2 as proxy
|
||||
|
||||
You will need the following `Caddyfile` on your host (or elsewhere, but then you'd need to adjust the proxy mount at the bottom of the compose file):
|
||||
|
||||
```conf
|
||||
vikunja.example.com {
|
||||
reverse_proxy api:3456
|
||||
}
|
||||
```
|
||||
|
||||
Note that you need to change the [`VIKUNJA_SERVICE_PUBLICURL`]({{< ref "config.md" >}}#publicurl) environment variable to the ip (the docker host you're running this on) is reachable at.
|
||||
Because the browser you'll use to access the Vikunja frontend uses that url to make the requests, it has to be able to reach that ip + port from the outside.
|
||||
|
||||
<div class="notification is-warning">
|
||||
<b>NOTE:</b> You must ensure Vikunja has write permissions on the `files` directory before starting the stack.
|
||||
To do this, <a href="#file-permissions">check out the related commands here</a>.
|
||||
</div>
|
||||
|
||||
Docker Compose config:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
vikunja:
|
||||
image: vikunja/vikunja
|
||||
environment:
|
||||
VIKUNJA_SERVICE_PUBLICURL: http://<the public url where vikunja is reachable>
|
||||
VIKUNJA_DATABASE_HOST: db
|
||||
VIKUNJA_DATABASE_PASSWORD: changeme
|
||||
VIKUNJA_DATABASE_TYPE: mysql
|
||||
VIKUNJA_DATABASE_USER: vikunja
|
||||
VIKUNJA_DATABASE_DATABASE: vikunja
|
||||
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
|
||||
ports:
|
||||
- 3456:3456
|
||||
volumes:
|
||||
- ./files:/app/vikunja/files
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
db:
|
||||
image: mariadb:10
|
||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: supersecret
|
||||
MYSQL_USER: vikunja
|
||||
MYSQL_PASSWORD: changeme
|
||||
MYSQL_DATABASE: vikunja
|
||||
volumes:
|
||||
- ./db:/var/lib/mysql
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h localhost -u $$MYSQL_USER --password=$$MYSQL_PASSWORD"]
|
||||
interval: 2s
|
||||
start_period: 30s
|
||||
caddy:
|
||||
image: caddy
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
depends_on:
|
||||
- api
|
||||
- frontend
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
```
|
||||
|
||||
## Setup on a Synology NAS
|
||||
|
||||
There is a proxy preinstalled in DSM, so if you want to access Vikunja from outside,
|
||||
you need to prepare a proxy rule the Vikunja Service.
|
||||
|
||||

|
||||
|
||||
You should also add 2 empty folders for mariadb and vikunja inside Synology's
|
||||
docker main folders:
|
||||
|
||||
* Docker
|
||||
* vikunja
|
||||
* mariadb
|
||||
|
||||
Synology has its own GUI for managing Docker containers, but it's easier via docker compose.
|
||||
|
||||
To do that, you can
|
||||
|
||||
* Either activate SSH and paste the adapted compose file in a terminal (using Putty or similar)
|
||||
* Without activating SSH as a "custom script" (go to Control Panel / Task Scheduler / Create / Scheduled Task / User-defined script)
|
||||
* Without activating SSH, by using Portainer (you have to install first, check out [this tutorial](https://www.portainer.io/blog/how-to-install-portainer-on-a-synology-nas) for example):
|
||||
1. Go to **Dashboard / Stacks** click the button **"Add Stack"**
|
||||
2. Give it the name Vikunja and paste the adapted docker compose file
|
||||
3. Deploy the Stack with the "Deploy Stack" button:
|
||||
|
||||

|
||||
|
||||
The docker-compose file we're going to use is exactly the same from the [example without any proxy](#example-without-any-proxy) above.
|
||||
|
||||
You may want to change the volumes to match the rest of your setup.
|
||||
|
||||
After registering all your users, you might also want to [disable the user registration]({{<ref "config.md">}}#enableregistration).
|
||||
|
||||
<div class="notification is-warning">
|
||||
<b>NOTE:</b> You must ensure Vikunja has write permissions on the `files` directory before starting the stack.
|
||||
To do this, <a href="#file-permissions">check out the related commands here</a>.
|
||||
</div>
|
||||
|
||||
## Redis
|
||||
|
||||
While Vikunja has support to use redis as a caching backend, you'll probably not need it unless you're using Vikunja with more than a handful of users.
|
||||
|
||||
To use redis, you'll need to add this to the config examples below:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
vikunja:
|
||||
image: vikunja/vikunja
|
||||
environment:
|
||||
VIKUNJA_REDIS_ENABLED: 1
|
||||
VIKUNJA_REDIS_HOST: 'redis:6379'
|
||||
VIKUNJA_CACHE_ENABLED: 1
|
||||
VIKUNJA_CACHE_TYPE: redis
|
||||
volumes:
|
||||
- ./files:/app/vikunja/files
|
||||
redis:
|
||||
image: redis
|
||||
```
|
@ -1,318 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Installing"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
weight: 10
|
||||
---
|
||||
|
||||
# Installing
|
||||
|
||||
Architecturally, Vikunja is made up of two parts: [API](https://code.vikunja.io/api) and [frontend](https://code.vikunja.io/api/frontend).
|
||||
|
||||
Both are bundled into one single deployable binary (or docker container).
|
||||
That means you only need to install one thing to be able to use Vikunja.
|
||||
|
||||
You can also:
|
||||
|
||||
* Use the desktop app, which is essentially the web frontend packaged for easy installation on desktop devices
|
||||
* Use the mobile app only, but as of right now it only supports the very basic features of Vikunja
|
||||
|
||||
<div class="notification is-warning">
|
||||
<b>NOTE:</b> If you intend to run Vikunja with mysql and/or to use non-latin characters
|
||||
<a href="{{< ref "utf-8.md">}}">make sure your db is utf-8 compatible</a>.
|
||||
</div>
|
||||
|
||||
Vikunja can be installed in various ways.
|
||||
This document provides an overview and instructions for the different methods:
|
||||
|
||||
* [Installing from binary (manual)](#install-from-binary)
|
||||
* [Build from source]({{< ref "build-from-source.md">}})
|
||||
* [Docker](#docker)
|
||||
* [Debian](#debian-packages)
|
||||
* [RPM](#rpm)
|
||||
* [FreeBSD](#freebsd--freenas)
|
||||
* [Kubernetes]({{< ref "k8s.md" >}})
|
||||
|
||||
And after you installed Vikunja, you may want to check out these other resources:
|
||||
|
||||
* [Configuration]({{< ref "config.md">}})
|
||||
* [UTF-8 Settings]({{< ref "utf-8.md">}})
|
||||
* [Reverse proxies]({{< ref "reverse-proxies.md">}})
|
||||
* [Full docker example]({{< ref "full-docker-example.md">}})
|
||||
* [Backups]({{< ref "backups.md">}})
|
||||
|
||||
## Install from binary
|
||||
|
||||
Download a copy of Vikunja from the [download page](https://dl.vikunja.io/vikunja) for your architecture.
|
||||
|
||||
```
|
||||
wget <download-url>
|
||||
```
|
||||
|
||||
### Verify the GPG signature
|
||||
|
||||
All releases are signed using GPG.
|
||||
|
||||
To validate the downloaded zip file use the signiture file `.asc` and the key `FF054DACD908493A`:
|
||||
|
||||
```
|
||||
gpg --keyserver keyserver.ubuntu.com --recv FF054DACD908493A
|
||||
gpg --verify vikunja-<vikunja version>-linux-amd64-full.zip.asc vikunja-<vikunja version>-linux-amd64-full.zip
|
||||
```
|
||||
|
||||
### Set it up
|
||||
|
||||
Once you've verified the signature, you need to unzip and make it executable.
|
||||
You'll also need to create a symlink to the binary, so that you can execute Vikunja by typing `vikunja` on your system.
|
||||
We'll install vikunja to `/opt/vikunja`, change the path where needed if you want to install it elsewhere.
|
||||
|
||||
Run these commands to install it:
|
||||
|
||||
```
|
||||
mkdir -p /opt/vikunja
|
||||
unzip <vikunja-zip-file> -d /opt/vikunja
|
||||
chmod +x /opt/vikunja
|
||||
sudo ln -s /opt/vikunja/vikunja /usr/bin/vikunja
|
||||
```
|
||||
|
||||
### Systemd service
|
||||
|
||||
To automatically start Vikunja when your system boots and to ensure all dependent services are met, you want to use an init system like systemd.
|
||||
|
||||
Save the following service file to `/etc/systemd/system/vikunja.service` and adapt it to your needs:
|
||||
|
||||
```unit file (systemd)
|
||||
[Unit]
|
||||
Description=Vikunja
|
||||
After=syslog.target
|
||||
After=network.target
|
||||
# Depending on how you configured Vikunja, you may want to uncomment these:
|
||||
#Requires=mysql.service
|
||||
#Requires=mariadb.service
|
||||
#Requires=postgresql.service
|
||||
#Requires=redis.service
|
||||
|
||||
[Service]
|
||||
RestartSec=2s
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/vikunja
|
||||
ExecStart=/usr/bin/vikunja
|
||||
Restart=always
|
||||
# If you want to bind Vikunja to a port below 1024 uncomment
|
||||
# the two values below
|
||||
###
|
||||
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
#AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
If you've installed Vikunja to a directory other than `/opt/vikunja`, you need to adapt `WorkingDirectory` accordingly.
|
||||
|
||||
After you made all necessary modifications, it's time to start the service:
|
||||
|
||||
```
|
||||
sudo systemctl enable vikunja
|
||||
sudo systemctl start vikunja
|
||||
```
|
||||
|
||||
### Build from source
|
||||
|
||||
To build vikunja from source, see [building from source]({{< ref "build-from-source.md">}}).
|
||||
|
||||
### Updating
|
||||
|
||||
[Make a backup first]({{< ref "backups.md" >}}).
|
||||
|
||||
Simply replace the binary with the new version, then restart Vikunja.
|
||||
It will automatically run all necessary database migrations.
|
||||
**Make sure to take a look at the changelog for the new version to not miss any manual steps the update may involve!**
|
||||
|
||||
## Docker
|
||||
|
||||
(Note: this assumes some familiarity with docker)
|
||||
|
||||
To get up and running quickly, use this command:
|
||||
|
||||
```
|
||||
mkdir $PWD/files $PWD/db
|
||||
chown 1000 $PWD/files $PWD/db
|
||||
docker run -p 3456:3456 -v $PWD/files:/app/vikunja/files -v $PWD/db:/db vikunja/vikunja
|
||||
```
|
||||
|
||||
This will expose vikunja on port `3456` on the host running the container and use sqlite as database backend.
|
||||
|
||||
**Note**: The container runs as the user `1000` and no group by default.
|
||||
You can use Docker's [`--user`](https://docs.docker.com/engine/reference/run/#user) flag to change that.
|
||||
Make sure the new user has required permissions on the `db` and `files` folder.
|
||||
|
||||
You can mount a local configuration like so:
|
||||
|
||||
```
|
||||
mkdir $PWD/files $PWD/db
|
||||
chown 1000 $PWD/files $PWD/db
|
||||
docker run -p 3456:3456 -v /path/to/config/on/host.yml:/app/vikunja/config.yml:ro -v $PWD/files:/app/vikunja/files -v $PWD/db:/db vikunja/vikunja
|
||||
```
|
||||
|
||||
Though it is recommended to use environment variables or `.env` files to configure Vikunja in docker.
|
||||
See [config]({{< ref "config.md">}}) for a list of available configuration options.
|
||||
|
||||
Check out the [docker examples]({{<ref "full-docker-example.md">}}) for more advanced configuration using mysql / postgres and a reverse proxy.
|
||||
|
||||
### Files volume
|
||||
|
||||
By default, the container stores all files uploaded and used through vikunja inside of `/app/vikunja/files` which is created as a docker volume.
|
||||
You should mount the volume somewhere to the host to permanently store the files and don't lose them if the container restarts.
|
||||
|
||||
### Docker compose
|
||||
|
||||
Check out the [docker examples]({{<ref "full-docker-example.md">}}) for more advanced configuration using docker compose.
|
||||
|
||||
## Debian packages
|
||||
|
||||
Vikunja is available as deb package for installation on debian-like systems.
|
||||
|
||||
To install these, grab a `.deb` file from [the download page](https://dl.vikunja.io/vikunja) and run
|
||||
|
||||
```
|
||||
dpkg -i vikunja.deb
|
||||
```
|
||||
|
||||
This will install Vikunja to `/opt/vikunja`.
|
||||
To configure it, use the config file in `/etc/vikunja/config.yml`.
|
||||
|
||||
## RPM
|
||||
|
||||
Vikunja is available as rpm package for installation on Fedora, CentOS and others.
|
||||
|
||||
To install these, grab a `.rpm` file from [the download page](https://dl.vikunja.io/vikunja) and run
|
||||
|
||||
```
|
||||
rpm -i vikunja.rpm
|
||||
```
|
||||
|
||||
To configure Vikunja, use the config file in `/etc/vikunja/config.yml`.
|
||||
|
||||
## FreeBSD / FreeNAS
|
||||
|
||||
Unfortunately, we currently can't provide pre-built binaries for FreeBSD.
|
||||
As a workaround, it is possible to compile vikunja for FreeBSD directly on a FreeBSD machine, a guide is available below:
|
||||
|
||||
*Thanks to HungrySkeleton who originally created this guide [in the forum](https://community.vikunja.io/t/freebsd-support/69/11).*
|
||||
|
||||
### Jail Setup
|
||||
|
||||
1. Create a jail named `vikunja`
|
||||
2. Set jail properties to 'auto start'
|
||||
3. Mount storage (`/mnt` to `jailData/vikunja`)
|
||||
4. Start jail & SSH into it
|
||||
|
||||
### Installing packages
|
||||
|
||||
```
|
||||
pkg update && pkg upgrade -y
|
||||
pkg install nano git go gmake
|
||||
go install github.com/magefile/mage
|
||||
```
|
||||
|
||||
### Clone vikunja repo
|
||||
|
||||
```
|
||||
mkdir /mnt/GO/code.vikunja.io
|
||||
cd /mnt/GO/code.vikunja.io
|
||||
git clone https://code.vikunja.io/vikunja
|
||||
cd vikunja
|
||||
```
|
||||
|
||||
**Note:** Check out the version you want to build with `git checkout VERSION` - replace `VERSION` with the version want to use.
|
||||
If you don't do this, you'll build the [latest unstable build]({{< ref "versions.md">}}), which might contain bugs.
|
||||
|
||||
### Compile binaries
|
||||
|
||||
```
|
||||
cd frontend
|
||||
pnpm install
|
||||
pnpm run build
|
||||
cd ..
|
||||
mage build
|
||||
```
|
||||
|
||||
### Create folder to install Vikunja into
|
||||
|
||||
```
|
||||
mkdir /mnt/vikunja
|
||||
cp /mnt/GO/code.vikunja.io/api/vikunja /mnt/vikunja
|
||||
cd /mnt/vikunja
|
||||
chmod +x /mnt/vikunja
|
||||
```
|
||||
|
||||
### Set vikunja to boot on startup
|
||||
|
||||
```
|
||||
nano /etc/rc.d/vikunja
|
||||
```
|
||||
|
||||
Then paste into the file:
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
|
||||
. /etc/rc.subr
|
||||
|
||||
name=vikunja
|
||||
rcvar=vikunja_enable
|
||||
|
||||
command="/mnt/vikunja/${name}"
|
||||
|
||||
load_rc_config $name
|
||||
run_rc_command "$1"
|
||||
```
|
||||
|
||||
Save and exit. Then execute:
|
||||
|
||||
```
|
||||
chmod +x /etc/rc.d/vikunja
|
||||
nano /etc/rc.conf
|
||||
```
|
||||
|
||||
Then add line to bottom of file:
|
||||
|
||||
```
|
||||
vikunja_enable="YES"
|
||||
```
|
||||
|
||||
Test vikunja now works with
|
||||
|
||||
```
|
||||
service vikunja start
|
||||
```
|
||||
|
||||
Vikunja is now available through IP:
|
||||
|
||||
```
|
||||
192.168.1.XXX:3456
|
||||
```
|
||||
|
||||
## Other installation resources
|
||||
|
||||
* [Docker Compose is MUCH Easier Than you Think - Let's Install Vikunja](https://www.youtube.com/watch?v=fGlz2PkXjuo) (Youtube)
|
||||
* [Setup Vikunja using Docker Compose - Homelab Wiki](https://thehomelab.wiki/books/docker/page/setup-vikunja-using-docker-compose)
|
||||
* [A Closer look at Vikunja - Email Notifications - Enable or Disable Registrations - Allow Attachments](https://www.youtube.com/watch?v=47wj9pRT6Gw) (Youtube)
|
||||
* [Install Vikunja in Docker for self-hosted Task Tracking](https://smarthomepursuits.com/install-vikunja-in-docker-for-self-hosted-task-tracking/)
|
||||
* [Self-Hosted To-Do List with Vikunja in Docker](https://www.youtube.com/watch?v=DqyqDWpEvKI) (Youtube)
|
||||
* [Vikunja self-hosted (step by step)](https://nguyenminhhung.com/vikunja-self-hosted-step-by-step/)
|
||||
* [How to Install Vikunja on Your Synology NAS](https://mariushosting.com/how-to-install-vikunja-on-your-synology-nas/)
|
||||
|
||||
## Configuration
|
||||
|
||||
See [available configuration options]({{< ref "config.md">}}).
|
||||
|
||||
## Default Password
|
||||
|
||||
After successfully installing Vikunja, there is no default user or password.
|
||||
You only need to register a new account and set all the details when creating it.
|
@ -1,22 +0,0 @@
|
||||
---
|
||||
title: "Hosting Vikunja with k8s"
|
||||
date: 2022-08-12T13:41:48+02:00
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# Hosting Vikunja with k8s
|
||||
|
||||
We have an official Helm Chart for Vikunja.
|
||||
|
||||
Check out [the repo](https://kolaente.dev/vikunja/helm-chart/) for more information about how to use it.
|
||||
|
||||
## Third-party Helm Charts
|
||||
|
||||
There are two third-party Helm-Charts which can be used to host Vikunja with k8s:
|
||||
|
||||
* [Truecharts](https://truecharts.org/charts/stable/vikunja/)
|
||||
* [k8s at Home](https://github.com/k8s-at-home/charts)
|
@ -1,57 +0,0 @@
|
||||
---
|
||||
date: "2023-03-09:00:00+02:00"
|
||||
title: "Migration from third-party services"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
weight: 5
|
||||
---
|
||||
|
||||
# Migration from third-party services
|
||||
|
||||
There are several importers available for third-party services like Trello, Microsoft To Do or Todoist.
|
||||
All available migration options can be found [here](https://kolaente.dev/vikunja/vikunja/src/branch/main/config.yml.sample#L218).
|
||||
|
||||
You can develop migrations for more services, see the [documentation]({{< ref "../development/migration.md">}}) for more info.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Trello
|
||||
|
||||
### Config Setup
|
||||
|
||||
Log into Trello and navigate to the [site](https://trello.com/app-key) to manage your API keys.
|
||||
Save your `Personal Key` for later and add your Vikunja domain to the Allowed Origins list.
|
||||
|
||||
Create a `config.yml` file based on [default config file](https://kolaente.dev/vikunja/vikunja/src/branch/main/config.yml.sample) if you haven't already.
|
||||
|
||||
- Copy the [Trello options](https://kolaente.dev/vikunja/vikunja/src/branch/main/config.yml.sample#L233) from the default config file
|
||||
- Set `enable` to true
|
||||
- Set `key` to your [trello API key](https://trello.com/app-key)
|
||||
- Replace `<frontend url>` in `redirecturl` with your url
|
||||
|
||||
### Config Loading
|
||||
|
||||
To load the config with Vikunja, see the [installation]({{< ref "install.md">}}) documentation for instructions to load the `config.yml` file and start Vikunja.
|
||||
|
||||
### Config Loading with Docker Compose
|
||||
|
||||
In case you are using Docker Compose you need to edit `docker-compose.yml` to load `config.yml`.
|
||||
Mount the `config.yml` file into the Vikunja container, by adding this line to the volumes of the Vikunja container and replacing the `./path/to/config.yml` with the relative path from the `docker-compose.yml` to your `config.yml`.
|
||||
```yaml
|
||||
volumes:
|
||||
- ./path/to/config.yml:/etc/vikunja/config.yml
|
||||
```
|
||||
|
||||
After all the setup is done, start Vikunja as shown in the [Docker Compose setup]({{< ref "full-docker-example.md">}}).
|
||||
|
||||
### Start the Migration Process
|
||||
|
||||
Log in, and navigate to Settings > Import from other services. In the list of available third-party services, there should be a Trello icon now.
|
||||
If not, ensure that you are properly loading your config file. Refer to the Vikunja log to see if the config file was loaded or not.
|
||||
In case the config file was loaded, and there is no Trello icon, make sure your [config setup](#config-setup) is correct.
|
||||
|
||||
Click on Trello and on Get Started. This will redirect you to Trello where you need to allow Vikunja Migration to access your account. In case there is an error when being directed to Trello, make sure that your Vikunja domain is in your Trello Allowed Origins list.
|
||||
Once this is done, you will be redirected to Vikunja which should tell you that the migration is in progress now. Note that this can take up to several hours depending on the amount of boards in your Trello account.
|
@ -1,117 +0,0 @@
|
||||
---
|
||||
date: "2022-08-09:00:00+02:00"
|
||||
title: "OpenID example configurations"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# OpenID example configurations
|
||||
|
||||
On this page you will find examples about how to set up Vikunja with a third-party OAuth 2.0 provider using OpenID Connect.
|
||||
To add another example, please [edit this document](https://kolaente.dev/vikunja/vikunja/src/branch/main/docs/content/doc/setup/openid-examples.md) and send a PR.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Authelia
|
||||
|
||||
Vikunja Config:
|
||||
|
||||
```yaml
|
||||
openid:
|
||||
enabled: true
|
||||
redirecturl: https://vikunja.mydomain.com/auth/openid/ <---- slash at the end is important
|
||||
providers:
|
||||
- name: Authelia
|
||||
authurl: https://login.mydomain.com
|
||||
clientid: <vikunja-id>
|
||||
clientsecret: <vikunja secret>
|
||||
```
|
||||
|
||||
Authelia config:
|
||||
|
||||
```yaml
|
||||
- id: <vikunja-id>
|
||||
description: Vikunja
|
||||
secret: <vikunja secret>
|
||||
redirect_uris:
|
||||
- https://vikunja.mydomain.com/auth/openid/authelia
|
||||
scopes:
|
||||
- openid
|
||||
- email
|
||||
- profile
|
||||
```
|
||||
|
||||
## Google / Google Workspace
|
||||
|
||||
Vikunja Config:
|
||||
|
||||
```yaml
|
||||
openid:
|
||||
enabled: true
|
||||
redirecturl: https://vikunja.mydomain.com/auth/openid/ <---- slash at the end is important
|
||||
providers:
|
||||
- name: Google
|
||||
authurl: https://accounts.google.com
|
||||
clientid: <google-oauth-client-id>
|
||||
clientsecret: <google-oauth-client-secret>
|
||||
```
|
||||
|
||||
Google config:
|
||||
|
||||
- Navigate to `https://console.cloud.google.com/apis/credentials` in the target project
|
||||
- Create a new OAuth client ID
|
||||
- Configure an authorized redirect URI of `https://vikunja.mydomain.com/auth/openid/google`
|
||||
|
||||
Note that there currently seems to be no way to stop creation of new users, even when `enableregistration` is `false` in the configuration. This means that this approach works well only with an "Internal Organization" app for Google Workspace, which limits the allowed users to organizational accounts only. External / public applications will potentially allow every Google user to register.
|
||||
|
||||
## Keycloak
|
||||
|
||||
Vikunja Config:
|
||||
```yaml
|
||||
openid:
|
||||
enabled: true
|
||||
redirecturl: https://vikunja.mydomain.com/auth/openid/ <---- slash at the end is important
|
||||
providers:
|
||||
- name: Keycloak
|
||||
authurl: https://keycloak.mydomain.com/realms/<relam-name>
|
||||
logouturl: https://keycloak.mydomain.com/realms/<relam-name>/protocol/openid-connect/logout
|
||||
clientid: <vikunja-id>
|
||||
clientsecret: <vikunja secret>
|
||||
```
|
||||
Keycloak Config:
|
||||
- Navigate to the keycloak instance
|
||||
- Create a new client with the type `OpenID Connect` and a unique ID.
|
||||
- Set `Client authentication` to On
|
||||
- Set `Root Url` to `https://vikunja.mydomain.com`
|
||||
- Set `Valid redirect URIs` to `/auth/openid/keycloak`
|
||||
- Create the client the navigate to the credentials tab and copy the `Client secret`
|
||||
|
||||
## Authentik
|
||||
|
||||
Authentik Config:
|
||||
- Create a new Provider called "Vikunja" in Authentik
|
||||
- Set the `Redirect URIs/Origins (RegEx)` to `https://vikunja.mydomain.com/auth/openid/authentik`
|
||||
- Copy the Client ID and Client Secret
|
||||
|
||||
Vikunja Config:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
openid:
|
||||
enabled: true
|
||||
redirecturl: "https://vikunja.mydomain.com/auth/openid/"
|
||||
providers:
|
||||
- name: authentik
|
||||
authurl: "https://authentik.mydomain.com/application/o/vikunja"
|
||||
logouturl: "https://authentik.mydomain.com/application/o/vikunja/end-session/"
|
||||
clientid: "" # copy from Authetik
|
||||
clientsecret: "" # copy from Authentik
|
||||
```
|
||||
|
||||
**Note:** The `authurl` that Vikunja requires is not the `Authorize URL` that you can see in the Provider.
|
||||
OpenID Discovery is used to find the correct endpoint to use automatically, by accessing the `OpenID Configuration URL` (usually `https://authentik.mydomain.com/application/o/vikunja/.well-known/openid-configuration`).
|
||||
Use this URL without the `.well-known/openid-configuration` as the `authurl`.
|
||||
Typically this URL can be found in the metadata section within your identity provider.
|
@ -1,215 +0,0 @@
|
||||
---
|
||||
date: "2022-08-09:00:00+02:00"
|
||||
title: "OpenID"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# OpenID
|
||||
|
||||
Vikunja allows for authentication with an external identity source such as Authentik, Keycloak or similar via the
|
||||
[OpenID Connect](https://openid.net/developers/specs/) standard.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## OpenID Connect Overview
|
||||
|
||||
OpenID Connect is a standardized identity layer built on top of the more generic OAuth 2.0 specification, simplifying interaction between the involved parties significantly.
|
||||
While the [OpenID specification](https://openid.net/specs/openid-connect-core-1_0.html#Overview) is worth a read, we summarize the most important basics here.
|
||||
|
||||
The involved parties are:
|
||||
|
||||
- **Resource Owner:** typically the end-user
|
||||
- **Resource Server:** the application server handling requests from the client, the Vikunja API in our case
|
||||
- **Client:** the application or client accessing the RS on behalf of the RO. Vikunja web frontend or any of the apps
|
||||
- **Authorization Server:** the server verifying the user identity and issuing tokens. These docs also use the words `OAuth 2.0 provider`, `Identity Provider` interchangeably.
|
||||
|
||||
After the user is authenticated, the provider issues a token to the user, containing various claims.
|
||||
There's different types of tokens (ID token, access token, refresh token), and all of them are created as [JSON Web Token](https://www.rfc-editor.org/info/rfc7519).
|
||||
Claims in turn are assertions containing information about the token bearer, usually the user.
|
||||
|
||||
**Scopes** are requested by the client when redirecting the end-user to the Authorization Server for authentication, and indirectly control which claims are included in the resulting tokens.
|
||||
There's certain default scopes, but its also possible to define custom scopes, which are used by the feature assigning users to Teams automatically.
|
||||
|
||||
## Supported and required claims
|
||||
|
||||
Vikunja only requires a few claims to be present in the ID token to successfully authenticate the user.
|
||||
Additional claims can be added though to customize behaviour during user creation.
|
||||
|
||||
The following table gives an overview about the claims supported by Vikunja. The scope column lists the scope that should request the claim according to the [OpenID Connect Standard](https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims). It omits the claims such as `sub` or `issuer` required by the `openid` scope, which must always be present.
|
||||
|
||||
| Claim | Type | Scope | Comment |
|
||||
| ------|------|-------|---------|
|
||||
| email | required | email | Sets the email address of the user. Taken from the `userinfo` endpoint if not present in ID token. User creation fails if claim not present and userinfo lookup fails. |
|
||||
| name | optional | profile | Sets the display name of the user. Taken from the `userinfo` endpoint if not present in ID token. |
|
||||
| preferred_username | optional | profile | Sets the username of the user. Taken from the `userinfo` endpoint if not present in ID token. If this also doesn't contain the claim, use the `nickname` claim from `userinfo` instead. If that one is not available either, the username is auto-generated by Vikunja. |
|
||||
| vikunja_groups | optional | N/A | Can be used to automatically assign users to teams. See below for a more detailed explanation about the expected format and implementation examples. |
|
||||
|
||||
If one of the claims `email`, `name` or `preferred_username` is missing from the ID token, Vikunja will attempt to query the `userinfo` endpoint to obtain the information from there.
|
||||
|
||||
## Configuring OIDC Authentication
|
||||
|
||||
To achieve authentication via an external provider, it is required to (a) configure a confidential Client on your OAuth 2.0 provider and (b) configure Vikunja to authenticate against this provider.
|
||||
[Example configurations]({{< ref "openid-examples.md">}}) are provided for various different identity providers, below you can find generic guides though.
|
||||
|
||||
OpenID Connect defines various flow types indicating how exactly the interaction between the involved parties work, Vikunja makes use of the standard **Authorization Code Flow**.
|
||||
|
||||
### Step 1: Configure your Authorization Server
|
||||
|
||||
The first step is to configure the Authorization Server to correctly handle requests coming from Vikunja.
|
||||
In general, this involves the following steps at a minimum:
|
||||
|
||||
- Create a confidential client and obtain the client ID and client secret
|
||||
- Configure (whitelist) redirect URLs that can be used by Vikunja
|
||||
- Make sure the required scopes (`openid profile email` are the default scopes used by Vikunja) are supported
|
||||
- Optional: configure an additional scope for automatic team assignment, see below for details
|
||||
|
||||
More detailed instructions for various different identity providers can be [found here]({{< ref "openid-examples.md">}})
|
||||
|
||||
### Step 2: Configure Vikunja
|
||||
|
||||
Vikunja has to be configured to use the identity provider. Please note that there is currently no option to configure these settings via environment variables, they have to be defined using the configuration file. The configuration schema is as follows:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
openid:
|
||||
enabled: true
|
||||
redirecturl: https://vikunja.mydomain.com/auth/openid/ <---- slash at the end is important
|
||||
providers:
|
||||
- name: <provider-name>
|
||||
authurl: <auth-url> <----- Used for OIDC Discovery, usually the issuer
|
||||
clientid: <vikunja client-id>
|
||||
clientsecret: <vikunja client-secret>
|
||||
scope: openid profile email
|
||||
```
|
||||
|
||||
The value for `authurl` can be obtained from the metadata of your provider.
|
||||
Note that the `authurl` is used for [OIDC Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html).
|
||||
Typically, you'll want to use the `issuer` URL as found in the provider metadata.
|
||||
|
||||
The values for `clientid` and `clientsecret` are typically obtained when configuring the client.
|
||||
The scope usually doesn't need to be specified or changed, unless you want to configure the automatic team assignment.
|
||||
|
||||
Optionally it is possible to disable local authentication and therefore forcing users to login via OpenID connect:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
local:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
## Automatically assign users to teams
|
||||
|
||||
Starting with version 0.24.0, Vikunja is capable of automatically adding users to a team based on OIDC claims added by the identity provider.
|
||||
If configured, Vikunja will sync teams, automatically create new ones and make sure the members are part of the configured teams.
|
||||
Teams which exist only because they were created from oidc attributes are not editable in Vikunja.
|
||||
|
||||
To distinguish between teams created in Vikunja and teams generated automatically via oidc, generated teams have an `oidcID` assigned internally.
|
||||
Within the UI, the teams created through OIDC get a `(OIDC)` suffix to make them distinguishable from locally created teams.
|
||||
|
||||
On a high level, you need to make sure that the **ID token** issued by your identity provider contains a `vikunja_groups` claim, following the structure defined below.
|
||||
It depends on the provider being used as well as the preferences of the administrator how this is achieved.
|
||||
Typically you'd want to request an additional scope (e.g. `vikunja_scope`) which then triggers the identity provider to add the claim.
|
||||
If the `vikunja_groups` is part of the **ID token**, Vikunja will start the procedure and import teams and team memberships.
|
||||
|
||||
The minimal claim structure expected by Vikunja is as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"vikunja_groups": [
|
||||
{
|
||||
"name": "team 1",
|
||||
"oidcID": 33349
|
||||
},
|
||||
{
|
||||
"name": "team 2",
|
||||
"oidcID": 35933
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
It is also possible to pass the `description` and the `isPublic` flag as optional parameters. If not present, the description will be empty and project visibility defaults to false.
|
||||
|
||||
```json
|
||||
{
|
||||
"vikunja_groups": [
|
||||
{
|
||||
"name": "team 3",
|
||||
"oidcID": 33349,
|
||||
"description": "My Team Description",
|
||||
"isPublic": true
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
For each team, you need to define a team `name` and an `oidcID`, where the `oidcID` can be any string with a length of less than 250 characters.
|
||||
The `oidcID` is used to uniquely identify the team, so please make sure to keep this unique.
|
||||
|
||||
Below you'll find two example implementations for Authentik and Keycloak.
|
||||
If you've successfully implemented this with another identity provider, please let us know and submit a PR to improve the docs.
|
||||
|
||||
### Setup in Authentik
|
||||
|
||||
To configure automatic team management through Authentik, we assume you have already [set up Authentik]({{< ref "openid-examples.md">}}#authentik) as an OIDC provider for authentication with Vikunja.
|
||||
|
||||
To use Authentik's group assignment feature, follow these steps:
|
||||
|
||||
1. Edit [your config]({{< ref "config.md">}}) to include the following scopes: `openid profile email vikunja_scope`
|
||||
2. Open `<your authentik url>/if/admin/#/core/property-mappings`
|
||||
3. Create a new property mapping called `vikunja_scope` as scope mapping. There is a field `expression` to enter python expressions that will be delivered with the oidc token.
|
||||
4. Write a small script like the following to add group information to `vikunja_scope`:
|
||||
|
||||
```python
|
||||
groupsDict = {"vikunja_groups": []}
|
||||
for group in request.user.ak_groups.all():
|
||||
groupsDict["vikunja_groups"].append({"name": group.name, "oidcID": group.num_pk})
|
||||
return groupsDict
|
||||
```
|
||||
|
||||
5. In Authentik's menu on the left, go to Applications > Providers > Select the Vikunja provider. Then click on "Edit", on the bottom open "Advanced protocol settings", select the newly created property mapping under "Scopes". Save the provider.
|
||||
|
||||
Now when you log into Vikunja via Authentik it will show you a list of scopes you are claiming.
|
||||
You should see the description you entered on the OIDC provider's admin area.
|
||||
|
||||
Proceed to vikunja and open the teams page in the sidebar menu.
|
||||
You should see "(OIDC)" written next to each team you were assigned through OIDC.
|
||||
|
||||
### Setup in Keycloak
|
||||
|
||||
The kind people from Makerspace Darmstadt e.V. have written [a guide on how to create a mapper for Vikunja here](https://github.com/makerspace-darmstadt/keycloak-vikunja-mapper).
|
||||
|
||||
## Use cases
|
||||
|
||||
All examples assume one team called "Team 1" to be configured within your provider.
|
||||
|
||||
* *Token delivers team.name +team.oidcID and Vikunja team does not exist:* \
|
||||
New team will be created called "Team 1" with attribute oidcID: "33929"
|
||||
|
||||
2. *In Vikunja Team with name "team 1" already exists in vikunja, but has no oidcID set:* \
|
||||
new team will be created called "team 1" with attribute oidcID: "33929"
|
||||
|
||||
3. *In Vikunja Team with name "team 1" already exists in vikunja, but has different oidcID set:* \
|
||||
new team will be created called "team 1" with attribute oidcID: "33929"
|
||||
|
||||
4. *In Vikunja Team with oidcID "33929" already exists in vikunja, but has different name than "team1":* \
|
||||
new team will be created called "team 1" with attribute oidcID: "33929"
|
||||
|
||||
5. *Scope vikunja_scope is not set:* \
|
||||
nothing happens
|
||||
|
||||
6. *oidcID is not set:* \
|
||||
You'll get error.
|
||||
Custom Scope malformed
|
||||
"The custom scope set by the OIDC provider is malformed. Please make sure the openid provider sets the data correctly for your scope. Check especially to have set an oidcID."
|
||||
|
||||
7. *In Vikunja I am in "team 3" with oidcID "", but the token does not deliver any data for "team 3":* \
|
||||
You will stay in team 3 since it was not set by the oidc provider
|
||||
|
||||
8. *In Vikunja I am in "team 3" with oidcID "12345", but the token does not deliver any data for "team 3"*:\
|
||||
You will be signed out of all teams, which have an oidcID set and are not contained in the token.
|
||||
Especially if you've been the last team member, the team will be deleted.
|
@ -1,152 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Reverse Proxy"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# Setup behind a reverse proxy
|
||||
|
||||
These examples assume you have an instance of Vikunja running on your server listening on port `3456`.
|
||||
If you've changed this setting, you need to update the server configurations accordingly.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## NGINX
|
||||
|
||||
You may need to adjust `server_name` and `root` accordingly.
|
||||
|
||||
```conf
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3456;
|
||||
client_max_body_size 20M;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<div class="notification is-warning">
|
||||
<b>NOTE:</b> If you change the max upload size in Vikunja's settings, you'll need to also change the <code>client_max_body_size</code> in the nginx proxy config.
|
||||
</div>
|
||||
|
||||
## NGINX Proxy Manager (NPM)
|
||||
|
||||
Following the [Docker Walkthrough]({{< ref "docker-start-to-finish.md" >}}) guide, you should be able to get Vikunja to work via HTTP connection to your server IP.
|
||||
|
||||
From there, all you have to do is adjust the following things:
|
||||
|
||||
### In `docker-compose.yml`
|
||||
|
||||
1. Change `VIKUNJA_SERVICE_PUBLICURL:` to your desired domain with `https://` and `/`.
|
||||
2. Expose your desired port on host under `ports:`.
|
||||
|
||||
example:
|
||||
|
||||
```yaml
|
||||
vikunja:
|
||||
image: vikunja/vikunja
|
||||
environment:
|
||||
VIKUNJA_SERVICE_PUBLICURL: https://vikunja.your-domain.com/ # change vikunja.your-domain.com to your desired domain/subdomain.
|
||||
VIKUNJA_DATABASE_HOST: db
|
||||
VIKUNJA_DATABASE_PASSWORD: secret
|
||||
VIKUNJA_DATABASE_TYPE: mysql
|
||||
VIKUNJA_DATABASE_USER: vikunja
|
||||
VIKUNJA_DATABASE_DATABASE: vikunja
|
||||
VIKUNJA_SERVICE_JWTSECRET: <your-random-secret>
|
||||
ports:
|
||||
- 3456:3456 # Change 3456 on the left to the port of your choice.
|
||||
volumes:
|
||||
- ./files:/app/vikunja/files
|
||||
depends_on:
|
||||
- db
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### In your DNS provider
|
||||
|
||||
Add an `A` records that points to your server IP.
|
||||
|
||||
You are of course free to change them to whatever domain/subdomain you desire and modify the `docker-compose.yml` accordingly.
|
||||
|
||||
(Tested on Cloudflare DNS. Settings are different for different DNS provider, in this case the end result should be `vikunja.your-domain.com`)
|
||||
|
||||
### In Nginx Proxy Manager
|
||||
|
||||
Add a Proxy Host as you normally would, and you don't have to add anything extra in Advanced.
|
||||
|
||||
Under `Details`:
|
||||
|
||||
```
|
||||
Domain Names:
|
||||
vikunja.your-domain.com
|
||||
Scheme:
|
||||
http
|
||||
Forward Hostname/IP:
|
||||
your-server-ip
|
||||
Forward Port:
|
||||
3456
|
||||
Cached Assets:
|
||||
Optional.
|
||||
Block Common Exploits:
|
||||
Toggled.
|
||||
Websockets Support:
|
||||
Toggled.
|
||||
```
|
||||
|
||||
Under `SSL`:
|
||||
|
||||
```
|
||||
SSL Certificate:
|
||||
However you prefer.
|
||||
Force SSL:
|
||||
Toggled.
|
||||
HTTP/2 Support:
|
||||
Toggled.
|
||||
HSTS Enabled:
|
||||
Toggled.
|
||||
HSTS Subdomains:
|
||||
Toggled.
|
||||
Use a DNS Challenge:
|
||||
Not toggled.
|
||||
Email Address for Let's Encrypt:
|
||||
your-email@email.com
|
||||
```
|
||||
|
||||
Your Vikunja service should now work and your HTTPS frontend should be able to reach the API after `docker-compose`.
|
||||
|
||||
## Apache
|
||||
|
||||
Put the following config in `cat /etc/apache2/sites-available/vikunja.conf`:
|
||||
|
||||
```aconf
|
||||
<VirtualHost *:80>
|
||||
ServerName localhost
|
||||
|
||||
<Proxy *>
|
||||
Order Deny,Allow
|
||||
Allow from all
|
||||
</Proxy>
|
||||
ProxyPass / http://localhost:3456/
|
||||
ProxyPassReverse / http://localhost:3456/
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
**Note:** The apache modules `proxy`, `proxy_http` and `rewrite` must be enabled for this.
|
||||
|
||||
## Caddy
|
||||
|
||||
Use the following Caddyfile to get Vikunja up and running:
|
||||
|
||||
```conf
|
||||
vikunja.domainname.tld {
|
||||
handle /* {
|
||||
reverse_proxy 127.0.0.1:3456
|
||||
}
|
||||
}
|
||||
```
|
@ -1,49 +0,0 @@
|
||||
---
|
||||
title: "Running Vikunja in a subdirectory"
|
||||
date: 2022-09-23T12:15:04+02:00
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# Running Vikunja in a subdirectory
|
||||
|
||||
Running Vikunja in a subdirectory is not supported out of the box.
|
||||
However, you can still run it in a subdirectory but need to build the frontend yourself.
|
||||
|
||||
## Frontend
|
||||
|
||||
First, make sure you're able to build the frontend from source.
|
||||
Check [the guide about building from source]({{< ref "build-from-source.md">}}#frontend) about that.
|
||||
|
||||
### Dynamically set with build command
|
||||
|
||||
Run the build with the `VIKUNJA_FRONTEND_BASE` variable specified.
|
||||
|
||||
```
|
||||
VIKUNJA_FRONTEND_BASE=/SUBPATH/ pnpm run build
|
||||
```
|
||||
|
||||
Where `SUBPATH` is the subdirectory you want to run Vikunja on.
|
||||
|
||||
### Set via .env.local
|
||||
|
||||
* Copy `.env.local.example` to `.env.local`
|
||||
* Uncomment `VIKUNJA_FRONTEND_BASE` and set `/subpath/` to the desired path.
|
||||
|
||||
After saving, build Vikunja as normal.
|
||||
|
||||
```
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
Once you have the frontend built, you can proceed to build the binary as outlined in [building from source]({{< ref "build-from-source.md">}}#api).
|
||||
|
||||
## API
|
||||
|
||||
If you're not using a reverse proxy you're good to go.
|
||||
Simply configure the api url in the frontend as you normally would.
|
||||
|
||||
If you're using a reverse proxy you'll need to adjust the paths so that the api is available at `/SUBPATH/api/v1`.
|
||||
You can check if everything is working correctly by opening `/SUBPATH/api/v1/info` in a browser.
|
@ -1,23 +0,0 @@
|
||||
---
|
||||
title: "Typesense"
|
||||
date: 2023-09-29T12:23:55+02:00
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# Use Typesense for enhanced search capabilities
|
||||
|
||||
Vikunja supports using [Typesense](https://typesense.org/) for a better search experience.
|
||||
Typesense allows fast fulltext search including fuzzy matching support.
|
||||
It may return different results than what you'd get with a database-only search, but generally, the results are more relevant to what you're looking for.
|
||||
|
||||
This document explains how to set up and use Typesense with Vikunja.
|
||||
|
||||
## Setup
|
||||
|
||||
1. First, install Typesense on your system. Refer to [their documentation](https://typesense.org/docs/guide/install-typesense.html) for specific instructions.
|
||||
2. Once Typesense is available on your system and reachable by Vikunja, add the relevant configuration keys to your Vikunja config. [Check out the docs article about this]({{< ref "config.md#typesense">}}).
|
||||
3. Index all tasks currently in Vikunja. To do that, run the `vikunja index` command with the api binary. This may take a while, depending on the size of your instance.
|
||||
4. Restart the api. From now on, all task changes will be automatically indexed in Typesense.
|
@ -1,105 +0,0 @@
|
||||
---
|
||||
date: "2020-07-06:00:00+02:00"
|
||||
title: "UTF-8 Settings"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# UTF-8 Settings
|
||||
|
||||
Vikunja itself is always fully capable of handling utf-8 characters.
|
||||
However, your database might be not. Vikunja itself will work just fine until you want to use non-latin characters in your tasks/projects/etc.
|
||||
|
||||
On this page, you will find information about how to fully ensure non-latin characters like *aüäß* or emojis work with your installation.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Postgresql & SQLite
|
||||
|
||||
Postgresql and SQLite should handle utf-8 just fine - If you discover any issues nonetheless, please
|
||||
[drop us a message](https://vikunja.io/contact/).
|
||||
|
||||
## MySQL
|
||||
|
||||
MySQL is not able to handle utf-8 by default.
|
||||
To fix this, follow the steps below.
|
||||
|
||||
To find out if your db supports utf-8, run the following in a shell or similar, assuming the database
|
||||
you're using for vikunja is called `vikunja`:
|
||||
|
||||
```sql
|
||||
SELECT default_character_set_name FROM information_schema.SCHEMATA WHERE schema_name = 'vikunja';
|
||||
```
|
||||
|
||||
This will get you a result like the following:
|
||||
|
||||
```
|
||||
+----------------------------+
|
||||
| default_character_set_name |
|
||||
+----------------------------+
|
||||
| latin1 |
|
||||
+----------------------------+
|
||||
1 row in set (0.001 sec)
|
||||
```
|
||||
|
||||
The charset `latin1` means the db is encoded in the `latin1` encoding which does not support utf-8 characters.
|
||||
|
||||
(The following guide is based on [this thread from stackoverflow](https://dba.stackexchange.com/a/104866))
|
||||
|
||||
### 0. Backup your database
|
||||
|
||||
Before attempting any conversion, please [back up your database]({{< ref "backups.md">}}).
|
||||
|
||||
### 1. Create a pre-conversion script
|
||||
|
||||
Copy the following sql statements in a file called `preAlterTables.sql` and replace all occurrences of `vikunja` with the name of your database:
|
||||
|
||||
```sql
|
||||
use information_schema;
|
||||
SELECT concat("ALTER DATABASE `",table_schema,"` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;") as _sql
|
||||
FROM `TABLES` where table_schema like 'vikunja' and TABLE_TYPE='BASE TABLE' group by table_schema;
|
||||
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name,"` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") as _sql
|
||||
FROM `TABLES` where table_schema like 'vikunja' and TABLE_TYPE='BASE TABLE' group by table_schema, table_name;
|
||||
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name, "` CHANGE `",column_name,"` `",column_name,"` ",data_type,"(",character_maximum_length,") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",IF(is_nullable="YES"," NULL"," NOT NULL"),";") as _sql
|
||||
FROM `COLUMNS` where table_schema like 'vikunja' and data_type in ('varchar','char');
|
||||
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name, "` CHANGE `",column_name,"` `",column_name,"` ",data_type," CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",IF(is_nullable="YES"," NULL"," NOT NULL"),";") as _sql
|
||||
FROM `COLUMNS` where table_schema like 'vikunja' and data_type in ('text','tinytext','mediumtext','longtext');
|
||||
```
|
||||
|
||||
### 2. Run the pre-conversion script
|
||||
|
||||
Running this will create the actual migration script for your particular database structure and save it in a file called `alterTables.sql`:
|
||||
|
||||
```
|
||||
mysql -uroot < preAlterTables.sql | egrep '^ALTER' > alterTables.sql
|
||||
```
|
||||
|
||||
### 3. Convert the database
|
||||
|
||||
At this point converting is just a matter of executing the previously generated sql script:
|
||||
|
||||
```
|
||||
mysql -uroot < alterTables.sql
|
||||
```
|
||||
|
||||
### 4. Verify it was successfully converted
|
||||
|
||||
If everything worked as intended, your db collation should now look like this:
|
||||
|
||||
```sql
|
||||
SELECT default_character_set_name FROM information_schema.SCHEMATA WHERE schema_name = 'vikunja';
|
||||
```
|
||||
|
||||
Should get you:
|
||||
|
||||
```
|
||||
+----------------------------+
|
||||
| default_character_set_name |
|
||||
+----------------------------+
|
||||
| utf8mb4 |
|
||||
+----------------------------+
|
||||
1 row in set (0.001 sec)
|
||||
```
|
@ -1,48 +0,0 @@
|
||||
---
|
||||
date: "2022-07-07:00:00+02:00"
|
||||
title: "Versions"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "setup"
|
||||
---
|
||||
|
||||
# Vikunja Versions
|
||||
|
||||
Vikunja api is available in two different release flavors.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Stable
|
||||
|
||||
Stable releases have a fixed version number like `0.20.2` and are published at irregular intervals whenever a new version is ready.
|
||||
They receive few bugfixes and security patches.
|
||||
|
||||
We use [Semantic Versioning](https://semver.org) for these releases.
|
||||
|
||||
## Unstable
|
||||
|
||||
Unstable versions are build every time a PR is merged or a commit to the main development branch is made.
|
||||
As such, they contain the current development code and are more likely to have bugs.
|
||||
There might be multiple new such builds a day.
|
||||
|
||||
Versions contain the last stable version, the number of commits since then and the commit the currently running binary was built from.
|
||||
They look like this: `v0.20.2-75-6049427322`
|
||||
|
||||
Since a release is also cut from the main branch at some point, features from unstable will eventually become available in stable releases.
|
||||
At the point in time of a new version release, the unstable build is the same exact thing.
|
||||
|
||||
The demo instance at [try.vikunja.io](https://try.vikunja.io) automatically updates and always runs the last unstable build.
|
||||
|
||||
## Switching between versions
|
||||
|
||||
First you should create a backup of your current setup!
|
||||
|
||||
Switching between versions is the same process as [upgrading]({{< ref install.md >}}#updating).
|
||||
Simply replace the stable binary with an unstable one or vice-versa.
|
||||
|
||||
For installations using docker, it is as simple as using the `unstable` or `latest` tag to switch between versions.
|
||||
|
||||
**Note:** While switching from stable to unstable should work without any problem, switching back might work but is not recommended and might break your instance.
|
||||
To switch from unstable back to stable the best way is to wait for the next stable release after the used unstable build and then upgrade to that.
|
@ -1,19 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "API Documentation"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
---
|
||||
|
||||
# API Documentation
|
||||
|
||||
You can find the api docs under `http://vikunja.tld/api/v1/docs` of your instance.<br />
|
||||
A public instance is available on [try.vikunja.io](https://try.vikunja.io/api/v1/docs).
|
||||
|
||||
These docs are autogenerated from annotations in the code with swagger.
|
||||
|
||||
The specification is hosted at `http://vikunja.tld/api/v1/docs.json`.
|
||||
You can use this to embed it into other OpenAPI compatible applications if you want.
|
@ -1,145 +0,0 @@
|
||||
---
|
||||
date: "2019-05-12:00:00+01:00"
|
||||
title: "CalDAV"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
---
|
||||
|
||||
# CalDAV
|
||||
|
||||
> **Warning:** The CalDAV integration is in an early alpha stage and has bugs.
|
||||
> It works well with some clients while having issues with others.
|
||||
> If you encounter issues, please [report them](https://code.vikunja.io/api/issues/new?body=[caldav])
|
||||
|
||||
Vikunja supports managing tasks via the [caldav VTODO](https://tools.ietf.org/html/rfc5545#section-3.6.2) extension.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## URLs
|
||||
|
||||
All urls are located under the `/dav` subspace.
|
||||
|
||||
Urls are:
|
||||
|
||||
* `/principals/<username>/`: Returns urls for project discovery. *Use this url to initially make connections to new clients.*
|
||||
* `/projects/`: Used to manage projects
|
||||
* `/projects/<Project ID>/`: Used to manage a single project
|
||||
* `/projects/<Project ID>/<Task UID>`: Used to manage a task on a project
|
||||
|
||||
## Supported properties
|
||||
|
||||
Vikunja currently supports the following properties:
|
||||
|
||||
* `UID`
|
||||
* `SUMMARY`
|
||||
* `DESCRIPTION`
|
||||
* `PRIORITY`
|
||||
* `CATEGORIES`
|
||||
* `COMPLETED`
|
||||
* `CREATED` (only Vikunja → Client)
|
||||
* `DUE`
|
||||
* `DURATION`
|
||||
* `DTSTAMP`
|
||||
* `DTSTART`
|
||||
* `LAST-MODIFIED` (only Vikunja → Client)
|
||||
* `RRULE` (Recurrence) (only Vikunja → Client)
|
||||
* `VALARM` (Reminders)
|
||||
|
||||
Vikunja **currently does not** support these properties:
|
||||
|
||||
* `ATTACH`
|
||||
* `CLASS`
|
||||
* `COMMENT`
|
||||
* `CONTACT`
|
||||
* `GEO`
|
||||
* `LOCATION`
|
||||
* `ORGANIZER` (disabled)
|
||||
* `PERCENT-COMPLETE`
|
||||
* `RECURRENCE-ID`
|
||||
* `RELATED-TO`
|
||||
* `RESOURCES`
|
||||
* `SEQUENCE`
|
||||
* `STATUS`
|
||||
* `URL`
|
||||
|
||||
## Tested Clients
|
||||
|
||||
### Working
|
||||
|
||||
* [Evolution](https://wiki.gnome.org/Apps/Evolution/)
|
||||
* [OpenTasks](https://opentasks.app/) & [DAVx⁵](https://www.davx5.com/)
|
||||
* [Tasks (Android)](https://tasks.org/)
|
||||
* [Korganizer](https://apps.kde.org/korganizer/)
|
||||
|
||||
### Not working
|
||||
|
||||
* [Thunderbird (68)](https://www.thunderbird.net/)
|
||||
* iOS CalDAV Sync (See [#753](https://kolaente.dev/vikunja/vikunja/issues/753))
|
||||
|
||||
## Dev logs
|
||||
|
||||
The whole thing is not optimized at all and probably pretty inefficient.
|
||||
|
||||
Request body and headers are logged if the debug output is enabled.
|
||||
|
||||
```
|
||||
Creating a new task:
|
||||
PUT /dav/lists/1/cd4dd0e1b3c19cc9d787829b6e08be536e3df3a4.ics
|
||||
|
||||
Body:
|
||||
|
||||
BEGIN:VCALENDAR
|
||||
CALSCALE:GREGORIAN
|
||||
PRODID:-//Ximian//NONSGML Evolution Calendar//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTODO
|
||||
UID:cd4dd0e1b3c19cc9d787829b6e08be536e3df3a4
|
||||
DTSTAMP:20190508T134538Z
|
||||
SUMMARY:test2000
|
||||
PRIORITY:0
|
||||
CLASS:PUBLIC
|
||||
CREATED:20190508T134710Z
|
||||
LAST-MODIFIED:20190508T134710Z
|
||||
END:VTODO
|
||||
END:VCALENDAR
|
||||
|
||||
|
||||
Marking a task as done:
|
||||
|
||||
BEGIN:VCALENDAR
|
||||
CALSCALE:GREGORIAN
|
||||
PRODID:-//Ximian//NONSGML Evolution Calendar//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VTODO
|
||||
UID:3ada92f28b4ceda38562ebf047c6ff05400d4c572352a
|
||||
DTSTAMP:20190511T183631
|
||||
DTSTART:19700101T000000
|
||||
DTEND:19700101T000000
|
||||
SUMMARY:sdgs
|
||||
ORGANIZER;CN=:user
|
||||
CREATED:20190511T183631
|
||||
PRIORITY:0
|
||||
LAST-MODIFIED:20190512T193428Z
|
||||
COMPLETED:20190512T193428Z
|
||||
PERCENT-COMPLETE:100
|
||||
STATUS:COMPLETED
|
||||
END:VTODO
|
||||
END:VCALENDAR
|
||||
|
||||
Requests from the app:::
|
||||
|
||||
[CALDAV] Request Body: <?xml version="1.0" encoding="UTF-8" ?><propfind xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav"><prop><current-user-principal /></prop></propfind>
|
||||
[CALDAV] GetResources: rpath: /dav/
|
||||
2019-05-18T23:25:49.971140654+02:00: WEB ▶ 192.168.1.134 PROPFIND 207 /dav/ 1.021705664s - okhttp/3.12.2
|
||||
|
||||
[CALDAV] Request Body: <?xml version="1.0" encoding="UTF-8" ?><propfind xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav"><prop><CAL:calendar-home-set /></prop></propfind>
|
||||
[CALDAV] GetResources: rpath: /dav/
|
||||
2019-05-18T23:25:52.166996113+02:00: WEB ▶ 192.168.1.134 PROPFIND 207 /dav/ 1.042834467s - okhttp/3.12.2
|
||||
|
||||
And then it just stops.
|
||||
... and complains about not being able to find the home set
|
||||
... without even requesting it...
|
||||
```
|
@ -1,221 +0,0 @@
|
||||
---
|
||||
date: "2019-03-31:00:00+01:00"
|
||||
title: "CLI"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
---
|
||||
|
||||
# Command line interface
|
||||
|
||||
You can interact with Vikunja using its `cli` interface.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
If you don't specify a command, the [`web`](#web) command will be executed.
|
||||
|
||||
All commands use the same standard [config file]({{< ref "../setup/config.md">}}).
|
||||
|
||||
## Using the cli in docker
|
||||
|
||||
When running Vikunja in docker, you'll need to execute all commands in the `vikunja` container.
|
||||
Instead of running the `vikunja` binary directly, run it like this:
|
||||
|
||||
```sh
|
||||
docker exec <name of the vikunja container> /app/vikunja/vikunja <subcommand>
|
||||
```
|
||||
|
||||
If you need to run a bunch of Vikunja commands, you can also create a shell alias for it:
|
||||
|
||||
```sh
|
||||
alias vikunja-docker='docker exec <name of the vikunja container> /app/vikunja/vikunja'
|
||||
```
|
||||
|
||||
Then use it as `vikunja-docker <subcommand>`.
|
||||
|
||||
## `dump`
|
||||
|
||||
Creates a zip file with all vikunja-related files.
|
||||
This includes config, version, all files and the full database.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja dump
|
||||
```
|
||||
|
||||
## `index`
|
||||
|
||||
Perform a full reindex of all tasks into Typesense. This will clear all tasks already present in the index unless the `--partial` flag is provided, see below.
|
||||
|
||||
The command will only work if Typesense is enabled.
|
||||
|
||||
Flags:
|
||||
* `-p`, `--partial`: If provided, Vikunja will only index tasks which are not present in the index yet.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja index [flags]
|
||||
```
|
||||
|
||||
## `help`
|
||||
|
||||
Shows more detailed help about any command.
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
$ vikunja help [command]
|
||||
```
|
||||
|
||||
## `migrate`
|
||||
|
||||
Run all database migrations which didn't already run.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja migrate [flags]
|
||||
$ vikunja migrate [command]
|
||||
```
|
||||
|
||||
### `migrate list`
|
||||
|
||||
Shows a list with all database migrations.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja migrate list
|
||||
```
|
||||
|
||||
### `migrate rollback`
|
||||
|
||||
Roll migrations back until a certain point.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja migrate rollback [flags]
|
||||
```
|
||||
|
||||
Flags:
|
||||
* `-n`, `--name` string: The id of the migration you want to roll back until.
|
||||
|
||||
## `restore`
|
||||
|
||||
Restores a previously created dump from a zip file, see `dump`.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja restore [path to dump zip file]
|
||||
```
|
||||
|
||||
## `testmail`
|
||||
|
||||
Sends a test mail using the configured smtp connection.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja testmail [email to send the test mail to]
|
||||
```
|
||||
|
||||
## `user`
|
||||
|
||||
Bundles a few commands to manage users.
|
||||
|
||||
### `user change-status`
|
||||
|
||||
Enable or disable a user. Will toggle the current status if no flag (`--enable` or `--disable`) is provided.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja user change-status [user id] [flags]
|
||||
```
|
||||
|
||||
Flags:
|
||||
* `-d`, `--disable`: Disable the user.
|
||||
* `-e`, `--enable`: Enable the user.
|
||||
|
||||
### `user create`
|
||||
|
||||
Create a new user.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja user create <flags>
|
||||
```
|
||||
|
||||
Flags:
|
||||
* `-a`, `--avatar-provider`: The avatar provider of the new user. Optional.
|
||||
* `-e`, `--email`: The email address of the new user.
|
||||
* `-p`, `--password`: The password of the new user. You will be asked to enter it if not provided through the flag.
|
||||
* `-u`, `--username`: The username of the new user.
|
||||
|
||||
### `user delete`
|
||||
|
||||
Start the user deletion process.
|
||||
If called without the `--now` flag, this command will only trigger an email to the user in order for them to confirm and start the deletion process (this is the same behavior as if the user requested their deletion via the web interface).
|
||||
With the flag the user is deleted **immediately**.
|
||||
|
||||
**USE WITH CAUTION.**
|
||||
|
||||
```
|
||||
$ vikunja user delete [id] [flags]
|
||||
```
|
||||
|
||||
Flags:
|
||||
* `-n`, `--now` If provided, deletes the user immediately instead of emailing them first.
|
||||
|
||||
### `user list`
|
||||
|
||||
Shows a list of all users.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja user list
|
||||
```
|
||||
|
||||
### `user reset-password`
|
||||
|
||||
Reset a users password, either through mailing them a reset link or directly.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja user reset-password [flags]
|
||||
```
|
||||
|
||||
Flags:
|
||||
* `-d`, `--direct`: If provided, reset the password directly instead of sending the user a reset mail.
|
||||
* `-p`, `--password`: The new password of the user. Only used in combination with --direct. You will be asked to enter it if not provided through the flag.
|
||||
|
||||
### `user update`
|
||||
|
||||
Update an existing user.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja user update [user id]
|
||||
```
|
||||
|
||||
Flags:
|
||||
* `-a`, `--avatar-provider`: The new avatar provider of the new user.
|
||||
* `-e`, `--email`: The new email address of the user.
|
||||
* `-u`, `--username`: The new username of the user.
|
||||
|
||||
## `version`
|
||||
|
||||
Prints the version of Vikunja.
|
||||
This is either the semantic version (something like `0.24.0`) or version + git commit hash.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja version
|
||||
```
|
||||
|
||||
## `web`
|
||||
|
||||
Starts Vikunja's web server, serving the api and frontend.
|
||||
|
||||
Usage:
|
||||
```
|
||||
$ vikunja web
|
||||
```
|
@ -1,169 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Errors"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
---
|
||||
|
||||
# Errors
|
||||
|
||||
This document describes the different errors Vikunja can return.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Generic
|
||||
|
||||
| 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. |
|
||||
| 1021 | 412 | This account is managed by a third-party authentication provider. |
|
||||
| 1021 | 412 | The username must not contain spaces. |
|
||||
| 1022 | 412 | The custom scope set by the OIDC provider is malformed. Please make sure the openid provider sets the data correctly for your scope. Check especially to have set an oidcID. |
|
||||
|
||||
## 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 additional array with all invalid fields. |
|
||||
|
||||
## Project
|
||||
|
||||
| ErrorCode | HTTP Status Code | Description |
|
||||
|-----------|------------------|------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 3001 | 404 | The project does not exist. |
|
||||
| 3004 | 403 | The user needs to have read permissions on that project to perform that action. |
|
||||
| 3005 | 400 | The project title cannot be empty. |
|
||||
| 3006 | 404 | The project share does not exist. |
|
||||
| 3007 | 400 | A project with this identifier already exists. |
|
||||
| 3008 | 412 | The project is archived and can therefore only be accessed read only. This is also true for all tasks associated with this project. |
|
||||
| 3009 | 412 | The project cannot belong to a dynamically generated parent project like "Favorites". |
|
||||
| 3010 | 412 | This project cannot be a child of itself. |
|
||||
| 3011 | 412 | This project cannot have a cyclic relationship to a parent project. |
|
||||
| 3012 | 412 | This project cannot be deleted because a user has set it as their default project. |
|
||||
| 3013 | 412 | This project cannot be archived because a user has set it as their default project. |
|
||||
| 3014 | 404 | This project view does not exist. |
|
||||
|
||||
## Task
|
||||
|
||||
| ErrorCode | HTTP Status Code | Description |
|
||||
|-----------|------------------|----------------------------------------------------------------------------|
|
||||
| 4001 | 400 | The project task text cannot be empty. |
|
||||
| 4002 | 404 | The project task does not exist. |
|
||||
| 4003 | 403 | All bulk editing tasks must belong to the same project. |
|
||||
| 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 | 400 | Invalid task field. |
|
||||
| 4017 | 400 | Invalid task filter comparator. |
|
||||
| 4018 | 400 | Invalid task filter concatinator. |
|
||||
| 4019 | 400 | Invalid task filter value. |
|
||||
| 4020 | 400 | The provided attachment does not belong to that task. |
|
||||
| 4021 | 400 | This user is already assigned to that task. |
|
||||
| 4022 | 400 | The task has a relative reminder which does not specify relative to what. |
|
||||
| 4023 | 409 | Tried to create a task relation which would create a cycle. |
|
||||
| 4024 | 400 | The provided filter expression is invalid. |
|
||||
| 4025 | 400 | The reaction kind is invalid. |
|
||||
| 4026 | 400 | You must provide a project view ID when sorting by position. |
|
||||
|
||||
## Team
|
||||
|
||||
| ErrorCode | HTTP Status Code | Description |
|
||||
|-----------|------------------|----------------------------------------------------------------------|
|
||||
| 6001 | 400 | The team name cannot be empty. |
|
||||
| 6002 | 404 | The team does not exist. |
|
||||
| 6004 | 409 | The team already has access to that project. |
|
||||
| 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 project to perform that action. |
|
||||
| 6008 | 400 | There are no teams found with that team name. |
|
||||
| 6009 | 400 | There is no oidc team with that team name and oidcId. |
|
||||
| 6010 | 400 | There are no oidc teams found for the user. |
|
||||
|
||||
## User Project Access
|
||||
|
||||
| ErrorCode | HTTP Status Code | Description |
|
||||
|-----------|------------------|-------------|
|
||||
| 7002 | 409 | The user already has access to that project. |
|
||||
| 7003 | 403 | The user does not have access to that project. |
|
||||
|
||||
## 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. |
|
||||
|
||||
## Kanban
|
||||
|
||||
| ErrorCode | HTTP Status Code | Description |
|
||||
|-----------|------------------|-------------|
|
||||
| 10001 | 404 | The bucket does not exist. |
|
||||
| 10002 | 400 | The bucket does not belong to that project. |
|
||||
| 10003 | 412 | You cannot remove the last bucket on a project. |
|
||||
| 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 project. |
|
||||
|
||||
## 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. |
|
||||
|
||||
## 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. |
|
||||
|
||||
## 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 is invalid. |
|
||||
| 13003 | 400 | The provided link share token is invalid. |
|
@ -1,67 +0,0 @@
|
||||
---
|
||||
title: "Filters"
|
||||
date: 2024-03-09T19:51:32+02:00
|
||||
draft: false
|
||||
type: doc
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
---
|
||||
|
||||
# Filter Syntax
|
||||
|
||||
To filter tasks via the api, you can use a query syntax similar to SQL.
|
||||
|
||||
This document is about filtering via the api. To filter in Vikunja's web ui, check out the help text below the filter query input.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Available fields
|
||||
|
||||
The available fields for filtering include:
|
||||
|
||||
* `done`: Whether the task is completed or not
|
||||
* `priority`: The priority level of the task (1-5)
|
||||
* `percentDone`: The percentage of completion for the task (0-100)
|
||||
* `dueDate`: The due date of the task
|
||||
* `startDate`: The start date of the task
|
||||
* `endDate`: The end date of the task
|
||||
* `doneAt`: The date and time when the task was completed
|
||||
* `assignees`: The assignees of the task
|
||||
* `labels`: The labels associated with the task
|
||||
* `project`: The project the task belongs to (only available for saved filters, not on a project level)
|
||||
|
||||
You can date math to set relative dates. Click on the date value in a query to find out more.
|
||||
|
||||
All strings must be either single-word or enclosed in `"` or `'`. This extends to date values like `2024-03-11`.
|
||||
|
||||
## Operators
|
||||
|
||||
The available operators for filtering include:
|
||||
|
||||
* `!=`: Not equal to
|
||||
* `=`: Equal to
|
||||
* `>`: Greater than
|
||||
* `>=`: Greater than or equal to
|
||||
* `<`: Less than
|
||||
* `<=`: Less than or equal to
|
||||
* `like`: Matches a pattern (using wildcard `%`)
|
||||
* `in`: Matches any value in a comma-seperated list of values
|
||||
|
||||
To combine multiple conditions, you can use the following logical operators:
|
||||
|
||||
* `&&`: AND operator, matches if all conditions are true
|
||||
* `||`: OR operator, matches if any of the conditions are true
|
||||
* `(` and `)`: Parentheses for grouping conditions
|
||||
|
||||
## Examples
|
||||
|
||||
Here are some examples of filter queries:
|
||||
|
||||
* `priority = 4`: Matches tasks with priority level 4
|
||||
* `dueDate < now`: Matches tasks with a due date in the past
|
||||
* `done = false && priority >= 3`: Matches undone tasks with priority level 3 or higher
|
||||
* `assignees in user1, user2`: Matches tasks assigned to either "user1" or "user2
|
||||
* `(priority = 1 || priority = 2) && dueDate <= now`: Matches tasks with priority level 1 or 2 and a due date in the past
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
---
|
||||
title: "n8n"
|
||||
date: 2023-10-24T19:31:35+02:00
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
---
|
||||
|
||||
# Using Vikunja with n8n
|
||||
|
||||
Vikunja maintains a [community node](https://github.com/go-vikunja/n8n-vikunja-nodes) for [n8n](https://n8n.io),
|
||||
allowing you to easily integrate Vikunja with all kinds of other tools and services.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## Installation
|
||||
|
||||
To install the node in your n8n installation:
|
||||
|
||||
1. In your n8n instance, go to **Settings > Community Nodes**.
|
||||
2. Select Install.
|
||||
3. Enter `n8n-nodes-vikunja` as the npm Package Name
|
||||
4. Agree to the risks of using community nodes: select I understand the risks of installing unverified code from a
|
||||
public source.
|
||||
5. Select Install. n8n installs the node, and returns to the Community Nodes list in Settings.
|
||||
6. Vikunja actions and triggers are now available in n8n.
|
||||
|
||||
[Official n8n docs about the installation](https://docs.n8n.io/integrations/community-nodes/installation/)
|
||||
|
||||
## Authentication
|
||||
|
||||
To authenticate your automation against Vikunja:
|
||||
|
||||
1. In Vikunja, go to **Settings > API Tokens** and create a new token. Use all scopes for the kind of task you want to
|
||||
do. \
|
||||
*Note:* If you want to use the webhook trigger node, the api token should have permissions to create, read and delete
|
||||
webhooks.
|
||||
2. Now in n8n, go to **Credentials** and then click on **Add Credential**.
|
||||
3. Search for `Vikunja API` and click *Continue*
|
||||
4. Enter the API key you created in step 1.
|
||||
5. Enter the API URL of your Vikunja instance, with `/api/v1` suffix.
|
||||
6. When you now create a Vikunja node, select the created credentials.
|
@ -1,25 +0,0 @@
|
||||
---
|
||||
date: "2019-09-25:00:00+02:00"
|
||||
title: "Task Relation kinds"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
---
|
||||
|
||||
# Available task relation kinds
|
||||
|
||||
| Code | Description | Opposite of |
|
||||
|------|-------------|-------------|
|
||||
| `subtask` | Task is a subtask of the other task. | `parenttask` |
|
||||
| `parenttask` | Task is a parent task of the other task. | `subtask` |
|
||||
| `related` | Both tasks are related to each other.<br /> How is not more specified. | ⸺ |
|
||||
| `duplicateof` | Task is a duplicate of the other task. | `duplicates` |
|
||||
| `duplicates` | Task duplicates the other task. | `duplicateof` |
|
||||
| `blocking` | Task is blocking the other task. | `blocked` |
|
||||
| `blocked` | Task is blocked by the other task. | `blocking` |
|
||||
| `precedes` | Task precedes the other task. | `follows` |
|
||||
| `follows` | Task follows the other task. | `precedes` |
|
||||
| `copiedfrom` | Task is copied from the other task. | `copiedto` |
|
||||
| `copiedto` | Task is copied to the other task. | `copiedfrom` |
|
@ -1,29 +0,0 @@
|
||||
---
|
||||
date: "2019-02-12:00:00+02:00"
|
||||
title: "Rights"
|
||||
draft: false
|
||||
type: "doc"
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
---
|
||||
|
||||
# Project rights for teams and users
|
||||
|
||||
Whenever you share a project with a user or team, you can specify a `rights` parameter.
|
||||
This parameter controls the rights that team or user is going to have (or has, if you request the current sharing status).
|
||||
|
||||
Rights are being specified using integers.
|
||||
|
||||
The following values are possible:
|
||||
|
||||
| Right (int) | Meaning |
|
||||
|-------------|-------------------------------------------------------------------------------------------------|
|
||||
| 0 (Default) | Read only. Anything which is shared with this right cannot be edited. |
|
||||
| 1 | Read and write. Projects shared with this right can be read and written to by the team or user. |
|
||||
| 2 | Admin. Can do anything like read and write, but can additionally manage sharing options. |
|
||||
|
||||
## Team admins
|
||||
|
||||
When adding or querying a team, every member has an additional boolean value stating if it is admin or not.
|
||||
A team admin can also add and remove team members and also change whether a user in the team is admin or not.
|
@ -1,58 +0,0 @@
|
||||
---
|
||||
title: "Webhooks"
|
||||
date: 2023-10-17T19:51:32+02:00
|
||||
draft: false
|
||||
type: doc
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
---
|
||||
|
||||
# Webhooks
|
||||
|
||||
Starting with version 0.22.0, Vikunja allows you to define webhooks to notify other services of events happening within Vikunja.
|
||||
|
||||
{{< table_of_contents >}}
|
||||
|
||||
## How to create webhooks
|
||||
|
||||
To create a webhook, in the project options select "Webhooks". The form will allow you to create and modify webhooks.
|
||||
|
||||
Check out [the api docs](https://try.vikunja.io/api/v1/docs#tag/webhooks) for information about how to create webhooks programmatically.
|
||||
|
||||
## Available events and their payload
|
||||
|
||||
All events registered as webhook events in [the event listeners definition](https://kolaente.dev/vikunja/vikunja/src/branch/main/pkg/models/listeners.go#L69) can be used as webhook target.
|
||||
|
||||
A webhook payload will look similar to this:
|
||||
|
||||
```json
|
||||
{
|
||||
"event_name": "task.created",
|
||||
"time": "2023-10-17T19:39:32.924194436+02:00",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
The `data` property will contain the raw event data as it was registered in the `listeners.go` file.
|
||||
|
||||
The `time` property holds the time when the webhook payload data was sent.
|
||||
It always uses the ISO 8601 format with date, time and time zone offset.
|
||||
|
||||
## Security considerations
|
||||
|
||||
### Signing
|
||||
|
||||
Vikunja allows you to provide a secret when creating the webhook.
|
||||
If you set a secret, all outgoing webhook requests will contain an `X-Vikunja-Signature` header with an HMAC signature over the webhook json payload.
|
||||
|
||||
Check out [webhooks.fyi](https://webhooks.fyi/security/hmac) for more information about how to validate the HMAC signature.
|
||||
|
||||
### Hosting webhook infrastructure
|
||||
|
||||
Vikunja has support to use [mole](https://github.com/frain-dev/mole) as a proxy for outgoing webhook requests.
|
||||
This allows you to prevent SSRF attacts on your own infrastructure.
|
||||
|
||||
You should use this and [configure it appropriately]({{< ref "../setup/config.md">}}#webhooks) if you're not the only one using your Vikunja instance.
|
||||
|
||||
Check out [webhooks.fyi](https://webhooks.fyi/best-practices/webhook-providers#implement-security-on-egress-communication) for more information about the attack vector and reasoning to prevent this.
|
@ -1,33 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
error_page 404 /docs/404.html;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
location /docs/contact {
|
||||
return 301 $scheme://vikunja.io/en/contact;
|
||||
}
|
||||
|
||||
location /docs/docs {
|
||||
return 301 $scheme://vikunja.io/docs;
|
||||
}
|
||||
|
||||
location /docs/install-backend {
|
||||
return 301 $scheme://vikunja.io/docs/installing;
|
||||
}
|
||||
|
||||
location /docs/install-frontend {
|
||||
return 301 $scheme://vikunja.io/docs/installing;
|
||||
}
|
||||
}
|
BIN
docs/static/synology-proxy-1.png
vendored
BIN
docs/static/synology-proxy-1.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 121 KiB |
BIN
docs/static/synology-proxy-2.png
vendored
BIN
docs/static/synology-proxy-2.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 502 KiB |
Loading…
x
Reference in New Issue
Block a user