API: New /users/:id/events endpoint

Signed-off-by: Rémy Coutable <remy@rymai.me>
This commit is contained in:
Rémy Coutable 2016-10-10 13:35:26 +02:00
parent 2e55580b90
commit 33ce197645
No known key found for this signature in database
GPG Key ID: 46DF07E5CD9E96AB
4 changed files with 222 additions and 0 deletions

View File

@ -59,6 +59,7 @@ v 8.13.0 (unreleased)
- Stop using a Redis lease when updating the project activity timestamp whenever a new event is created
- 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

View File

@ -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 latest.
```
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"
}
]
```

View File

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

View File

@ -895,4 +895,59 @@ describe API::API, api: true do
expect{put api("/users/ASDF/block", admin) }.to raise_error(ActionController::RoutingError)
end
end
describe 'GET /user/:id/events' do
let(:user) { create(:user) }
let(:lambda_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
get api("/users/#{user.id}/events", lambda_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)
first_event = json_response.first
expect(first_event['action_name']).to eq('commented on')
expect(first_event['project_id'].to_i).to eq(project.id)
expect(first_event['author_username']).to eq(user.username)
expect(first_event['note']['id']).to eq(note.id)
expect(first_event['note']['body']).to eq('What an awesome day!')
last_event = json_response.last
expect(last_event['action_name']).to eq('joined')
expect(last_event['project_id'].to_i).to eq(project.id)
expect(last_event['author_username']).to eq(user.username)
expect(last_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