Compare commits

...

7 Commits

Author SHA1 Message Date
kolaente f93362defa
0.14.1 release preparations 2020-07-07 10:48:49 +02:00
konrad b1c750373e
Fix creating lists with non ascii characters (#607)
Fix test name

Fix migrating lists with non utf-8 characters in their name

Fix creating lists with non utf-8 characters

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#607
(cherry picked from commit 4db06ba9a1)
2020-07-07 10:13:04 +02:00
kolaente 960258a8c2
Fix parsing todoist reminder dates
(cherry picked from commit 78791f31a4)
2020-07-07 10:13:04 +02:00
kolaente 75f95e2afc
Fix parsing todoist reminder dates
(cherry picked from commit ec3fa9300b)
2020-07-07 10:13:04 +02:00
kolaente 13bed6f749
update theme
(cherry picked from commit 9fa7e30a0a)
2020-07-07 10:13:03 +02:00
kolaente 9024fa6c3a
Fix decoding active users from redis
(cherry picked from commit ae12871bd7)
2020-07-07 10:13:03 +02:00
kolaente d2d8c91c43
Make sure the metrics map accesses only happen explicitly
(cherry picked from commit 7141050f8b)
2020-07-07 10:13:03 +02:00
9 changed files with 72 additions and 25 deletions

View File

@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
All releases can be found on https://code.vikunja.io/api/releases. All releases can be found on https://code.vikunja.io/api/releases.
## [0.14.1] - 2020-07-07
### Fixed
* Fix creating lists with non ascii characters (#607)
* Fix decoding active users from redis
* Fix parsing todoist reminder dates
* Make sure the metrics map accesses only happen explicitly
### Changed
* Update docs theme
## [0.14.0] - 2020-07-01 ## [0.14.0] - 2020-07-01
### Added ### Added

View File

@ -2,7 +2,7 @@
[![Build Status](https://drone1.kolaente.de/api/badges/vikunja/api/status.svg)](https://drone1.kolaente.de/vikunja/api) [![Build Status](https://drone1.kolaente.de/api/badges/vikunja/api/status.svg)](https://drone1.kolaente.de/vikunja/api)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](LICENSE) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](LICENSE)
[![Download](https://img.shields.io/badge/download-v0.14.0-brightgreen.svg)](https://dl.vikunja.io) [![Download](https://img.shields.io/badge/download-v0.14.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/) [![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) [![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/git.kolaente.de/vikunja/api)](https://goreportcard.com/report/git.kolaente.de/vikunja/api) [![Go Report Card](https://goreportcard.com/badge/git.kolaente.de/vikunja/api)](https://goreportcard.com/report/git.kolaente.de/vikunja/api)

2
docs/themes/vikunja vendored

@ -1 +1 @@
Subproject commit f50566db25df9fa03243ba06d17511e050d4be95 Subproject commit a17ba5976906ee431943798c08e4d3c38689590d

View File

@ -23,6 +23,7 @@ import (
"encoding/gob" "encoding/gob"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
"sync"
"time" "time"
) )
@ -38,24 +39,35 @@ type ActiveUser struct {
LastSeen time.Time LastSeen time.Time
} }
type activeUsersMap map[int64]*ActiveUser
// ActiveUsersMap is the type used to save active users // ActiveUsersMap is the type used to save active users
type ActiveUsersMap map[int64]*ActiveUser type ActiveUsers struct {
users activeUsersMap
mutex *sync.Mutex
}
// activeUsers holds a map with all active users // activeUsers holds a map with all active users
var activeUsers ActiveUsersMap var activeUsers *ActiveUsers
func init() { func init() {
activeUsers = make(ActiveUsersMap) activeUsers = &ActiveUsers{
users: make(map[int64]*ActiveUser),
mutex: &sync.Mutex{},
}
promauto.NewGaugeFunc(prometheus.GaugeOpts{ promauto.NewGaugeFunc(prometheus.GaugeOpts{
Name: "vikunja_active_users", Name: "vikunja_active_users",
Help: "The currently active users on this node", Help: "The currently active users on this node",
}, func() float64 { }, func() float64 {
allActiveUsers, err := GetActiveUsers() allActiveUsers, err := getActiveUsers()
if err != nil { if err != nil {
log.Error(err.Error()) log.Error(err.Error())
} }
if allActiveUsers == nil {
return 0
}
activeUsersCount := 0 activeUsersCount := 0
for _, u := range allActiveUsers { for _, u := range allActiveUsers {
if time.Since(u.LastSeen) < SecondsUntilInactive*time.Second { if time.Since(u.LastSeen) < SecondsUntilInactive*time.Second {
@ -68,15 +80,17 @@ func init() {
// SetUserActive sets a user as active and pushes it to redis // SetUserActive sets a user as active and pushes it to redis
func SetUserActive(a web.Auth) (err error) { func SetUserActive(a web.Auth) (err error) {
activeUsers[a.GetID()] = &ActiveUser{ activeUsers.mutex.Lock()
activeUsers.users[a.GetID()] = &ActiveUser{
UserID: a.GetID(), UserID: a.GetID(),
LastSeen: time.Now(), LastSeen: time.Now(),
} }
activeUsers.mutex.Unlock()
return PushActiveUsers() return PushActiveUsers()
} }
// GetActiveUsers returns the active users from redis // getActiveUsers returns the active users from redis
func GetActiveUsers() (users ActiveUsersMap, err error) { func getActiveUsers() (users activeUsersMap, err error) {
activeUsersR, err := r.Get(ActiveUsersKey).Bytes() activeUsersR, err := r.Get(ActiveUsersKey).Bytes()
if err != nil { if err != nil {
@ -102,7 +116,9 @@ func GetActiveUsers() (users ActiveUsersMap, err error) {
func PushActiveUsers() (err error) { func PushActiveUsers() (err error) {
var b bytes.Buffer var b bytes.Buffer
e := gob.NewEncoder(&b) e := gob.NewEncoder(&b)
if err := e.Encode(activeUsers); err != nil { activeUsers.mutex.Lock()
defer activeUsers.mutex.Unlock()
if err := e.Encode(activeUsers.users); err != nil {
return err return err
} }

View File

@ -55,7 +55,7 @@ func init() {
// The general idea here is to take the title and slice it into pieces, until we found a unique piece. // The general idea here is to take the title and slice it into pieces, until we found a unique piece.
var exists = true var exists = true
titleSlug := strings.Replace(strings.ToUpper(l.Title), " ", "", -1) titleSlug := []rune(strings.Replace(strings.ToUpper(l.Title), " ", "", -1))
// We can save at most 10 characters in the db, so we need to ensure it has at most 10 characters // We can save at most 10 characters in the db, so we need to ensure it has at most 10 characters
if len(titleSlug) > 10 { if len(titleSlug) > 10 {
@ -72,7 +72,7 @@ func init() {
} }
// Take a random part of the title slug, starting at the beginning // Take a random part of the title slug, starting at the beginning
l.Identifier = titleSlug[i:] l.Identifier = string(titleSlug[i:])
exists, err = sess. exists, err = sess.
Where("identifier = ?", l.Identifier). Where("identifier = ?", l.Identifier).
And("id != ?", l.ID). And("id != ?", l.ID).

View File

@ -404,7 +404,7 @@ func GenerateListIdentifier(l *List, sess *xorm.Engine) (err error) {
// The general idea here is to take the title and slice it into pieces, until we found a unique piece. // The general idea here is to take the title and slice it into pieces, until we found a unique piece.
var exists = true var exists = true
titleSlug := strings.Replace(strings.ToUpper(l.Title), " ", "", -1) titleSlug := []rune(strings.Replace(strings.ToUpper(l.Title), " ", "", -1))
// We can save at most 10 characters in the db, so we need to ensure it has at most 10 characters // We can save at most 10 characters in the db, so we need to ensure it has at most 10 characters
if len(titleSlug) > 10 { if len(titleSlug) > 10 {
@ -421,7 +421,7 @@ func GenerateListIdentifier(l *List, sess *xorm.Engine) (err error) {
} }
// Take a random part of the title slug, starting at the beginning // Take a random part of the title slug, starting at the beginning
l.Identifier = titleSlug[i:] l.Identifier = string(titleSlug[i:])
exists, err = sess. exists, err = sess.
Where("identifier = ?", l.Identifier). Where("identifier = ?", l.Identifier).
And("id != ?", l.ID). And("id != ?", l.ID).

View File

@ -79,6 +79,16 @@ func TestList_CreateOrUpdate(t *testing.T) {
assert.Error(t, err) assert.Error(t, err)
assert.True(t, IsErrListIdentifierIsNotUnique(err)) assert.True(t, IsErrListIdentifierIsNotUnique(err))
}) })
t.Run("non ascii characters", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
list := List{
Title: "приффки фсем",
Description: "Lorem Ipsum",
NamespaceID: 1,
}
err := list.Create(usr)
assert.NoError(t, err)
})
}) })
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {

View File

@ -368,7 +368,15 @@ func convertTodoistToVikunja(sync *sync) (fullVikunjaHierachie []*models.Namespa
continue continue
} }
date, err := time.Parse("2006-01-02", r.Due.Date) var err error
var date time.Time
date, err = time.Parse("2006-01-02T15:04:05Z", r.Due.Date)
if err != nil {
date, err = time.Parse("2006-01-02T15:04:05", r.Due.Date)
}
if err != nil {
date, err = time.Parse("2006-01-02", r.Due.Date)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -274,7 +274,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
ID: 103001, ID: 103001,
ItemID: 400000000, ItemID: 400000000,
Due: &dueDate{ Due: &dueDate{
Date: "2020-06-16", Date: "2020-06-16T07:00:00",
IsRecurring: false, IsRecurring: false,
}, },
}, },
@ -282,7 +282,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
ID: 103002, ID: 103002,
ItemID: 400000002, ItemID: 400000002,
Due: &dueDate{ Due: &dueDate{
Date: "2020-07-15", Date: "2020-07-15T07:00:00Z",
IsRecurring: true, IsRecurring: true,
}, },
}, },
@ -290,7 +290,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
ID: 103003, ID: 103003,
ItemID: 400000003, ItemID: 400000003,
Due: &dueDate{ Due: &dueDate{
Date: "2020-06-15", Date: "2020-06-15T07:00:00",
IsRecurring: false, IsRecurring: false,
}, },
}, },
@ -298,7 +298,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
ID: 103004, ID: 103004,
ItemID: 400000005, ItemID: 400000005,
Due: &dueDate{ Due: &dueDate{
Date: "2020-06-15", Date: "2020-06-15T07:00:00",
IsRecurring: false, IsRecurring: false,
}, },
}, },
@ -306,7 +306,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
ID: 103006, ID: 103006,
ItemID: 400000009, ItemID: 400000009,
Due: &dueDate{ Due: &dueDate{
Date: "2020-06-15", Date: "2020-06-15T07:00:00",
IsRecurring: false, IsRecurring: false,
}, },
}, },
@ -350,7 +350,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
Created: time1, Created: time1,
Reminders: []time.Time{ Reminders: []time.Time{
time.Date(2020, time.June, 15, 0, 0, 0, 0, time.UTC).In(config.GetTimeZone()), time.Date(2020, time.June, 15, 0, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
time.Date(2020, time.June, 16, 0, 0, 0, 0, time.UTC).In(config.GetTimeZone()), time.Date(2020, time.June, 16, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
}, },
}, },
{ {
@ -364,7 +364,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
Done: false, Done: false,
Created: time1, Created: time1,
Reminders: []time.Time{ Reminders: []time.Time{
time.Date(2020, time.July, 15, 0, 0, 0, 0, time.UTC).In(config.GetTimeZone()), time.Date(2020, time.July, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
}, },
}, },
{ {
@ -376,7 +376,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
DoneAt: time3, DoneAt: time3,
Labels: vikunjaLabels, Labels: vikunjaLabels,
Reminders: []time.Time{ Reminders: []time.Time{
time.Date(2020, time.June, 15, 0, 0, 0, 0, time.UTC).In(config.GetTimeZone()), time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
}, },
}, },
{ {
@ -392,7 +392,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
Created: time1, Created: time1,
DoneAt: time3, DoneAt: time3,
Reminders: []time.Time{ Reminders: []time.Time{
time.Date(2020, time.June, 15, 0, 0, 0, 0, time.UTC).In(config.GetTimeZone()), time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
}, },
}, },
{ {
@ -470,7 +470,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
Done: false, Done: false,
Created: time1, Created: time1,
Reminders: []time.Time{ Reminders: []time.Time{
time.Date(2020, time.June, 15, 0, 0, 0, 0, time.UTC).In(config.GetTimeZone()), time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
}, },
}, },
{ {