diff options
author | Robert Speicher <robert@gitlab.com> | 2016-10-12 11:33:19 +0000 |
---|---|---|
committer | Robert Speicher <robert@gitlab.com> | 2016-10-12 11:33:19 +0000 |
commit | 7c07c07d7a2b93ab81964b9cd28736652da1370a (patch) | |
tree | 41734446a104fa184195e7b71601a762a22adbb9 | |
parent | c004bb3e74b6a60a4b6ede93d0ea8a898e56c41b (diff) | |
parent | c7865786572a3a2e12ed67a3f8121c0be8c4ba38 (diff) | |
download | gitlab-ce-7c07c07d7a2b93ab81964b9cd28736652da1370a.tar.gz |
Merge branch 'user-events-api' into 'master'
API: New /users/:id/events endpoint
## What does this MR do?
If add a new `/users/:id/events` endpoint to retrieve a user's contribution events. The events returned are filtered so that only the events for projects that the current user can see are returned (similarly to what we do at the controller level).
## Why was this MR needed?
Because it's a nice feature to calculate leaderboards, for instance for #17815.
## What are the relevant issue numbers?
Closes #20866.
See merge request !6771
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | doc/api/projects.md | 2 | ||||
-rw-r--r-- | doc/api/users.md | 146 | ||||
-rw-r--r-- | lib/api/users.rb | 20 | ||||
-rw-r--r-- | spec/requests/api/users_spec.rb | 54 |
5 files changed, 222 insertions, 1 deletions
diff --git a/CHANGELOG b/CHANGELOG index 2d16f7fd3ab..e478e8c3365 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -73,6 +73,7 @@ v 8.13.0 (unreleased) - Add disabled delete button to protected branches (ClemMakesApps) - Add broadcast messages and alerts below sub-nav - Better empty state for Groups view + - API: New /users/:id/events endpoint - Update ruby-prof to 0.16.2. !6026 (Elan Ruusamäe) - Replace bootstrap caret with fontawesome caret (ClemMakesApps) - Fix unnecessary escaping of reserved HTML characters in milestone title. !6533 diff --git a/doc/api/projects.md b/doc/api/projects.md index 27436a052da..f96bf7f6d63 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -436,7 +436,7 @@ Parameters: ### Get project events Get the events for the specified project. -Sorted from newest to latest +Sorted from newest to oldest ``` GET /projects/:id/events diff --git a/doc/api/users.md b/doc/api/users.md index 9be4f2e6ec3..a52b2d51d78 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -627,3 +627,149 @@ Parameters: Will return `200 OK` on success, `404 User Not Found` is user cannot be found or `403 Forbidden` when trying to unblock a user blocked by LDAP synchronization. + +### Get user contribution events + +Get the contribution events for the specified user, sorted from newest to oldest. + +``` +GET /users/:id/events +``` + +Parameters: + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer | yes | The ID of the user | + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/user/:id/events +``` + +Example response: + +```json +[ + { + "title": null, + "project_id": 15, + "action_name": "closed", + "target_id": 830, + "target_type": "Issue", + "author_id": 1, + "data": null, + "target_title": "Public project search field", + "author": { + "name": "Dmitriy Zaporozhets", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png", + "web_url": "http://localhost:3000/u/root" + }, + "author_username": "root" + }, + { + "title": null, + "project_id": 15, + "action_name": "opened", + "target_id": null, + "target_type": null, + "author_id": 1, + "author": { + "name": "Dmitriy Zaporozhets", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png", + "web_url": "http://localhost:3000/u/root" + }, + "author_username": "john", + "data": { + "before": "50d4420237a9de7be1304607147aec22e4a14af7", + "after": "c5feabde2d8cd023215af4d2ceeb7a64839fc428", + "ref": "refs/heads/master", + "user_id": 1, + "user_name": "Dmitriy Zaporozhets", + "repository": { + "name": "gitlabhq", + "url": "git@dev.gitlab.org:gitlab/gitlabhq.git", + "description": "GitLab: self hosted Git management software. \r\nDistributed under the MIT License.", + "homepage": "https://dev.gitlab.org/gitlab/gitlabhq" + }, + "commits": [ + { + "id": "c5feabde2d8cd023215af4d2ceeb7a64839fc428", + "message": "Add simple search to projects in public area", + "timestamp": "2013-05-13T18:18:08+00:00", + "url": "https://dev.gitlab.org/gitlab/gitlabhq/commit/c5feabde2d8cd023215af4d2ceeb7a64839fc428", + "author": { + "name": "Dmitriy Zaporozhets", + "email": "dmitriy.zaporozhets@gmail.com" + } + } + ], + "total_commits_count": 1 + }, + "target_title": null + }, + { + "title": null, + "project_id": 15, + "action_name": "closed", + "target_id": 840, + "target_type": "Issue", + "author_id": 1, + "data": null, + "target_title": "Finish & merge Code search PR", + "author": { + "name": "Dmitriy Zaporozhets", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png", + "web_url": "http://localhost:3000/u/root" + }, + "author_username": "root" + }, + { + "title": null, + "project_id": 15, + "action_name": "commented on", + "target_id": 1312, + "target_type": "Note", + "author_id": 1, + "data": null, + "target_title": null, + "created_at": "2015-12-04T10:33:58.089Z", + "note": { + "id": 1312, + "body": "What an awesome day!", + "attachment": null, + "author": { + "name": "Dmitriy Zaporozhets", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png", + "web_url": "http://localhost:3000/u/root" + }, + "created_at": "2015-12-04T10:33:56.698Z", + "system": false, + "upvote": false, + "downvote": false, + "noteable_id": 377, + "noteable_type": "Issue" + }, + "author": { + "name": "Dmitriy Zaporozhets", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://localhost:3000/uploads/user/avatar/1/fox_avatar.png", + "web_url": "http://localhost:3000/u/root" + }, + "author_username": "root" + } +] +``` diff --git a/lib/api/users.rb b/lib/api/users.rb index 18c4cad09ae..e868f628404 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -321,6 +321,26 @@ module API user.activate end end + + desc 'Get contribution events of a specified user' do + detail 'This feature was introduced in GitLab 8.13.' + success Entities::Event + end + params do + requires :id, type: String, desc: 'The user ID' + end + get ':id/events' do + user = User.find_by(id: declared(params).id) + not_found!('User') unless user + + events = user.recent_events. + merge(ProjectsFinder.new.execute(current_user)). + references(:project). + with_associations. + page(params[:page]) + + present paginate(events), with: Entities::Event + end end resource :user do diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index b002949b41b..f83f4d2c9b1 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -913,4 +913,58 @@ describe API::API, api: true do expect(response).to have_http_status(404) end end + + describe 'GET /user/:id/events' do + let(:user) { create(:user) } + let(:project) { create(:empty_project) } + let(:note) { create(:note_on_issue, note: 'What an awesome day!', project: project) } + + before do + project.add_user(user, :developer) + EventCreateService.new.leave_note(note, user) + end + + context "as a user than cannot see the event's project" do + it 'returns no events' do + other_user = create(:user) + + get api("/users/#{user.id}/events", other_user) + + expect(response).to have_http_status(200) + expect(json_response).to be_empty + end + end + + context "as a user than can see the event's project" do + it_behaves_like 'a paginated resources' do + let(:request) { get api("/users/#{user.id}/events", user) } + end + + context 'joined event' do + it 'returns the "joined" event' do + get api("/users/#{user.id}/events", user) + + comment_event = json_response.find { |e| e['action_name'] == 'commented on' } + + expect(comment_event['project_id'].to_i).to eq(project.id) + expect(comment_event['author_username']).to eq(user.username) + expect(comment_event['note']['id']).to eq(note.id) + expect(comment_event['note']['body']).to eq('What an awesome day!') + + joined_event = json_response.find { |e| e['action_name'] == 'joined' } + + expect(joined_event['project_id'].to_i).to eq(project.id) + expect(joined_event['author_username']).to eq(user.username) + expect(joined_event['author']['name']).to eq(user.name) + end + end + end + + it 'returns a 404 error if not found' do + get api('/users/42/events', user) + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 User Not Found') + end + end end |