Docs improvements
This commit is contained in:
parent
4216ed7277
commit
7ee535de47
19 changed files with 232 additions and 317 deletions
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
date: "2019-03-31:00:00+01:00"
|
date: "2019-03-31:00:00+01:00"
|
||||||
title: "Adding new cli commands"
|
title: "Cli Commands"
|
||||||
draft: false
|
draft: false
|
||||||
type: "doc"
|
type: "doc"
|
||||||
menu:
|
menu:
|
||||||
|
|
41
docs/content/doc/development/config.md
Normal file
41
docs/content/doc/development/config.md
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
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 retreive a configured value call the key with a getter for the type you need.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
{{< highlight golang >}}
|
||||||
|
if config.CacheEnabled.GetBool() {
|
||||||
|
// Do something with enabled caches
|
||||||
|
}
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
Take a look at the methods declared on the type to see what's available.
|
35
docs/content/doc/development/cron.md
Normal file
35
docs/content/doc/development/cron.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
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:
|
||||||
|
|
||||||
|
{{< highlight golang >}}
|
||||||
|
func RegisterSomeCronTask() {
|
||||||
|
err := cron.Schedule("0 * * * *", func() {
|
||||||
|
// Do something every hour
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
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).
|
40
docs/content/doc/development/database.md
Normal file
40
docs/content/doc/development/database.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
date: "2019-02-12:00:00+02:00"
|
||||||
|
title: "Database"
|
||||||
|
draft: false
|
||||||
|
type: "doc"
|
||||||
|
menu:
|
||||||
|
sidebar:
|
||||||
|
parent: "development"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Database
|
||||||
|
|
||||||
|
Vikunja uses [xorm](http://xorm.io/) as an abstraction layer to handle the database connection.
|
||||||
|
Please refer to [their](http://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 documentaion](http://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,6 +1,6 @@
|
||||||
---
|
---
|
||||||
date: "2019-03-29:00:00+02:00"
|
date: "2019-03-29:00:00+02:00"
|
||||||
title: "Database migrations"
|
title: "Database Migrations"
|
||||||
draft: false
|
draft: false
|
||||||
type: "doc"
|
type: "doc"
|
||||||
menu:
|
menu:
|
||||||
|
@ -37,6 +37,11 @@ All migrations are sorted before being executed, since `init()` does not guarant
|
||||||
When you're adding a new struct, you also need to add it to the `models.GetTables()` function
|
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.
|
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
|
### Example
|
||||||
|
|
||||||
{{< highlight golang >}}
|
{{< highlight golang >}}
|
||||||
|
|
|
@ -12,56 +12,11 @@ menu:
|
||||||
|
|
||||||
# Development
|
# Development
|
||||||
|
|
||||||
We use go modules to vendor libraries for Vikunja, so you'll need at least go `1.11` to use these.
|
We use go modules to manage third-party libraries for Vikunja, so you'll need at least go `1.11` to use these.
|
||||||
If you don't intend to add new dependencies, go `1.9` and above should be fine.
|
|
||||||
|
|
||||||
To contribute to Vikunja, fork the project and work on the main branch.
|
To contribute to Vikunja, fork the project and work on the main branch.
|
||||||
|
|
||||||
A lot of developing tasks are automated using a Magefile, so make sure to [take a look at it]({{< ref "mage.md">}}).
|
A lot of developing tasks are automated using a Magefile, so make sure to [take a look at it]({{< ref "mage.md">}}).
|
||||||
|
|
||||||
{{< table_of_contents >}}
|
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" >}}).
|
||||||
## Libraries
|
|
||||||
|
|
||||||
We keep all libraries used for Vikunja around in the `vendor/` folder to still be able to build the project even if
|
|
||||||
some maintainers take their libraries down like [it happened in the past](https://github.com/jteeuwen/go-bindata/issues/5).
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
See [testing]({{< ref "test.md">}}).
|
|
||||||
|
|
||||||
#### Development using go modules
|
|
||||||
|
|
||||||
If you're able to use go modules, you can clone the project wherever you want to and work from there.
|
|
||||||
|
|
||||||
#### Development-setup without go modules
|
|
||||||
|
|
||||||
Some internal packages are referenced using their respective package URL. This can become problematic.
|
|
||||||
To “trick” the Go tool into thinking this is a clone from the official repository, download the source code
|
|
||||||
into `$GOPATH/code.vikunja.io/api`. Fork the Vikunja repository, it should then be possible to switch the source directory on the command line.
|
|
||||||
|
|
||||||
{{< highlight bash >}}
|
|
||||||
cd $GOPATH/src/code.vikunja.io/api
|
|
||||||
{{< /highlight >}}
|
|
||||||
|
|
||||||
To be able to create pull requests, the forked repository should be added as a remote to the Vikunja sources, otherwise changes can’t be pushed.
|
|
||||||
|
|
||||||
{{< highlight bash >}}
|
|
||||||
git remote rename origin upstream
|
|
||||||
git remote add origin git@git.kolaente.de:<USERNAME>/api.git
|
|
||||||
git fetch --all --prune
|
|
||||||
{{< /highlight >}}
|
|
||||||
|
|
||||||
This should provide a working development environment for Vikunja. Take a look at the Magefile to get an overview about
|
|
||||||
the available tasks. The most common tasks should be `mage test:unit` which will start our test environment and `mage build:build`
|
|
||||||
which will build a vikunja binary into the working directory. Writing test cases is not mandatory to contribute, but it
|
|
||||||
is highly encouraged and helps developers sleep at night.
|
|
||||||
|
|
||||||
That’s it! You are ready to hack on Vikunja. Test changes, push them to the repository, and open a pull request.
|
|
||||||
|
|
||||||
## Static assets
|
|
||||||
|
|
||||||
Each Vikunja release contains all static assets directly compiled into the binary.
|
|
||||||
To prevent this during development, use the `dev` tag when developing.
|
|
||||||
|
|
||||||
See the [mage docs](mage.md#statically-compile-all-templates-into-the-binary) about how to compile with static assets for a release.
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ draft: false
|
||||||
type: "doc"
|
type: "doc"
|
||||||
menu:
|
menu:
|
||||||
sidebar:
|
sidebar:
|
||||||
parent: "practical instructions"
|
parent: "development"
|
||||||
---
|
---
|
||||||
|
|
||||||
# Custom Errors
|
# Custom Errors
|
|
@ -28,11 +28,11 @@ This document explains how events and listeners work in Vikunja, how to use them
|
||||||
|
|
||||||
Each event has to implement this interface:
|
Each event has to implement this interface:
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
type Event interface {
|
type Event interface {
|
||||||
Name() string
|
Name() string
|
||||||
}
|
}
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
||||||
An event can contain whatever data you need.
|
An event can contain whatever data you need.
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ To dispatch an event, simply call the `events.Dispatch` method and pass in the e
|
||||||
|
|
||||||
The `TaskCreatedEvent` is declared in the `pkg/models/events.go` file as follows:
|
The `TaskCreatedEvent` is declared in the `pkg/models/events.go` file as follows:
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
// TaskCreatedEvent represents an event where a task has been created
|
// TaskCreatedEvent represents an event where a task has been created
|
||||||
type TaskCreatedEvent struct {
|
type TaskCreatedEvent struct {
|
||||||
Task *Task
|
Task *Task
|
||||||
|
@ -86,11 +86,11 @@ type TaskCreatedEvent struct {
|
||||||
func (t *TaskCreatedEvent) Name() string {
|
func (t *TaskCreatedEvent) Name() string {
|
||||||
return "task.created"
|
return "task.created"
|
||||||
}
|
}
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
||||||
It is dispatched in the `createTask` function of the `models` package:
|
It is dispatched in the `createTask` function of the `models` package:
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
func createTask(s *xorm.Session, t *Task, a web.Auth, updateAssignees bool) (err error) {
|
func createTask(s *xorm.Session, t *Task, a web.Auth, updateAssignees bool) (err error) {
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
@ -102,7 +102,7 @@ func createTask(s *xorm.Session, t *Task, a web.Auth, updateAssignees bool) (err
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
||||||
As you can see, the curent task and doer are injected into it.
|
As you can see, the curent task and doer are injected into it.
|
||||||
|
|
||||||
|
@ -122,13 +122,13 @@ A single event can have multiple listeners who are independent of each other.
|
||||||
|
|
||||||
All listeners must implement this interface:
|
All listeners must implement this interface:
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
// Listener represents something that listens to events
|
// Listener represents something that listens to events
|
||||||
type Listener interface {
|
type Listener interface {
|
||||||
Handle(msg *message.Message) error
|
Handle(msg *message.Message) error
|
||||||
Name() string
|
Name() string
|
||||||
}
|
}
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
||||||
The `Handle` method is executed when the event this listener listens on is dispatched.
|
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.
|
* 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.
|
||||||
|
@ -165,7 +165,7 @@ See the example below.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
// RegisterListeners registers all event listeners
|
// RegisterListeners registers all event listeners
|
||||||
func RegisterListeners() {
|
func RegisterListeners() {
|
||||||
events.RegisterListener((&ListCreatedEvent{}).Name(), &IncreaseListCounter{})
|
events.RegisterListener((&ListCreatedEvent{}).Name(), &IncreaseListCounter{})
|
||||||
|
@ -183,13 +183,13 @@ func (s *IncreaseTaskCounter) Name() string {
|
||||||
func (s *IncreaseTaskCounter) Handle(payload message.Payload) (err error) {
|
func (s *IncreaseTaskCounter) Handle(payload message.Payload) (err error) {
|
||||||
return keyvalue.IncrBy(metrics.TaskCountKey, 1)
|
return keyvalue.IncrBy(metrics.TaskCountKey, 1)
|
||||||
}
|
}
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
When testing, you should call the `events.Fake()` method in the `TestMain` function of the package you want to test.
|
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:
|
This prevents any events from being fired and lets you assert an event has been dispatched like so:
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
events.AssertDispatched(t, &TaskCreatedEvent{})
|
events.AssertDispatched(t, &TaskCreatedEvent{})
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
date: "2019-02-12:00:00+02:00"
|
date: "2019-02-12:00:00+02:00"
|
||||||
title: "Add a new api endpoint"
|
title: "New API Endpoints"
|
||||||
draft: false
|
draft: false
|
||||||
type: "doc"
|
type: "doc"
|
||||||
menu:
|
menu:
|
||||||
sidebar:
|
sidebar:
|
||||||
parent: "practical instructions"
|
parent: "development"
|
||||||
---
|
---
|
||||||
|
|
||||||
# Add a new api endpoint/feature
|
# Add a new api endpoint/feature
|
|
@ -57,15 +57,13 @@ These tasks are automatically run in our CI every time someone pushes to main or
|
||||||
mage build:build
|
mage build:build
|
||||||
{{< /highlight >}}
|
{{< /highlight >}}
|
||||||
|
|
||||||
Builds a `vikunja`-binary in the root directory of the repo for the platform it is run on.
|
or
|
||||||
|
|
||||||
### Statically compile all templates into the binary
|
|
||||||
|
|
||||||
{{< highlight bash >}}
|
{{< highlight bash >}}
|
||||||
mage build:generate
|
mage build
|
||||||
{{< /highlight >}}
|
{{< /highlight >}}
|
||||||
|
|
||||||
This generates static code with all templates, meaning no template need to be referenced at runtime.
|
Builds a `vikunja`-binary in the root directory of the repo for the platform it is run on.
|
||||||
|
|
||||||
### clean
|
### clean
|
||||||
|
|
||||||
|
@ -73,7 +71,7 @@ This generates static code with all templates, meaning no template need to be re
|
||||||
mage build:clean
|
mage build:clean
|
||||||
{{< /highlight >}}
|
{{< /highlight >}}
|
||||||
|
|
||||||
Cleans all build, executable and bindata files
|
Cleans all build and executable files
|
||||||
|
|
||||||
## Check
|
## Check
|
||||||
|
|
||||||
|
@ -173,6 +171,8 @@ mage dev:create-migration
|
||||||
Creates a new migration with the current date.
|
Creates a new migration with the current date.
|
||||||
Will ask for the name of the struct you want to create a migration for.
|
Will ask for the name of the struct you want to create a migration for.
|
||||||
|
|
||||||
|
See also [migration docs]({{< ref "mage.md" >}}).
|
||||||
|
|
||||||
## Misc
|
## Misc
|
||||||
|
|
||||||
### Format the code
|
### Format the code
|
||||||
|
|
|
@ -5,7 +5,7 @@ draft: false
|
||||||
type: "doc"
|
type: "doc"
|
||||||
menu:
|
menu:
|
||||||
sidebar:
|
sidebar:
|
||||||
parent: "practical instructions"
|
parent: "development"
|
||||||
---
|
---
|
||||||
|
|
||||||
# Metrics
|
# Metrics
|
||||||
|
@ -17,7 +17,7 @@ The `metrics` package provides several functions to create and update metrics.
|
||||||
|
|
||||||
{{< table_of_contents >}}
|
{{< table_of_contents >}}
|
||||||
|
|
||||||
## New metrics
|
## Exposing New Metrics
|
||||||
|
|
||||||
First, define a `const` with the metric key in redis. This is done in `pkg/metrics/metrics.go`.
|
First, define a `const` with the metric key in redis. This is done in `pkg/metrics/metrics.go`.
|
||||||
|
|
|
@ -63,7 +63,7 @@ if config.MigrationWunderlistEnable.GetBool() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You should also document the routes with [swagger annotations]({{< ref "../practical-instructions/swagger-docs.md" >}}).
|
You should also document the routes with [swagger annotations]({{< ref "swagger-docs.md" >}}).
|
||||||
|
|
||||||
## Insertion helper method
|
## Insertion helper method
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,13 @@ Vikunjs provides a simple abstraction to send notifications per mail and in the
|
||||||
|
|
||||||
Each notification has to implement this interface:
|
Each notification has to implement this interface:
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
type Notification interface {
|
type Notification interface {
|
||||||
ToMail() *Mail
|
ToMail() *Mail
|
||||||
ToDB() interface{}
|
ToDB() interface{}
|
||||||
Name() string
|
Name() string
|
||||||
}
|
}
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
||||||
Both functions return the formatted messages for mail and database.
|
Both functions return the formatted messages for mail and database.
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ For example, if your notification should not be recorded in the database but onl
|
||||||
|
|
||||||
A list of chainable functions is available to compose a mail:
|
A list of chainable functions is available to compose a mail:
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
mail := NewMail().
|
mail := NewMail().
|
||||||
// The optional sender of the mail message.
|
// The optional sender of the mail message.
|
||||||
From("test@example.com").
|
From("test@example.com").
|
||||||
|
@ -54,7 +54,7 @@ mail := NewMail().
|
||||||
Action("The Action", "https://example.com").
|
Action("The Action", "https://example.com").
|
||||||
// Another line of text.
|
// Another line of text.
|
||||||
Line("This should be an outro line").
|
Line("This should be an outro line").
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
||||||
If not provided, the `from` field of the mail contains the value configured in [`mailer.fromemail`](https://vikunja.io/docs/config-options/#fromemail).
|
If not provided, the `from` field of the mail contains the value configured in [`mailer.fromemail`](https://vikunja.io/docs/config-options/#fromemail).
|
||||||
|
|
||||||
|
@ -75,14 +75,14 @@ It takes the name of the notification and the package where the notification wil
|
||||||
Notifiables can receive a notification.
|
Notifiables can receive a notification.
|
||||||
A notifiable is defined with this interface:
|
A notifiable is defined with this interface:
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
type Notifiable interface {
|
type Notifiable interface {
|
||||||
// Should return the email address this notifiable has.
|
// Should return the email address this notifiable has.
|
||||||
RouteForMail() string
|
RouteForMail() string
|
||||||
// Should return the id of the notifiable entity
|
// Should return the id of the notifiable entity
|
||||||
RouteForDB() int64
|
RouteForDB() int64
|
||||||
}
|
}
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
||||||
The `User` type from the `user` package implements this interface.
|
The `User` type from the `user` package implements this interface.
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ It takes a notifiable and a notification as input.
|
||||||
|
|
||||||
For example, the email confirm notification when a new user registers is sent like this:
|
For example, the email confirm notification when a new user registers is sent like this:
|
||||||
|
|
||||||
```golang
|
{{< highlight golang >}}
|
||||||
n := &EmailConfirmNotification{
|
n := &EmailConfirmNotification{
|
||||||
User: update.User,
|
User: update.User,
|
||||||
IsNew: false,
|
IsNew: false,
|
||||||
|
@ -101,7 +101,7 @@ n := &EmailConfirmNotification{
|
||||||
|
|
||||||
err = notifications.Notify(update.User, n)
|
err = notifications.Notify(update.User, n)
|
||||||
return
|
return
|
||||||
```
|
{{< /highlight >}}
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
date: "2019-02-12:00:00+02:00"
|
date: "2019-02-12:00:00+02:00"
|
||||||
title: "Project structure"
|
title: "Project Structure"
|
||||||
draft: false
|
draft: false
|
||||||
type: "doc"
|
type: "doc"
|
||||||
menu:
|
menu:
|
||||||
|
@ -10,40 +10,7 @@ menu:
|
||||||
|
|
||||||
# Project structure
|
# Project structure
|
||||||
|
|
||||||
In general, this api repo has the following structure:
|
This document explains what each package does.
|
||||||
|
|
||||||
* `docker`
|
|
||||||
* `docs`
|
|
||||||
* `pkg`
|
|
||||||
* `caldav`
|
|
||||||
* `cmd`
|
|
||||||
* `config`
|
|
||||||
* `db`
|
|
||||||
* `fixtures`
|
|
||||||
* `files`
|
|
||||||
* `integration`
|
|
||||||
* `log`
|
|
||||||
* `mail`
|
|
||||||
* `metrics`
|
|
||||||
* `migration`
|
|
||||||
* `models`
|
|
||||||
* `modules`
|
|
||||||
* `migration`
|
|
||||||
* `handler`
|
|
||||||
* `wunderlist`
|
|
||||||
* `red`
|
|
||||||
* `routes`
|
|
||||||
* `api/v1`
|
|
||||||
* `static`
|
|
||||||
* `swagger`
|
|
||||||
* `user`
|
|
||||||
* `utils`
|
|
||||||
* `version`
|
|
||||||
* `REST-Tests`
|
|
||||||
* `templates`
|
|
||||||
* `vendor`
|
|
||||||
|
|
||||||
This document will explain what these mean and what you can find where.
|
|
||||||
|
|
||||||
{{< table_of_contents >}}
|
{{< table_of_contents >}}
|
||||||
|
|
||||||
|
@ -52,18 +19,13 @@ This document will explain what these mean and what you can find where.
|
||||||
The root directory is where [the config file]({{< ref "../setup/config.md">}}), [Magefile]({{< ref "mage.md">}}), license, drone config,
|
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.
|
application entry point (`main.go`) and so on are located.
|
||||||
|
|
||||||
## docker
|
|
||||||
|
|
||||||
This directory holds additonal files needed to build and run the docker container, mainly service configuration to properly run Vikunja inside a docker
|
|
||||||
container.
|
|
||||||
|
|
||||||
## pkg
|
## pkg
|
||||||
|
|
||||||
This is where most of the magic happens. Most packages with actual code are located in this folder.
|
This is where most of the magic happens. Most packages with actual code are located in this folder.
|
||||||
|
|
||||||
### caldav
|
### caldav
|
||||||
|
|
||||||
This folder holds a simple caldav implementation which is responsible for returning the caldav feature.
|
This folder holds a simple caldav implementation which is responsible for the caldav feature.
|
||||||
|
|
||||||
### cmd
|
### cmd
|
||||||
|
|
||||||
|
@ -75,10 +37,15 @@ To learn more about how to use this cli, see [the cli usage docs]({{< ref "../us
|
||||||
|
|
||||||
### config
|
### config
|
||||||
|
|
||||||
This package configures the config. It sets default values and sets up viper and tells it where to look for config files,
|
This package configures handling of Vikunja's runtime configuration.
|
||||||
how to interpret which env variables for config etc.
|
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.
|
||||||
|
|
||||||
If you want to add a new config parameter, you should add default value in this package.
|
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
|
### db
|
||||||
|
|
||||||
|
@ -102,17 +69,17 @@ This init is called in `main.go` after the config init is done.
|
||||||
|
|
||||||
### mail
|
### mail
|
||||||
|
|
||||||
This package handles all mail sending. To learn how to send a mail, see [sending emails]({{< ref "../practical-instructions/mail.md">}}).
|
This package handles all mail sending. To learn how to send a mail, see [notifications]({{< ref "notifications.md" >}}).
|
||||||
|
|
||||||
### metrics
|
### metrics
|
||||||
|
|
||||||
This package handles all metrics which are exposed to the prometheus endpoint.
|
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 "../practical-instructions/metrics.md">}}).
|
To learn how it works and how to add new metrics, take a look at [how metrics work]({{< ref "metrics.md">}}).
|
||||||
|
|
||||||
### migration
|
### migration
|
||||||
|
|
||||||
This package handles all migrations.
|
This package handles all migrations.
|
||||||
All migrations are stored and executed here.
|
All migrations are stored and executed in this package.
|
||||||
|
|
||||||
To learn more, take a look at the [migrations docs]({{< ref "../development/db-migrations.md">}}).
|
To learn more, take a look at the [migrations docs]({{< ref "../development/db-migrations.md">}}).
|
||||||
|
|
||||||
|
@ -123,11 +90,35 @@ When adding new features or upgrading existing ones, that most likely happens he
|
||||||
|
|
||||||
Because this package is pretty huge, there are several documents and how-to's about it:
|
Because this package is pretty huge, there are several documents and how-to's about it:
|
||||||
|
|
||||||
* [Adding a feature]({{< ref "../practical-instructions/feature.md">}})
|
* [Adding a feature]({{< ref "feature.md">}})
|
||||||
* [Making calls to the database]({{< ref "../practical-instructions/database.md">}})
|
* [Making calls to the database]({{< ref "database.md">}})
|
||||||
|
|
||||||
### modules
|
### 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 list 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
|
#### migration
|
||||||
|
|
||||||
See [writing a migrator]({{< ref "migration.md" >}}).
|
See [writing a migrator]({{< ref "migration.md" >}}).
|
||||||
|
@ -142,20 +133,19 @@ 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.
|
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
|
### routes
|
||||||
|
|
||||||
This package defines all routes which are available for vikunja clients to use.
|
This package defines all routes which are available for vikunja clients to use.
|
||||||
To add a new route, see [adding a new route]({{< ref "../practical-instructions/feature.md">}}).
|
To add a new route, see [adding a new route]({{< ref "feature.md">}}).
|
||||||
|
|
||||||
#### api/v1
|
#### api/v1
|
||||||
|
|
||||||
This is where all http-handler functions for the api are stored.
|
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.
|
Every handler function which does not use the standard web handler should live here.
|
||||||
|
|
||||||
### static
|
|
||||||
|
|
||||||
All static files generated by `mage generate` live here.
|
|
||||||
|
|
||||||
### swagger
|
### swagger
|
||||||
|
|
||||||
This is where the [generated]({{< ref "mage.md#generate-swagger-definitions-from-code-comments">}} [api docs]({{< ref "../usage/api.md">}}) live.
|
This is where the [generated]({{< ref "mage.md#generate-swagger-definitions-from-code-comments">}} [api docs]({{< ref "../usage/api.md">}}) live.
|
||||||
|
@ -179,23 +169,3 @@ See their function definitions for instructions on how to use them.
|
||||||
The single purpouse of this package is to hold the current vikunja version which gets overridden through build flags
|
The single purpouse 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.
|
each time `mage release` or `mage build` is run.
|
||||||
It is a seperate package to avoid import cycles with other packages.
|
It is a seperate package to avoid import cycles with other packages.
|
||||||
|
|
||||||
## REST-Tests
|
|
||||||
|
|
||||||
Holds all kinds of test files to directly test the api from inside of [jetbrains ide's](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html).
|
|
||||||
|
|
||||||
These files are currently more an experiment, maybe we will drop them in the future to use something we could integrate in the testing process with drone.
|
|
||||||
Therefore, this has no claim to be complete yet even working, you're free to change whatever is needed to get it working for you.
|
|
||||||
|
|
||||||
## templates
|
|
||||||
|
|
||||||
Holds the email templates used to send plain text and html emails for new user registration and password changes.
|
|
||||||
|
|
||||||
## vendor
|
|
||||||
|
|
||||||
All libraries needed to build Vikunja.
|
|
||||||
|
|
||||||
We keep all libraries used for Vikunja around in the `vendor/` folder to still be able to build the project even if
|
|
||||||
some maintainers take their libraries down like [it happened in the past](https://github.com/jteeuwen/go-bindata/issues/5).
|
|
||||||
|
|
||||||
When adding a new dependency, make sure to run `go mod vendor` to put it inside this directory.
|
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
---
|
---
|
||||||
date: "2019-02-12:00:00+02:00"
|
date: "2019-02-12:00:00+02:00"
|
||||||
title: "Modifying swagger api docs"
|
title: "Modifying Swagger API Docs"
|
||||||
draft: false
|
draft: false
|
||||||
type: "doc"
|
type: "doc"
|
||||||
menu:
|
menu:
|
||||||
sidebar:
|
sidebar:
|
||||||
parent: "practical instructions"
|
parent: "development"
|
||||||
---
|
---
|
||||||
|
|
||||||
# Adding/editing swagger api docs
|
# Modifying swagger api docs
|
||||||
|
|
||||||
The api documentation is generated using [swaggo](https://github.com/swaggo/swag) from comments.
|
The api documentation is generated using [swaggo](https://github.com/swaggo/swag) from comments.
|
||||||
|
|
||||||
|
{{< table_of_contents >}}
|
||||||
|
|
||||||
## Documenting structs
|
## Documenting structs
|
||||||
|
|
||||||
You should always comment every field which will be exposed as a json in the api.
|
You should always comment every field which will be exposed as a json in the api.
|
||||||
|
@ -45,3 +47,27 @@ type List struct {
|
||||||
web.Rights `xorm:"-" json:"-"`
|
web.Rights `xorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
{{< /highlight >}}
|
{{< /highlight >}}
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
|
{{< highlight golang >}}
|
||||||
|
// @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
|
||||||
|
}
|
||||||
|
{{< /highlight >}}
|
|
@ -10,7 +10,7 @@ menu:
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
|
|
||||||
You can run unit tests with [our `Magefile`]({{< ref "mage.md">}}) with
|
You can run unit tests with [mage]({{< ref "mage.md">}}) with
|
||||||
|
|
||||||
{{< highlight bash >}}
|
{{< highlight bash >}}
|
||||||
mage test:unit
|
mage test:unit
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-02-12:00:00+02:00"
|
|
||||||
title: "Database"
|
|
||||||
draft: false
|
|
||||||
type: "doc"
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "practical instructions"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Database
|
|
||||||
|
|
||||||
Vikunja uses [xorm](http://xorm.io/) as an abstraction layer to handle the database connection.
|
|
||||||
Please refer to [their](http://xorm.io/docs/) documentation on how to exactly use it.
|
|
||||||
|
|
||||||
Inside the `models` package, a variable `x` is available which contains a pointer to an instance of `xorm.Engine`.
|
|
||||||
This is used whenever you make a call to the database to get or update data.
|
|
||||||
|
|
||||||
This xorm instance is set up and initialized every time vikunja is started.
|
|
||||||
|
|
||||||
{{< table_of_contents >}}
|
|
||||||
|
|
||||||
## Adding new database tables
|
|
||||||
|
|
||||||
To add a new table to the database, add a an instance of your struct to the `tables` variable in the
|
|
||||||
init function in `pkg/models/models.go`. Xorm will sync them automatically.
|
|
||||||
|
|
||||||
You also need to add a pointer to the `tablesWithPointer` slice to enable caching for all instances of this struct.
|
|
||||||
|
|
||||||
To learn more about how to configure your struct to create "good" tables, refer to [the xorm documentaion](http://xorm.io/docs/).
|
|
||||||
|
|
||||||
## Adding data to test fixtures
|
|
||||||
|
|
||||||
Adding data for test fixtures is done in via `yaml` files insinde of `pkg/models/fixtures`.
|
|
||||||
|
|
||||||
The name of the yaml file should equal the table name in the database.
|
|
||||||
Adding values to it is done via array definition inside of the yaml file.
|
|
||||||
|
|
||||||
**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,86 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-02-12:00:00+02:00"
|
|
||||||
title: "Mailer"
|
|
||||||
draft: false
|
|
||||||
type: "doc"
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "practical instructions"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Mailer
|
|
||||||
|
|
||||||
This document explains how to use the mailer to send emails and what to do to create a new kind of email to be sent.
|
|
||||||
|
|
||||||
{{< table_of_contents >}}
|
|
||||||
|
|
||||||
## Sending emails
|
|
||||||
|
|
||||||
**Note:** You should use mail templates whenever possible (see below).
|
|
||||||
|
|
||||||
To send an email, use the function `mail.SendMail(options)`. The options are defined as follows:
|
|
||||||
|
|
||||||
{{< highlight golang >}}
|
|
||||||
type Opts struct {
|
|
||||||
To string // The email address of the recipent
|
|
||||||
Subject string // The subject of the mail
|
|
||||||
Message string // The plaintext message in the mail
|
|
||||||
HTMLMessage string // The html message
|
|
||||||
ContentType ContentType // The content type of the mail. Can be either mail.ContentTypePlain, mail.ContentTypeHTML, mail.ContentTypeMultipart. You should set this according to the kind of mail you want to send.
|
|
||||||
Boundary string
|
|
||||||
Headers []*header // Other headers to set in the mail.
|
|
||||||
}
|
|
||||||
{{< /highlight >}}
|
|
||||||
|
|
||||||
### Sending emails based on a template
|
|
||||||
|
|
||||||
For each mail with a template, there are two email templates: One for plaintext emails, one for html emails.
|
|
||||||
|
|
||||||
These are located in the `templates/mail` folder and follow the conventions of `template-name.{plain|hmtl}.tmpl`,
|
|
||||||
both the plaintext and html templates are in the same folder.
|
|
||||||
|
|
||||||
To send a mail based on a template, use the function `mail.SendMailWithTemplate(to, subject, tpl string, data map[string]interface{})`.
|
|
||||||
`to` and `subject` are pretty much self-explanatory, `tpl` is the name of the template, without `.html.tmpl` or `.plain.tmpl`.
|
|
||||||
`data` is a map you can pass additional data to your template.
|
|
||||||
|
|
||||||
### Sending a mail with a template
|
|
||||||
|
|
||||||
A basic html email template would look like this:
|
|
||||||
|
|
||||||
{{< highlight go-html-template >}}
|
|
||||||
{{template "mail-header.tmpl" .}}
|
|
||||||
<p>
|
|
||||||
Hey there!<br/>
|
|
||||||
This is a minimal html email example.<br/>
|
|
||||||
{{.Something}}
|
|
||||||
</p>
|
|
||||||
{{template "mail-footer.tmpl"}}
|
|
||||||
{{< /highlight >}}
|
|
||||||
|
|
||||||
And the corresponding plaintext template:
|
|
||||||
|
|
||||||
{{< highlight go-text-template >}}
|
|
||||||
Hey there!
|
|
||||||
|
|
||||||
This is a minimal html email example.
|
|
||||||
|
|
||||||
{{.Something}}
|
|
||||||
{{< /highlight >}}
|
|
||||||
You would then call this like so:
|
|
||||||
|
|
||||||
{{< highlight golang >}}
|
|
||||||
data := make(map[string]interface{})
|
|
||||||
data["Something"] = "I am some computed value"
|
|
||||||
to := "test@example.com"
|
|
||||||
subject := "A simple test mail"
|
|
||||||
tpl := "demo" // Assuming you saved the templates as demo.plain.tmpl and demo.html.tmpl
|
|
||||||
mail.SendMailWithTemplate(to, subject, tpl, data)
|
|
||||||
{{< /highlight >}}
|
|
||||||
|
|
||||||
The function does not return an error. If an error occures when sending a mail, it is logged but not returned because sending the mail happens asinchrounly.
|
|
||||||
|
|
||||||
Notice the `mail-header.tmpl` and `mail-footer.tmpl` in the template. These populate some basic css, a box for your content and the vikunja logo.
|
|
||||||
All that's left for you is to put the content in, which then will appear in a beautifully-styled box.
|
|
||||||
|
|
||||||
Remeber, these are email templates. This is different from normal html/css, you cannot use whatever you want (because most of the clients are wayyy to outdated).
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
---
|
|
||||||
date: "2019-02-12:00:00+02:00"
|
|
||||||
title: "Adding new config options"
|
|
||||||
draft: false
|
|
||||||
type: "doc"
|
|
||||||
menu:
|
|
||||||
sidebar:
|
|
||||||
parent: "practical instructions"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Adding new config options
|
|
||||||
|
|
||||||
Vikunja uses [viper](https://github.com/spf13/viper) to handle configuration options.
|
|
||||||
It handles parsing all different configuration sources.
|
|
||||||
|
|
||||||
The configuration is done in sections. These are represented with a `.` in viper.
|
|
||||||
Take a look at `pkg/config/config.go` to understand how these are set.
|
|
||||||
|
|
||||||
To add a new config option, you should add a default value to `pkg/config/config.go`.
|
|
||||||
Default values should always enable the feature to work somehow, or turn it off completely if it always needs
|
|
||||||
additional configuration.
|
|
||||||
|
|
||||||
Make sure to add the new config option to [the config document]({{< ref "../setup/config.md">}}) and the default config file
|
|
||||||
(`config.yml.sample` at the root of the repository) to make sure it is well documented.
|
|
||||||
|
|
||||||
If you're using a computed value as a default, make sure to update the sample config file and debian
|
|
||||||
post-install scripts to reflect that.
|
|
||||||
|
|
||||||
To get a configured option, use `viper.Get("config.option")`.
|
|
||||||
Take a look at [viper's documentation](https://github.com/spf13/viper#getting-values-from-viper) to learn of the
|
|
||||||
different ways available to get config options.
|
|
Loading…
Reference in a new issue