Docs improvements

This commit is contained in:
kolaente 2021-07-14 00:25:12 +02:00
parent 4216ed7277
commit 7ee535de47
No known key found for this signature in database
GPG key ID: F40E70337AB24C9B
19 changed files with 232 additions and 317 deletions

View file

@ -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:

View 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.

View 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).

View 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.

View file

@ -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 >}}

View file

@ -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 cant 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.
Thats 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.

View file

@ -5,7 +5,7 @@ draft: false
type: "doc" type: "doc"
menu: menu:
sidebar: sidebar:
parent: "practical instructions" parent: "development"
--- ---
# Custom Errors # Custom Errors

View file

@ -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 >}}

View file

@ -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

View file

@ -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

View file

@ -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`.

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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 >}}

View file

@ -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

View file

@ -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.

View file

@ -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).

View file

@ -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.