diff --git a/Featurecreep.md b/Featurecreep.md index 4c0ed062896..7f379986060 100644 --- a/Featurecreep.md +++ b/Featurecreep.md @@ -65,7 +65,7 @@ Sorry for some of them being in German, I'll tranlate them at some point. -> Bleibt noch Profile abrufen und Einstellungen -> Macht also keinen Sinn das auf den neuen Handler umzuziehen * [x] Email-Verifizierung beim Registrieren * [x] Password Reset -* [ ] New field in user model which holds a url of an avatar image - for now just Gravatar, later more +* [x] New field in user model which holds a url of an avatar image - for now just Gravatar, later more * [ ] Settings * [ ] Password update * [ ] Email update diff --git a/pkg/integrations/task_test.go b/pkg/integrations/task_test.go index d9da983dce8..9bf6a811184 100644 --- a/pkg/integrations/task_test.go +++ b/pkg/integrations/task_test.go @@ -80,33 +80,33 @@ func TestListTask(t *testing.T) { t.Run("by priority", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"priority"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1`) + assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1`) }) t.Run("by priority desc", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"prioritydesc"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1`) + assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1`) }) t.Run("by priority asc", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"priorityasc"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `{"id":31,"text":"task #31 with color","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"f0f0f0","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}}]`) + assert.Contains(t, rec.Body.String(), `{"id":31,"text":"task #31 with color","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"f0f0f0","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`) }) // should equal duedate desc t.Run("by duedate", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"dueadate"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`) + assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`) }) t.Run("by duedate desc", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"dueadatedesc"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`) + assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`) }) t.Run("by duedate asc", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"duedateasc"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"doneAt":0,"dueDate":1543616724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}}]`) + assert.Contains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"doneAt":0,"dueDate":1543616724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`) }) t.Run("invalid parameter", func(t *testing.T) { // Invalid parameter should not sort at all diff --git a/pkg/models/label_task_test.go b/pkg/models/label_task_test.go index f986ce439c8..38375e366fa 100644 --- a/pkg/models/label_task_test.go +++ b/pkg/models/label_task_test.go @@ -47,9 +47,10 @@ func TestLabelTask_ReadAll(t *testing.T) { Title: "Label #4 - visible via other task", CreatedByID: 2, CreatedBy: &User{ - ID: 2, - Username: "user2", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + ID: 2, + Username: "user2", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", // hash for "" }, }, }, diff --git a/pkg/models/label_test.go b/pkg/models/label_test.go index 41b72c88394..9fd2810c3bc 100644 --- a/pkg/models/label_test.go +++ b/pkg/models/label_test.go @@ -44,10 +44,11 @@ func TestLabel_ReadAll(t *testing.T) { page int } user1 := &User{ - ID: 1, - Username: "user1", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", - IsActive: true, + ID: 1, + Username: "user1", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", } tests := []struct { name string @@ -85,9 +86,10 @@ func TestLabel_ReadAll(t *testing.T) { Title: "Label #4 - visible via other task", CreatedByID: 2, CreatedBy: &User{ - ID: 2, - Username: "user2", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + ID: 2, + Username: "user2", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", }, }, }, @@ -138,10 +140,11 @@ func TestLabel_ReadOne(t *testing.T) { Rights web.Rights } user1 := &User{ - ID: 1, - Username: "user1", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", - IsActive: true, + ID: 1, + Username: "user1", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", } tests := []struct { name string @@ -193,9 +196,10 @@ func TestLabel_ReadOne(t *testing.T) { Title: "Label #4 - visible via other task", CreatedByID: 2, CreatedBy: &User{ - ID: 2, - Username: "user2", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + ID: 2, + Username: "user2", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", }, }, auth: &User{ID: 1}, diff --git a/pkg/models/list_task_readall_test.go b/pkg/models/list_task_readall_test.go index 80901acf413..9c87104ca0a 100644 --- a/pkg/models/list_task_readall_test.go +++ b/pkg/models/list_task_readall_test.go @@ -17,21 +17,24 @@ import ( func sortTasksForTesting(by SortBy) (tasks []*ListTask) { user1 := User{ - ID: 1, - Username: "user1", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", - IsActive: true, + ID: 1, + Username: "user1", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for "" } user2 := User{ - ID: 2, - Username: "user2", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + ID: 2, + Username: "user2", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", // hash for "" } user6 := User{ - ID: 6, - Username: "user6", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", - IsActive: true, + ID: 6, + Username: "user6", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + AvatarURL: "3efbe51f864c6666bc27caf4c6ff90ed", // hash for "" } tasks = []*ListTask{ @@ -343,10 +346,11 @@ func TestListTask_ReadAll(t *testing.T) { // Dummy users user1 := User{ - ID: 1, - Username: "user1", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", - IsActive: true, + ID: 1, + Username: "user1", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for "" } type fields struct { diff --git a/pkg/models/list_users_test.go b/pkg/models/list_users_test.go index 9d38a9e41ed..2b94e7ef9ed 100644 --- a/pkg/models/list_users_test.go +++ b/pkg/models/list_users_test.go @@ -160,18 +160,20 @@ func TestListUser_ReadAll(t *testing.T) { want: []*UserWithRight{ { User: User{ - ID: 1, - Username: "user1", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", - IsActive: true, + ID: 1, + Username: "user1", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", }, Right: RightRead, }, { User: User{ - ID: 2, - Username: "user2", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + ID: 2, + Username: "user2", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", }, Right: RightRead, }, diff --git a/pkg/models/namespace_users_test.go b/pkg/models/namespace_users_test.go index fefdf12f95b..80d5ef9d65c 100644 --- a/pkg/models/namespace_users_test.go +++ b/pkg/models/namespace_users_test.go @@ -159,18 +159,20 @@ func TestNamespaceUser_ReadAll(t *testing.T) { want: []*UserWithRight{ { User: User{ - ID: 1, - Username: "user1", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", - IsActive: true, + ID: 1, + Username: "user1", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", }, Right: RightRead, }, { User: User{ - ID: 2, - Username: "user2", - Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + ID: 2, + Username: "user2", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", }, Right: RightRead, }, diff --git a/pkg/models/user.go b/pkg/models/user.go index 55f570245c3..15999236107 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -19,6 +19,7 @@ package models import ( "code.vikunja.io/api/pkg/log" "code.vikunja.io/api/pkg/metrics" + "code.vikunja.io/api/pkg/utils" "code.vikunja.io/web" "fmt" "github.com/dgrijalva/jwt-go" @@ -46,6 +47,8 @@ type User struct { // The user's email address. Email string `xorm:"varchar(250) null" json:"email,omitempty" valid:"email,length(0|250)" maxLength:"250"` IsActive bool `xorm:"null" json:"-"` + // The users md5-hashed email address, used to get the avatar from gravatar and the likes. + AvatarURL string `xorm:"-" json:"avatarUrl"` PasswordResetToken string `xorm:"varchar(450) null" json:"-"` EmailConfirmToken string `xorm:"varchar(450) null" json:"-"` @@ -60,6 +63,7 @@ type User struct { // AfterLoad is used to delete all emails to not have them leaked to the user func (u *User) AfterLoad() { + u.AvatarURL = utils.Md5String(u.Email) u.Email = "" } diff --git a/pkg/swagger/docs.go b/pkg/swagger/docs.go index 67304548503..dc0e412774d 100644 --- a/pkg/swagger/docs.go +++ b/pkg/swagger/docs.go @@ -1,6 +1,6 @@ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag at -// 2019-05-25 11:35:41.214134069 +0200 CEST m=+0.124896065 +// 2019-05-30 23:45:13.052367163 +0200 CEST m=+0.289150504 package swagger @@ -14,7 +14,7 @@ import ( var doc = `{ "swagger": "2.0", "info": { - "description": "This is the documentation for the [Vikunja](http://vikunja.io) API. Vikunja is a cross-plattform Todo-application with a lot of features, such as sharing lists with users or teams. \u003c!-- ReDoc-Inject: \u003csecurity-definitions\u003e --\u003e\n# Authorization\n**JWT-Auth:** Main authorization method, used for most of the requests. Needs ` + "`" + `Authorization: Bearer \u003cjwt-token\u003e` + "`" + `-header to authenticate successfully.\n\n**BasicAuth:** Only used when requesting tasks via caldav.\n\u003c!-- ReDoc-Inject: \u003csecurity-definitions\u003e --\u003e", + "description": "\u003c!-- ReDoc-Inject: \u003csecurity-definitions\u003e --\u003e", "title": "Vikunja API", "contact": { "name": "General Vikunja contact", @@ -391,7 +391,7 @@ var doc = `{ "JWTKeyAuth": [] } ], - "description": "Returns a list by its ID.", + "description": "Returns a team by its ID.", "consumes": [ "application/json" ], @@ -399,13 +399,13 @@ var doc = `{ "application/json" ], "tags": [ - "list" + "team" ], - "summary": "Gets one list", + "summary": "Gets one team", "parameters": [ { "type": "integer", - "description": "List ID", + "description": "Team ID", "name": "id", "in": "path", "required": true @@ -413,14 +413,14 @@ var doc = `{ ], "responses": { "200": { - "description": "The list", + "description": "The team", "schema": { "type": "object", - "$ref": "#/definitions/models.List" + "$ref": "#/definitions/models.Team" } }, "403": { - "description": "The user does not have access to the list", + "description": "The user does not have access to the team", "schema": { "type": "object", "$ref": "#/definitions/code.vikunja.io.web.HTTPError" @@ -4243,6 +4243,10 @@ var doc = `{ "description": "Whether or not the member is an admin of the team. See the docs for more about what a team admin can do", "type": "boolean" }, + "avatarUrl": { + "description": "The users md5-hashed email address, used to get the avatar from gravatar and the likes.", + "type": "string" + }, "created": { "description": "A unix timestamp when this task was created. You cannot change this value.", "type": "integer" @@ -4315,6 +4319,10 @@ var doc = `{ "models.User": { "type": "object", "properties": { + "avatarUrl": { + "description": "The users md5-hashed email address, used to get the avatar from gravatar and the likes.", + "type": "string" + }, "created": { "description": "A unix timestamp when this task was created. You cannot change this value.", "type": "integer" @@ -4356,6 +4364,10 @@ var doc = `{ "models.UserWithRight": { "type": "object", "properties": { + "avatarUrl": { + "description": "The users md5-hashed email address, used to get the avatar from gravatar and the likes.", + "type": "string" + }, "created": { "description": "A unix timestamp when this task was created. You cannot change this value.", "type": "integer" diff --git a/pkg/swagger/swagger.json b/pkg/swagger/swagger.json index 7a700ec98a8..35e4bb78778 100644 --- a/pkg/swagger/swagger.json +++ b/pkg/swagger/swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "description": "This is the documentation for the [Vikunja](http://vikunja.io) API. Vikunja is a cross-plattform Todo-application with a lot of features, such as sharing lists with users or teams. \u003c!-- ReDoc-Inject: \u003csecurity-definitions\u003e --\u003e\n# Authorization\n**JWT-Auth:** Main authorization method, used for most of the requests. Needs ` + \"`\" + `Authorization: Bearer \u003cjwt-token\u003e` + \"`\" + `-header to authenticate successfully.\n\n**BasicAuth:** Only used when requesting tasks via caldav.\n\u003c!-- ReDoc-Inject: \u003csecurity-definitions\u003e --\u003e", + "description": "\u003c!-- ReDoc-Inject: \u003csecurity-definitions\u003e --\u003e", "title": "Vikunja API", "contact": { "name": "General Vikunja contact", @@ -378,7 +378,7 @@ "JWTKeyAuth": [] } ], - "description": "Returns a list by its ID.", + "description": "Returns a team by its ID.", "consumes": [ "application/json" ], @@ -386,13 +386,13 @@ "application/json" ], "tags": [ - "list" + "team" ], - "summary": "Gets one list", + "summary": "Gets one team", "parameters": [ { "type": "integer", - "description": "List ID", + "description": "Team ID", "name": "id", "in": "path", "required": true @@ -400,14 +400,14 @@ ], "responses": { "200": { - "description": "The list", + "description": "The team", "schema": { "type": "object", - "$ref": "#/definitions/models.List" + "$ref": "#/definitions/models.Team" } }, "403": { - "description": "The user does not have access to the list", + "description": "The user does not have access to the team", "schema": { "type": "object", "$ref": "#/definitions/code.vikunja.io/web.HTTPError" @@ -4229,6 +4229,10 @@ "description": "Whether or not the member is an admin of the team. See the docs for more about what a team admin can do", "type": "boolean" }, + "avatarUrl": { + "description": "The users md5-hashed email address, used to get the avatar from gravatar and the likes.", + "type": "string" + }, "created": { "description": "A unix timestamp when this task was created. You cannot change this value.", "type": "integer" @@ -4301,6 +4305,10 @@ "models.User": { "type": "object", "properties": { + "avatarUrl": { + "description": "The users md5-hashed email address, used to get the avatar from gravatar and the likes.", + "type": "string" + }, "created": { "description": "A unix timestamp when this task was created. You cannot change this value.", "type": "integer" @@ -4342,6 +4350,10 @@ "models.UserWithRight": { "type": "object", "properties": { + "avatarUrl": { + "description": "The users md5-hashed email address, used to get the avatar from gravatar and the likes.", + "type": "string" + }, "created": { "description": "A unix timestamp when this task was created. You cannot change this value.", "type": "integer" diff --git a/pkg/swagger/swagger.yaml b/pkg/swagger/swagger.yaml index bd464c261c2..19e45f932bb 100644 --- a/pkg/swagger/swagger.yaml +++ b/pkg/swagger/swagger.yaml @@ -521,6 +521,10 @@ definitions: description: Whether or not the member is an admin of the team. See the docs for more about what a team admin can do type: boolean + avatarUrl: + description: The users md5-hashed email address, used to get the avatar from + gravatar and the likes. + type: string created: description: A unix timestamp when this task was created. You cannot change this value. @@ -579,6 +583,10 @@ definitions: type: object models.User: properties: + avatarUrl: + description: The users md5-hashed email address, used to get the avatar from + gravatar and the likes. + type: string created: description: A unix timestamp when this task was created. You cannot change this value. @@ -611,6 +619,10 @@ definitions: type: object models.UserWithRight: properties: + avatarUrl: + description: The users md5-hashed email address, used to get the avatar from + gravatar and the likes. + type: string created: description: A unix timestamp when this task was created. You cannot change this value. @@ -652,13 +664,7 @@ info: email: hello@vikunja.io name: General Vikunja contact url: http://vikunja.io/en/contact/ - description: |- - This is the documentation for the [Vikunja](http://vikunja.io) API. Vikunja is a cross-plattform Todo-application with a lot of features, such as sharing lists with users or teams. - # Authorization - **JWT-Auth:** Main authorization method, used for most of the requests. Needs ` + "`" + `Authorization: Bearer ` + "`" + `-header to authenticate successfully. - - **BasicAuth:** Only used when requesting tasks via caldav. - + description: '' license: name: GPLv3 url: http://code.vikunja.io/api/src/branch/master/LICENSE @@ -942,9 +948,9 @@ paths: get: consumes: - application/json - description: Returns a list by its ID. + description: Returns a team by its ID. parameters: - - description: List ID + - description: Team ID in: path name: id required: true @@ -953,12 +959,12 @@ paths: - application/json responses: "200": - description: The list + description: The team schema: - $ref: '#/definitions/models.List' + $ref: '#/definitions/models.Team' type: object "403": - description: The user does not have access to the list + description: The user does not have access to the team schema: $ref: '#/definitions/code.vikunja.io/web.HTTPError' type: object @@ -969,9 +975,9 @@ paths: type: object security: - JWTKeyAuth: [] - summary: Gets one list + summary: Gets one team tags: - - list + - team post: consumes: - application/json diff --git a/pkg/utils/md5_string.go b/pkg/utils/md5_string.go new file mode 100644 index 00000000000..d731b7047ca --- /dev/null +++ b/pkg/utils/md5_string.go @@ -0,0 +1,30 @@ +// Vikunja is a todo-list application to facilitate your life. +// Copyright 2019 Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package utils + +import ( + "crypto/md5" + "fmt" + "io" +) + +// Md5String generates an md5 hash from a string +func Md5String(in string) string { + h := md5.New() + io.WriteString(h, in) + return fmt.Sprintf("%x", h.Sum(nil)) +}