Compare commits

...

18 Commits

Author SHA1 Message Date
kolaente 3d9fcb9ffb
fix(ci): pipeline dependency 2022-11-12 14:32:16 +01:00
kolaente a6e214b654
feat: use docker buildx to build multiarch images 2022-11-12 14:30:48 +01:00
renovate c47e07f9b0 fix(deps): update module golang.org/x/crypto to v0.2.0 (#1315)
Reviewed-on: vikunja/api#1315
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-12 13:14:07 +00:00
renovate 3a4a04ee8e fix(deps): update module github.com/yuin/goldmark to v1.5.3 (#1317)
Reviewed-on: vikunja/api#1317
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-12 12:15:44 +00:00
kolaente 96b5e93379
fix: swagger docs 2022-11-11 15:34:26 +01:00
kolaente 87c2e442f2
chore: 0.20.1 release preperations 2022-11-11 11:59:49 +01:00
kolaente 33e27c66a0
fix(filters): try parsing invalid dates like 2022-11-1 2022-11-11 11:05:21 +01:00
kolaente 986129a784
fix(filters): try parsing dates without time 2022-11-11 10:54:50 +01:00
kolaente 3d7605591e
fix(filters): try to parse date filter fields of the provided dates are not valid iso dates
Resolves https://community.vikunja.io/t/due-date-saved-filter-doesnt-seem-to-work/966/12
2022-11-10 16:39:44 +01:00
kolaente 811514855b
fix(metrics): make currently active users actually work 2022-11-09 21:12:17 +01:00
kolaente a9e6776abf
fix(tasks): allow sorting by task index 2022-11-09 14:43:31 +01:00
renovate 15828df041 fix(deps): update module github.com/getsentry/sentry-go to v0.15.0 (#1314)
Reviewed-on: vikunja/api#1314
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-09 11:15:57 +00:00
kolaente f9b48ec091
fix(filter): only check for 0 values in filter fields with numeric values 2022-11-08 17:03:07 +01:00
kolaente 3b0b4a8460
fix(task): duplicate reminders when adding different ones between winter / summer time
Resolves F-889
2022-11-08 16:50:19 +01:00
kolaente 2ef5e54588
fix(filter): also check for 0 values if the filter should include nulls
Resolves https://community.vikunja.io/t/due-date-saved-filter-doesnt-seem-to-work/966
2022-11-08 16:27:16 +01:00
renovate 65bca226e0 fix(deps): update module github.com/prometheus/client_golang to v1.14.0 (#1313)
Reviewed-on: vikunja/api#1313
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-08 13:11:14 +00:00
renovate 63a9148132 fix(deps): update module golang.org/x/term to v0.2.0 (#1312)
Reviewed-on: vikunja/api#1312
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-08 07:26:13 +00:00
renovate b880d0e300 fix(deps): update module golang.org/x/sys to v0.2.0 (#1311)
Reviewed-on: vikunja/api#1311
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-07 20:15:54 +00:00
22 changed files with 206 additions and 307 deletions

View File

@ -1,4 +1,7 @@
files/
dist/
logs/
Dockerfile
docker-manifest.tmpl
docker-manifest-unstable.tmpl

View File

@ -627,102 +627,11 @@ steps:
---
kind: pipeline
type: docker
name: docker-arm-release
name: docker-release
depends_on:
- testing
platform:
os: linux
arch: arm64
trigger:
ref:
- refs/heads/main
- "refs/tags/**"
steps:
- name: fetch-tags
image: docker:git
commands:
- git fetch --tags
- name: docker-arm-unstable
image: plugins/docker:linux-arm
pull: true
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: vikunja/api
tags: unstable-linux-arm
dockerfile: Dockerfile.arm32
depends_on: [ fetch-tags ]
when:
ref:
- refs/heads/main
- name: docker-arm
image: plugins/docker:linux-arm
pull: true
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: vikunja/api
auto_tag: true
auto_tag_suffix: linux-arm
dockerfile: Dockerfile.arm32
depends_on: [ fetch-tags ]
when:
ref:
- "refs/tags/**"
- name: docker-arm64-unstable
image: plugins/docker:linux-arm64
pull: true
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: vikunja/api
tags: unstable-linux-arm64
depends_on: [ fetch-tags ]
when:
ref:
- refs/heads/main
- name: docker-arm64
image: plugins/docker:linux-arm64
pull: true
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: vikunja/api
auto_tag: true
auto_tag_suffix: linux-arm64
depends_on: [ fetch-tags ]
when:
ref:
- "refs/tags/**"
---
kind: pipeline
type: docker
name: docker-amd64-release
depends_on:
- testing
platform:
os: linux
arch: amd64
trigger:
ref:
- refs/heads/main
@ -735,7 +644,8 @@ steps:
- git fetch --tags
- name: docker-unstable
image: plugins/docker:linux-amd64
image: thegeeklab/drone-docker-buildx
privileged: true
pull: true
settings:
username:
@ -743,86 +653,36 @@ steps:
password:
from_secret: docker_password
repo: vikunja/api
tags: unstable-linux-amd64
depends_on: [ fetch-tags ]
when:
ref:
- refs/heads/main
- name: docker
image: plugins/docker:linux-amd64
pull: true
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: vikunja/api
auto_tag: true
auto_tag_suffix: linux-amd64
depends_on: [ fetch-tags ]
when:
ref:
- "refs/tags/**"
---
kind: pipeline
type: docker
name: docker-manifest
trigger:
ref:
- refs/heads/main
- "refs/tags/**"
depends_on:
- docker-amd64-release
- docker-arm-release
steps:
- name: manifest-unstable
pull: always
image: plugins/manifest
settings:
tags: unstable
ignore_missing: true
spec: docker-manifest-unstable.tmpl
password:
from_secret: docker_password
username:
from_secret: docker_username
platforms:
- linux/386
- linux/amd64
- linux/arm/v6
- linux/arm/v7
- linux/arm64/v8
depends_on: [ fetch-tags ]
when:
ref:
- refs/heads/main
- name: manifest-release
pull: always
image: plugins/manifest
- name: docker-release
image: thegeeklab/drone-docker-buildx
privileged: true
pull: true
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
repo: vikunja/api
auto_tag: true
ignore_missing: true
spec: docker-manifest.tmpl
password:
from_secret: docker_password
username:
from_secret: docker_username
when:
ref:
- "refs/tags/**"
- name: manifest-release-latest
pull: always
image: plugins/manifest
depends_on:
- clone
settings:
tags: latest
ignore_missing: true
spec: docker-manifest.tmpl
password:
from_secret: docker_password
username:
from_secret: docker_username
platforms:
- linux/386
- linux/amd64
- linux/arm/v6
- linux/arm/v7
- linux/arm64/v8
depends_on: [ fetch-tags ]
when:
ref:
- "refs/tags/**"
@ -841,9 +701,7 @@ depends_on:
- testing
- release
- deploy-docs
- docker-arm-release
- docker-amd64-release
- docker-manifest
- docker-release
steps:
- name: notify
@ -861,6 +719,6 @@ steps:
- failure
---
kind: signature
hmac: 5500acb776acae4975592637767035c45af277f1f56c8d10ffd99f38761cd5c8
hmac: 768d54fc8433705fb63f754adf19536a16152a4046a040afdbcbb7df60614056
...

View File

@ -7,6 +7,39 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
All releases can be found on https://code.vikunja.io/api/releases.
## [0.20.1] - 2022-11-11
### Bug Fixes
* *(docs)* Add explanation on how to run the cli in docker
* *(filter)* Also check for 0 values if the filter should include nulls
* *(filter)* Only check for 0 values in filter fields with numeric values
* *(filters)* Try to parse date filter fields of the provided dates are not valid iso dates
* *(filters)* Try parsing dates without time
* *(filters)* Try parsing invalid dates like 2022-11-1
* *(metrics)* Make currently active users actually work
* *(task)* Duplicate reminders when adding different ones between winter / summer time
* *(tasks)* Allow sorting by task index* Make sure task indexes are calculated correctly when moving tasks between lists ([c495096](c4950964443a9bffc4cdd8fc25004ad951520f20))
* Look for the default bucket based on the position instead of the index ([622f2f0](622f2f0562bd8e3a5c97ec0b001c646a33a86c2b))
* Usage with postgres over unix socket (#1308) ([641a9da](641a9da93d24a18d6cbad2929eea1be6c1e0d0b2))
### Dependencies
* *(deps)* Update module github.com/prometheus/client_golang to v1.13.1 (#1307)
* *(deps)* Update module github.com/spf13/viper to v1.14.0 (#1309)
* *(deps)* Update module golang.org/x/sys to v0.2.0 (#1311)
* *(deps)* Update module golang.org/x/term to v0.2.0 (#1312)
* *(deps)* Update module github.com/prometheus/client_golang to v1.14.0 (#1313)
* *(deps)* Update module github.com/getsentry/sentry-go to v0.15.0 (#1314)
### Features
* *(docs)* Add relase checklist
### Other
* *(other)* Nessecary is a common misspelling of necessary (#1304)
## [0.20.0] - 2022-10-28
### Bug Fixes

View File

@ -1,9 +1,9 @@
##############
# Build stage
FROM golang:1.19-alpine AS build-env
FROM --platform=$BUILDPLATFORM techknowlogick/xgo:latest AS build-env
RUN apk --no-cache add build-base git && \
RUN \
go install github.com/magefile/mage@latest && \
mv /go/bin/mage /usr/local/go/bin
@ -13,9 +13,11 @@ ARG VIKUNJA_VERSION
COPY . /go/src/code.vikunja.io/api
WORKDIR /go/src/code.vikunja.io/api
ARG TARGETOS TARGETARCH TARGETVARIANT
# Checkout version if set
RUN if [ -n "${VIKUNJA_VERSION}" ]; then git checkout "${VIKUNJA_VERSION}"; fi \
&& mage build:clean build
RUN if [ -n "${VIKUNJA_VERSION}" ]; then git checkout "${VIKUNJA_VERSION}"; fi && \
mage build:clean && \
mage release:xgo $TARGETOS/$TARGETARCH/$TARGETVARIANT
###################
# The actual image
@ -25,7 +27,7 @@ FROM alpine:3.16
LABEL maintainer="maintainers@vikunja.io"
WORKDIR /app/vikunja/
COPY --from=build-env /go/src/code.vikunja.io/api/vikunja .
COPY --from=build-env /build/vikunja-* vikunja
ENV VIKUNJA_SERVICE_ROOTPATH=/app/vikunja/
# Dynamic permission changing stuff

View File

@ -1,48 +0,0 @@
##############
# Build stage
FROM golang:1.19-buster AS build-env
RUN go install github.com/magefile/mage@latest && \
mv /go/bin/mage /usr/local/go/bin
ARG VIKUNJA_VERSION
# Setup repo
COPY . /go/src/code.vikunja.io/api
WORKDIR /go/src/code.vikunja.io/api
# Checkout version if set
RUN if [ -n "${VIKUNJA_VERSION}" ]; then git checkout "${VIKUNJA_VERSION}"; fi \
&& mage build:clean build
###################
# The actual image
# Note: I wanted to use the scratch image here, but unfortunatly the go-sqlite bindings require cgo and
# because of this, the container would not start when I compiled the image without cgo.
# We're using debian as a base image here because the latest alpine image does not work with arm.
FROM debian:buster-slim
LABEL maintainer="maintainers@vikunja.io"
WORKDIR /app/vikunja/
COPY --from=build-env /go/src/code.vikunja.io/api/vikunja .
ENV VIKUNJA_SERVICE_ROOTPATH=/app/vikunja/
# Dynamic permission changing stuff
ENV PUID 1000
ENV PGID 1000
RUN addgroup --gid ${PGID} vikunja && \
chown ${PUID} -R /app/vikunja && \
useradd --shell /bin/sh --gid vikunja --uid ${PUID} --home-dir /app/vikunja vikunja
COPY run.sh /run.sh
# Fix time zone settings not working
RUN apt-get update && apt-get install -y tzdata && apt-get clean
# Files permissions
RUN mkdir /app/vikunja/files && \
chown -R vikunja /app/vikunja/files
VOLUME /app/vikunja/files
CMD ["/run.sh"]
EXPOSE 3456

View File

@ -2,7 +2,7 @@
[![Build Status](https://drone.kolaente.de/api/badges/vikunja/api/status.svg)](https://drone.kolaente.de/vikunja/api)
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](LICENSE)
[![Download](https://img.shields.io/badge/download-v0.20.0-brightgreen.svg)](https://dl.vikunja.io)
[![Download](https://img.shields.io/badge/download-v0.20.1-brightgreen.svg)](https://dl.vikunja.io)
[![Docker Pulls](https://img.shields.io/docker/pulls/vikunja/api.svg)](https://hub.docker.com/r/vikunja/api/)
[![Swagger Docs](https://img.shields.io/badge/swagger-docs-brightgreen.svg)](https://try.vikunja.io/api/v1/docs)
[![Go Report Card](https://goreportcard.com/badge/kolaente.dev/vikunja/api)](https://goreportcard.com/report/kolaente.dev/vikunja/api)

View File

@ -1,17 +0,0 @@
image: vikunja/api:unstable
manifests:
-
image: vikunja/api:unstable-linux-amd64
platform:
architecture: amd64
os: linux
-
image: vikunja/api:unstable-linux-arm64
platform:
architecture: arm64
os: linux
-
image: vikunja/api:unstable-linux-arm
platform:
architecture: arm
os: linux

View File

@ -1,23 +0,0 @@
image: vikunja/api:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
{{/if}}
manifests:
-
image: vikunja/api:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform:
architecture: amd64
os: linux
-
image: vikunja/api:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform:
architecture: arm64
os: linux
-
image: vikunja/api:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
platform:
architecture: arm
os: linux

16
go.mod
View File

@ -31,7 +31,7 @@ require (
github.com/disintegration/imaging v1.6.2
github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0
github.com/gabriel-vasile/mimetype v1.4.1
github.com/getsentry/sentry-go v0.14.0
github.com/getsentry/sentry-go v0.15.0
github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.6.0
github.com/go-testfixtures/testfixtures/v3 v3.8.1
@ -49,7 +49,7 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pquerna/otp v1.3.0
github.com/prometheus/client_golang v1.13.1
github.com/prometheus/client_golang v1.14.0
github.com/robfig/cron/v3 v3.0.1
github.com/samedi/caldav-go v3.0.0+incompatible
github.com/spf13/afero v1.9.2
@ -61,13 +61,13 @@ require (
github.com/ulule/limiter/v3 v3.10.0
github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93
github.com/wneessen/go-mail v0.3.4
github.com/yuin/goldmark v1.5.2
golang.org/x/crypto v0.1.0
github.com/yuin/goldmark v1.5.3
golang.org/x/crypto v0.2.0
golang.org/x/image v0.1.0
golang.org/x/oauth2 v0.1.0
golang.org/x/sync v0.1.0
golang.org/x/sys v0.1.0
golang.org/x/term v0.1.0
golang.org/x/sys v0.2.0
golang.org/x/term v0.2.0
gopkg.in/d4l3k/messagediff.v1 v1.2.1
gopkg.in/yaml.v3 v3.0.1
src.techknowlogick.com/xgo v1.5.1-0.20220906164532-735bfdfb90d9
@ -122,7 +122,7 @@ require (
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
@ -135,7 +135,7 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.1.0 // indirect
golang.org/x/net v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
golang.org/x/tools v0.1.12 // indirect

16
go.sum
View File

@ -208,6 +208,8 @@ github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/getsentry/sentry-go v0.14.0 h1:rlOBkuFZRKKdUnKO+0U3JclRDQKlRu5vVQtkWSQvC70=
github.com/getsentry/sentry-go v0.14.0/go.mod h1:RZPJKSw+adu8PBNygiri/A98FqVr2HtRckJk9XVxJ9I=
github.com/getsentry/sentry-go v0.15.0 h1:CP9bmA7pralrVUedYZsmIHWpq/pBtXTSew7xvVpfLaA=
github.com/getsentry/sentry-go v0.15.0/go.mod h1:RZPJKSw+adu8PBNygiri/A98FqVr2HtRckJk9XVxJ9I=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
@ -646,6 +648,8 @@ github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPk
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.13.1 h1:3gMjIY2+/hzmqhtUC/aQNYldJA6DtH3CgQvwS+02K1c=
github.com/prometheus/client_golang v1.13.1/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -653,6 +657,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
@ -781,6 +787,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.2 h1:ALmeCk/px5FSm1MAcFBAsVKZjDuMVj8Tm7FFIlMJnqU=
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.3 h1:3HUJmBFbQW9fhQOzMgseU134xfi6hU+mjWywx5Ty+/M=
github.com/yuin/goldmark v1.5.3/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@ -829,6 +837,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE=
golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -927,6 +937,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1060,11 +1072,15 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -546,6 +546,20 @@ func (Release) Darwin() error {
return runXgo("darwin-10.15/*")
}
func (Release) Xgo(target string) error {
parts := strings.Split(target, "/")
if len(parts) < 2 {
return fmt.Errorf("invalid target")
}
variant := ""
if len(parts) > 2 && parts[2] != "" {
variant = "-" + strings.ReplaceAll(parts[2], "v", "")
}
return runXgo(parts[0] + "/" + parts[1] + variant)
}
// Compresses the built binaries in dist/binaries/ to reduce their filesize
func (Release) Compress(ctx context.Context) error {
// $(foreach file,$(filter-out $(wildcard $(wildcard $(DIST)/binaries/$(EXECUTABLE)-*mips*)),$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*)), upx -9 $(file);)

View File

@ -28,7 +28,7 @@ import (
)
// SecondsUntilInactive defines the seconds until a user is considered inactive
const SecondsUntilInactive = 60
const SecondsUntilInactive = 30
// ActiveUsersKey is the key used to store active users in redis
const ActiveUsersKey = `activeusers`
@ -55,12 +55,13 @@ func init() {
users: make(map[int64]*ActiveUser),
mutex: &sync.Mutex{},
}
}
promauto.NewGaugeFunc(prometheus.GaugeOpts{
func setupActiveUsersMetric() {
err := registry.Register(promauto.NewGaugeFunc(prometheus.GaugeOpts{
Name: "vikunja_active_users",
Help: "The currently active users on this node",
Help: "The number of users active within the last 30 seconds on this node",
}, func() float64 {
allActiveUsers, err := getActiveUsers()
if err != nil {
log.Error(err.Error())
@ -75,7 +76,10 @@ func init() {
}
}
return float64(activeUsersCount)
})
}))
if err != nil {
log.Criticalf("Could not register metrics for currently active users: %s", err)
}
}
// SetUserActive sets a user as active and pushes it to redis

View File

@ -113,7 +113,7 @@ func InitMetrics() {
log.Criticalf("Could not register metrics for %s: %s", TaskCountKey, err)
}
// Register total user count metric
// Register total teams count metric
err = registry.Register(promauto.NewGaugeFunc(prometheus.GaugeOpts{
Name: "vikunja_team_count",
Help: "The total number of teams on this instance",
@ -124,9 +124,11 @@ func InitMetrics() {
if err != nil {
log.Criticalf("Could not register metrics for %s: %s", TeamCountKey, err)
}
setupActiveUsersMetric()
}
// GetCount returns the current count from redis
// GetCount returns the current count from keyvalue
func GetCount(key string) (count int64, err error) {
cnt, exists, err := keyvalue.Get(key)
if err != nil {

View File

@ -74,7 +74,8 @@ func validateTaskField(fieldName string) error {
taskPropertyUpdated,
taskPropertyPosition,
taskPropertyKanbanPosition,
taskPropertyBucketID:
taskPropertyBucketID,
taskPropertyIndex:
return nil
}
return ErrInvalidTaskField{TaskField: fieldName}

View File

@ -24,6 +24,7 @@ import (
"time"
"code.vikunja.io/api/pkg/config"
"github.com/iancoleman/strcase"
"github.com/vectordotdev/go-datemath"
"xorm.io/xorm/schemas"
@ -44,10 +45,47 @@ const (
taskFilterComparatorIn taskFilterComparator = "in"
)
// Guess what you get back if you ask Safari for a rfc 3339 formatted date?
const safariDateAndTime = "2006-01-02 15:04"
const safariDate = "2006-01-02"
type taskFilter struct {
field string
value interface{} // Needs to be an interface to be able to hold the field's native value
comparator taskFilterComparator
isNumeric bool
}
func parseTimeFromUserInput(timeString string) (value time.Time, err error) {
value, err = time.Parse(time.RFC3339, timeString)
if err != nil {
value, err = time.Parse(safariDateAndTime, timeString)
}
if err != nil {
value, err = time.Parse(safariDate, timeString)
}
if err != nil {
// Here we assume a date like 2022-11-1 and try to parse it manually
parts := strings.Split(timeString, "-")
if len(parts) < 3 {
return
}
year, err := strconv.Atoi(parts[0])
if err != nil {
return value, err
}
month, err := strconv.Atoi(parts[1])
if err != nil {
return value, err
}
day, err := strconv.Atoi(parts[2])
if err != nil {
return value, err
}
value = time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
return value.In(config.GetTimeZone()), nil
}
return value.In(config.GetTimeZone()), err
}
func getTaskFiltersByCollections(c *TaskCollection) (filters []*taskFilter, err error) {
@ -90,8 +128,9 @@ func getTaskFiltersByCollections(c *TaskCollection) (filters []*taskFilter, err
}
// Cast the field value to its native type
var reflectValue *reflect.StructField
if len(c.FilterValue) > i {
filter.value, err = getNativeValueForTaskField(filter.field, filter.comparator, c.FilterValue[i])
reflectValue, filter.value, err = getNativeValueForTaskField(filter.field, filter.comparator, c.FilterValue[i])
if err != nil {
return nil, ErrInvalidTaskFilterValue{
Value: filter.field,
@ -99,6 +138,9 @@ func getTaskFiltersByCollections(c *TaskCollection) (filters []*taskFilter, err
}
}
}
if reflectValue != nil {
filter.isNumeric = reflectValue.Type.Kind() == reflect.Int64
}
filters = append(filters, filter)
}
@ -165,8 +207,7 @@ func getValueForField(field reflect.StructField, rawValue string) (value interfa
if err == nil {
value = t.Time(datemath.WithLocation(config.GetTimeZone()))
} else {
value, err = time.Parse(time.RFC3339, rawValue)
value = value.(time.Time).In(config.GetTimeZone())
value, err = parseTimeFromUserInput(rawValue)
}
}
case reflect.Slice:
@ -192,7 +233,7 @@ func getValueForField(field reflect.StructField, rawValue string) (value interfa
return
}
func getNativeValueForTaskField(fieldName string, comparator taskFilterComparator, value string) (nativeValue interface{}, err error) {
func getNativeValueForTaskField(fieldName string, comparator taskFilterComparator, value string) (reflectField *reflect.StructField, nativeValue interface{}, err error) {
realFieldName := strings.ReplaceAll(strcase.ToCamel(fieldName), "Id", "ID")
@ -203,11 +244,11 @@ func getNativeValueForTaskField(fieldName string, comparator taskFilterComparato
for _, val := range vals {
v, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return nil, err
return nil, nil, err
}
valueSlice = append(valueSlice, v)
}
return valueSlice, nil
return nil, valueSlice, nil
}
nativeValue, err = strconv.ParseInt(value, 10, 64)
@ -217,12 +258,12 @@ func getNativeValueForTaskField(fieldName string, comparator taskFilterComparato
if realFieldName == "Assignees" {
vals := strings.Split(value, ",")
valueSlice := append([]string{}, vals...)
return valueSlice, nil
return nil, valueSlice, nil
}
field, ok := reflect.TypeOf(&Task{}).Elem().FieldByName(realFieldName)
if !ok {
return nil, ErrInvalidTaskField{TaskField: fieldName}
return nil, nil, ErrInvalidTaskField{TaskField: fieldName}
}
if comparator == taskFilterComparatorIn {
@ -231,12 +272,13 @@ func getNativeValueForTaskField(fieldName string, comparator taskFilterComparato
for _, val := range vals {
v, err := getValueForField(field, val)
if err != nil {
return nil, err
return nil, nil, err
}
valueSlice = append(valueSlice, v)
}
return valueSlice, nil
return nil, valueSlice, nil
}
return getValueForField(field, value)
val, err := getValueForField(field, value)
return &field, val, err
}

View File

@ -46,6 +46,7 @@ const (
taskPropertyPosition string = "position"
taskPropertyKanbanPosition string = "kanban_position"
taskPropertyBucketID string = "bucket_id"
taskPropertyIndex string = "index"
)
const (

View File

@ -202,7 +202,7 @@ func (rel *TaskRelation) Create(s *xorm.Session, a web.Auth) error {
// @Param relation body models.TaskRelation true "The relation object"
// @Param taskID path int true "Task ID"
// @Param relationKind path string true "The kind of the relation. See the TaskRelation type for more info."
// @Param otherTaskID path int true "The id of the other task."
// @Param otherTaskId path int true "The id of the other task."
// @Success 200 {object} models.Message "The task relation was successfully deleted."
// @Failure 400 {object} web.HTTPError "Invalid task relation object provided."
// @Failure 404 {object} web.HTTPError "The task relation was not found."

View File

@ -227,6 +227,9 @@ func getFilterCond(f *taskFilter, includeNulls bool) (cond builder.Cond, err err
if includeNulls {
cond = builder.Or(cond, &builder.IsNull{field})
if f.isNumeric {
cond = builder.Or(cond, &builder.IsNull{field}, &builder.Eq{field: 0})
}
}
return
@ -306,10 +309,10 @@ func getRawTasksForLists(s *xorm.Session, lists []*List, a web.Auth, opts *taskO
// Because it does not have support for NULLS FIRST or NULLS LAST we work around this by
// first sorting for null (or not null) values and then the order we actually want to.
if db.Type() == schemas.MYSQL {
orderby += param.sortBy + " IS NULL, "
orderby += "`" + param.sortBy + "` IS NULL, "
}
orderby += param.sortBy + " " + param.orderBy.String()
orderby += "`" + param.sortBy + "` " + param.orderBy.String()
// Postgres and sqlite allow us to control how columns with null values are sorted.
// To make that consistent with the sort order we have and other dbms, we're adding a separate clause here.
@ -580,7 +583,9 @@ func GetTasksByUIDs(s *xorm.Session, uids []string, a web.Auth) (tasks []*Task,
func getRemindersForTasks(s *xorm.Session, taskIDs []int64) (reminders []*TaskReminder, err error) {
reminders = []*TaskReminder{}
err = s.In("task_id", taskIDs).Find(&reminders)
err = s.In("task_id", taskIDs).
OrderBy("reminder asc").
Find(&reminders)
return
}
@ -1400,8 +1405,14 @@ func (t *Task) updateReminders(s *xorm.Session, reminders []time.Time) (err erro
return
}
// Resolve duplicates and sort them
reminderMap := make(map[string]time.Time, len(reminders))
for _, reminder := range reminders {
reminderMap[reminder.UTC().String()] = reminder
}
// Loop through all reminders and add them
for _, r := range reminders {
for _, r := range reminderMap {
_, err = s.Insert(&TaskReminder{TaskID: t.ID, Reminder: r})
if err != nil {
return err

View File

@ -47,7 +47,7 @@ func unsplashImage(url string, c echo.Context) error {
// @Description Get an unsplash image. **Returns json on error.**
// @tags list
// @Produce octet-stream
// @Param thumb path int true "Unsplash Image ID"
// @Param image path int true "Unsplash Image ID"
// @Security JWTKeyAuth
// @Success 200 {} string "The image"
// @Failure 404 {object} models.Message "The image does not exist."
@ -67,7 +67,7 @@ func ProxyUnsplashImage(c echo.Context) error {
// @Description Get an unsplash thumbnail image. The thumbnail is cropped to a max width of 200px. **Returns json on error.**
// @tags list
// @Produce octet-stream
// @Param thumb path int true "Unsplash Image ID"
// @Param image path int true "Unsplash Image ID"
// @Security JWTKeyAuth
// @Success 200 {} string "The thumbnail"
// @Failure 404 {object} models.Message "The image does not exist."

View File

@ -95,7 +95,7 @@ const docTemplate = `{
{
"type": "integer",
"description": "Unsplash Image ID",
"name": "thumb",
"name": "image",
"in": "path",
"required": true
}
@ -141,7 +141,7 @@ const docTemplate = `{
{
"type": "integer",
"description": "Unsplash Image ID",
"name": "thumb",
"name": "image",
"in": "path",
"required": true
}
@ -5688,7 +5688,7 @@ const docTemplate = `{
{
"type": "integer",
"description": "The id of the other task.",
"name": "otherTaskID",
"name": "otherTaskId",
"in": "path",
"required": true
}

View File

@ -86,7 +86,7 @@
{
"type": "integer",
"description": "Unsplash Image ID",
"name": "thumb",
"name": "image",
"in": "path",
"required": true
}
@ -132,7 +132,7 @@
{
"type": "integer",
"description": "Unsplash Image ID",
"name": "thumb",
"name": "image",
"in": "path",
"required": true
}
@ -5679,7 +5679,7 @@
{
"type": "integer",
"description": "The id of the other task.",
"name": "otherTaskID",
"name": "otherTaskId",
"in": "path",
"required": true
}

View File

@ -1509,7 +1509,7 @@ paths:
parameters:
- description: Unsplash Image ID
in: path
name: thumb
name: image
required: true
type: integer
produces:
@ -1539,7 +1539,7 @@ paths:
parameters:
- description: Unsplash Image ID
in: path
name: thumb
name: image
required: true
type: integer
produces:
@ -5247,7 +5247,7 @@ paths:
type: string
- description: The id of the other task.
in: path
name: otherTaskID
name: otherTaskId
required: true
type: integer
produces: