summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--app/assets/javascripts/gl_dropdown.js3
-rw-r--r--app/assets/stylesheets/pages/todos.scss44
-rw-r--r--app/helpers/namespaces_helper.rb4
-rw-r--r--app/views/dashboard/todos/_todo.html.haml17
-rw-r--r--app/views/projects/new.html.haml2
-rw-r--r--app/views/search/results/_snippet_blob.html.haml55
-rw-r--r--app/views/shared/members/_member.html.haml2
-rw-r--r--changelogs/unreleased/28186-long-group-names-overflow-out-of-todos-view.yml4
-rw-r--r--changelogs/unreleased/api-todos-restful.yml4
-rw-r--r--changelogs/unreleased/group-memebrs-owner-level.yml4
-rw-r--r--changelogs/unreleased/snippets-search.yml4
-rw-r--r--doc/api/todos.md15
-rw-r--r--doc/api/v3_to_v4.md2
-rw-r--r--doc/ci/docker/using_docker_images.md15
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/todos.rb6
-rw-r--r--lib/api/v3/todos.rb28
-rw-r--r--lib/gitlab/database/migration_helpers.rb11
-rw-r--r--spec/features/groups/members/list_spec.rb15
-rw-r--r--spec/features/projects/new_project_spec.rb45
-rw-r--r--spec/features/projects/ref_switcher_spec.rb2
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb10
-rw-r--r--spec/requests/api/todos_spec.rb27
-rw-r--r--spec/requests/api/v3/todos_spec.rb73
25 files changed, 314 insertions, 81 deletions
diff --git a/README.md b/README.md
index 4f85fac4a56..09e08adbb73 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ We're hiring developers, support people, and production engineers all the time,
There are two editions of GitLab:
- GitLab Community Edition (CE) is available freely under the MIT Expat license.
-- GitLab Enterprise Edition (EE) includes [extra features](https://about.gitlab.com/features/#compare) that are more useful for organizations with more than 100 users. To use EE and get official support please [become a subscriber](https://about.gitlab.com/pricing/).
+- GitLab Enterprise Edition (EE) includes [extra features](https://about.gitlab.com/products/#compare-options) that are more useful for organizations with more than 100 users. To use EE and get official support please [become a subscriber](https://about.gitlab.com/products/).
## Website
diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js
index bf3da8528f0..a01662e2f9e 100644
--- a/app/assets/javascripts/gl_dropdown.js
+++ b/app/assets/javascripts/gl_dropdown.js
@@ -47,9 +47,10 @@
}
// Only filter asynchronously only if option remote is set
if (this.options.remote) {
- $inputContainer.parent().addClass('is-loading');
clearTimeout(timeout);
return timeout = setTimeout(function() {
+ $inputContainer.parent().addClass('is-loading');
+
return this.options.query(this.input.val(), function(data) {
$inputContainer.parent().removeClass('is-loading');
return this.options.callback(data);
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index 551a66fbf3a..bac831ec315 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -43,6 +43,12 @@
}
}
+ .todo-avatar,
+ .todo-actions {
+ -webkit-flex: 0 0 auto;
+ flex: 0 0 auto;
+ }
+
.todo-actions {
display: -webkit-flex;
display: flex;
@@ -55,8 +61,9 @@
}
.todo-item {
- -webkit-flex: auto;
- flex: auto;
+ -webkit-flex: 0 1 100%;
+ flex: 0 1 100%;
+ min-width: 0;
}
}
@@ -74,8 +81,29 @@
.todo-item {
.todo-title {
- @include str-truncated(calc(100% - 174px));
- overflow: visible;
+ display: flex;
+
+ & > .title-item {
+ -webkit-flex: 0 0 auto;
+ flex: 0 0 auto;
+ margin: 0 2px;
+
+ &:first-child {
+ margin-left: 0;
+ }
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+
+ .todo-label {
+ -webkit-flex: 0 1 auto;
+ flex: 0 1 auto;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
}
.status-box {
@@ -154,10 +182,12 @@
.todo-item {
.todo-title {
- white-space: normal;
- overflow: visible;
- max-width: 100%;
+ flex-flow: row wrap;
margin-bottom: 10px;
+
+ .todo-label {
+ white-space: normal;
+ }
}
.todo-body {
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
index 0676767d910..dc5ae8edbb2 100644
--- a/app/helpers/namespaces_helper.rb
+++ b/app/helpers/namespaces_helper.rb
@@ -1,4 +1,8 @@
module NamespacesHelper
+ def namespace_id_from(params)
+ params.dig(:project, :namespace_id) || params[:namespace_id]
+ end
+
def namespaces_options(selected = :current_user, display_path: false, extra_group: nil)
groups = current_user.owned_groups + current_user.masters_groups
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index dc2d924f212..a3993d5ef16 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -1,28 +1,33 @@
%li{ class: "todo todo-#{todo.done? ? 'done' : 'pending'}", id: dom_id(todo), data: { url: todo_target_path(todo) } }
- = author_avatar(todo, size: 40)
+ .todo-avatar
+ = author_avatar(todo, size: 40)
.todo-item.todo-block
.todo-title.title
- unless todo.build_failed? || todo.unmergeable?
= todo_target_state_pill(todo)
- %span.author-name
+ .title-item.author-name
- if todo.author
= link_to_author(todo)
- else
(removed)
- %span.action-name
+ .title-item.action-name
= todo_action_name(todo)
- %span.todo-label
+ .title-item.todo-label
- if todo.target
= todo_target_link(todo)
- else
(removed)
- · #{time_ago_with_tooltip(todo.created_at)}
- = todo_due_date(todo)
+ .title-item
+ ·
+
+ .title-item
+ #{time_ago_with_tooltip(todo.created_at)}
+ = todo_due_date(todo)
.todo-body
.todo-note
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index a07885537b9..2a98bba05ee 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -22,7 +22,7 @@
- if current_user.can_select_namespace?
.input-group-addon
= root_url
- = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user, display_path: true), {}, {class: 'select2 js-select-namespace', tabindex: 1}
+ = f.select :namespace_id, namespaces_options(namespace_id_from(params) || :current_user, display_path: true), {}, {class: 'select2 js-select-namespace', tabindex: 1}
- else
.input-group-addon.static-namespace
diff --git a/app/views/search/results/_snippet_blob.html.haml b/app/views/search/results/_snippet_blob.html.haml
index e977c1f1698..f84be600df8 100644
--- a/app/views/search/results/_snippet_blob.html.haml
+++ b/app/views/search/results/_snippet_blob.html.haml
@@ -12,41 +12,34 @@
%span.light= time_ago_with_tooltip(snippet.created_at)
%h4.snippet-title
- snippet_path = reliable_snippet_path(snippet)
- = link_to snippet_path do
- .file-holder
- .js-file-title.file-title
+ .file-holder
+ .js-file-title.file-title
+ = link_to snippet_path do
%i.fa.fa-file
%strong= snippet.file_name
- - if markup?(snippet.file_name)
- .file-content.wiki
+ - if markup?(snippet.file_name)
+ .file-content.wiki
+ - snippet_chunks.each do |chunk|
+ - unless chunk[:data].empty?
+ = render_markup(snippet.file_name, chunk[:data])
+ - else
+ .file-content.code
+ .nothing-here-block Empty file
+ - else
+ .file-content.code.js-syntax-highlight
+ .line-numbers
- snippet_chunks.each do |chunk|
- unless chunk[:data].empty?
- = render_markup(snippet.file_name, chunk[:data])
+ - Gitlab::Git::Util.count_lines(chunk[:data]).times do |index|
+ - offset = defined?(chunk[:start_line]) ? chunk[:start_line] : 1
+ - i = index + offset
+ = link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}", class: "diff-line-num" do
+ %i.fa.fa-link
+ = i
+ .blob-content
+ - snippet_chunks.each do |chunk|
+ - unless chunk[:data].empty?
+ = highlight(snippet.file_name, chunk[:data], repository: nil, plain: snippet.no_highlighting?)
- else
.file-content.code
.nothing-here-block Empty file
- - else
- .file-content.code.js-syntax-highlight
- .line-numbers
- - snippet_chunks.each do |chunk|
- - unless chunk[:data].empty?
- - Gitlab::Git::Util.count_lines(chunk[:data]).times do |index|
- - offset = defined?(chunk[:start_line]) ? chunk[:start_line] : 1
- - i = index + offset
- = link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}", class: "diff-line-num" do
- %i.fa.fa-link
- = i
- - unless snippet == snippet_chunks.last
- %a.diff-line-num
- = "."
- %pre.code
- %code
- - snippet_chunks.each do |chunk|
- - unless chunk[:data].empty?
- = chunk[:data]
- - unless chunk == snippet_chunks.last
- %a
- = "..."
- - else
- .file-content.code
- .nothing-here-block Empty file
diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml
index 239387fc9fa..8e721c9c8dd 100644
--- a/app/views/shared/members/_member.html.haml
+++ b/app/views/shared/members/_member.html.haml
@@ -61,7 +61,7 @@
= dropdown_title("Change permissions")
.dropdown-content
%ul
- - Gitlab::Access.options.each do |role, role_id|
+ - member.class.access_level_roles.each do |role, role_id|
%li
= link_to role, "javascript:void(0)",
class: ("is-active" if member.access_level == role_id),
diff --git a/changelogs/unreleased/28186-long-group-names-overflow-out-of-todos-view.yml b/changelogs/unreleased/28186-long-group-names-overflow-out-of-todos-view.yml
new file mode 100644
index 00000000000..3bcf0e06d08
--- /dev/null
+++ b/changelogs/unreleased/28186-long-group-names-overflow-out-of-todos-view.yml
@@ -0,0 +1,4 @@
+---
+title: Truncate long Todo titles for non-mobile screens
+merge_request: 9311
+author:
diff --git a/changelogs/unreleased/api-todos-restful.yml b/changelogs/unreleased/api-todos-restful.yml
new file mode 100644
index 00000000000..dba1350a495
--- /dev/null
+++ b/changelogs/unreleased/api-todos-restful.yml
@@ -0,0 +1,4 @@
+---
+title: 'API: Use POST requests to mark todos as done'
+merge_request: 9410
+author: Robert Schilling
diff --git a/changelogs/unreleased/group-memebrs-owner-level.yml b/changelogs/unreleased/group-memebrs-owner-level.yml
new file mode 100644
index 00000000000..ba77f38eb6d
--- /dev/null
+++ b/changelogs/unreleased/group-memebrs-owner-level.yml
@@ -0,0 +1,4 @@
+---
+title: Added option to update to owner for group members
+merge_request:
+author:
diff --git a/changelogs/unreleased/snippets-search.yml b/changelogs/unreleased/snippets-search.yml
new file mode 100644
index 00000000000..00cf34f4a48
--- /dev/null
+++ b/changelogs/unreleased/snippets-search.yml
@@ -0,0 +1,4 @@
+---
+title: Fix snippets search result spacing
+merge_request:
+author:
diff --git a/doc/api/todos.md b/doc/api/todos.md
index a5e81801024..a2fbbc7e1f8 100644
--- a/doc/api/todos.md
+++ b/doc/api/todos.md
@@ -184,7 +184,7 @@ Marks a single pending todo given by its ID for the current user as done. The
todo marked as done is returned in the response.
```
-DELETE /todos/:id
+POST /todos/:id/mark_as_done
```
Parameters:
@@ -194,7 +194,7 @@ Parameters:
| `id` | integer | yes | The ID of a todo |
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/todos/130
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/todos/130/mark_as_done
```
Example Response:
@@ -277,20 +277,15 @@ Example Response:
## Mark all todos as done
-Marks all pending todos for the current user as done. It returns the number of marked todos.
+Marks all pending todos for the current user as done. It returns the HTTP status code `204` with an empty response.
```
-DELETE /todos
+POST /todos/mark_as_done
```
```bash
-curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/todos
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/todos/donmark_as_donee
```
-Example Response:
-
-```json
-3
-```
[ce-3188]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3188
diff --git a/doc/api/v3_to_v4.md b/doc/api/v3_to_v4.md
index 3f58c098b43..1af124c56b1 100644
--- a/doc/api/v3_to_v4.md
+++ b/doc/api/v3_to_v4.md
@@ -24,9 +24,9 @@ changes are in V4:
- `/gitlab_ci_ymls/:key`
- `/dockerfiles/:key`
- Moved `/projects/fork/:id` to `/projects/:id/fork`
+- Moved `DELETE /todos` to `POST /todos/mark_as_done` and `DELETE /todos/:todo_id` to `POST /todos/:todo_id/mark_as_done`
- Endpoints `/projects/owned`, `/projects/visible`, `/projects/starred` & `/projects/all` are consolidated into `/projects` using query parameters
- Return pagination headers for all endpoints that return an array
- Removed `DELETE projects/:id/deploy_keys/:key_id/disable`. Use `DELETE projects/:id/deploy_keys/:key_id` instead
- Moved `PUT /users/:id/(block|unblock)` to `POST /users/:id/(block|unblock)`
- Labels filter on `projects/:id/issues` and `/issues` now matches only issues containing all labels (i.e.: Logical AND, not OR)
-
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index 9dee61bfa1f..00787323b6b 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -39,13 +39,15 @@ accessible during the build process.
## What is an image
-The `image` keyword is the name of the docker image that is present in the
-local Docker Engine (list all images with `docker images`) or any image that
-can be found at [Docker Hub][hub]. For more information about images and Docker
-Hub please read the [Docker Fundamentals][] documentation.
+The `image` keyword is the name of the docker image the docker executor
+will run to perform the CI tasks.
-In short, with `image` we refer to the docker image, which will be used to
-create a container on which your job will run.
+By default the executor will only pull images from [Docker Hub][hub],
+but this can be configured in the `gitlab-runner/config.toml` by setting
+the [docker pull policy][] to allow using local images.
+
+For more information about images and Docker Hub please read
+the [Docker Fundamentals][] documentation.
## What is a service
@@ -271,6 +273,7 @@ containers as well as all volumes (`-v`) that were created with the container
creation.
[Docker Fundamentals]: https://docs.docker.com/engine/understanding-docker/
+[docker pull policy]: https://docs.gitlab.com/runner/executors/docker.html#how-pull-policies-work
[hub]: https://hub.docker.com/
[linking-containers]: https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/
[tutum/wordpress]: https://hub.docker.com/r/tutum/wordpress/
diff --git a/lib/api/api.rb b/lib/api/api.rb
index dbb7271ccbd..e729c07f8c3 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -19,6 +19,7 @@ module API
mount ::API::V3::Repositories
mount ::API::V3::SystemHooks
mount ::API::V3::Tags
+ mount ::API::V3::Todos
mount ::API::V3::Templates
mount ::API::V3::Users
end
diff --git a/lib/api/todos.rb b/lib/api/todos.rb
index 9bd077263a7..0b9650b296c 100644
--- a/lib/api/todos.rb
+++ b/lib/api/todos.rb
@@ -58,7 +58,7 @@ module API
params do
requires :id, type: Integer, desc: 'The ID of the todo being marked as done'
end
- delete ':id' do
+ post ':id/mark_as_done' do
todo = current_user.todos.find(params[:id])
TodoService.new.mark_todos_as_done([todo], current_user)
@@ -66,9 +66,11 @@ module API
end
desc 'Mark all todos as done'
- delete do
+ post '/mark_as_done' do
todos = find_todos
TodoService.new.mark_todos_as_done(todos, current_user)
+
+ no_content!
end
end
end
diff --git a/lib/api/v3/todos.rb b/lib/api/v3/todos.rb
new file mode 100644
index 00000000000..4f9b5fe72a6
--- /dev/null
+++ b/lib/api/v3/todos.rb
@@ -0,0 +1,28 @@
+module API
+ module V3
+ class Todos < Grape::API
+ before { authenticate! }
+
+ resource :todos do
+ desc 'Mark a todo as done' do
+ success ::API::Entities::Todo
+ end
+ params do
+ requires :id, type: Integer, desc: 'The ID of the todo being marked as done'
+ end
+ delete ':id' do
+ todo = current_user.todos.find(params[:id])
+ TodoService.new.mark_todos_as_done([todo], current_user)
+
+ present todo.reload, with: ::API::Entities::Todo, current_user: current_user
+ end
+
+ desc 'Mark all todos as done'
+ delete do
+ todos = TodosFinder.new(current_user, params).execute
+ TodoService.new.mark_todos_as_done(todos, current_user)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 4800a509b37..fc445ab9483 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -54,7 +54,7 @@ module Gitlab
disable_statement_timeout
- key_name = "fk_#{source}_#{target}_#{column}"
+ key_name = concurrent_foreign_key_name(source, column)
# Using NOT VALID allows us to create a key without immediately
# validating it. This means we keep the ALTER TABLE lock only for a
@@ -74,6 +74,15 @@ module Gitlab
execute("ALTER TABLE #{source} VALIDATE CONSTRAINT #{key_name};")
end
+ # Returns the name for a concurrent foreign key.
+ #
+ # PostgreSQL constraint names have a limit of 63 bytes. The logic used
+ # here is based on Rails' foreign_key_name() method, which unfortunately
+ # is private so we can't rely on it directly.
+ def concurrent_foreign_key_name(table, column)
+ "fk_#{Digest::SHA256.hexdigest("#{table}_#{column}_fk").first(10)}"
+ end
+
# Long-running migrations may take more than the timeout allowed by
# the database. Disable the session's statement timeout to ensure
# migrations don't get killed prematurely. (PostgreSQL only)
diff --git a/spec/features/groups/members/list_spec.rb b/spec/features/groups/members/list_spec.rb
index 109de39b2dd..14c193f7450 100644
--- a/spec/features/groups/members/list_spec.rb
+++ b/spec/features/groups/members/list_spec.rb
@@ -30,6 +30,21 @@ feature 'Groups members list', feature: true do
expect(second_row).to be_blank
end
+ it 'updates user to owner level', :js do
+ group.add_owner(user1)
+ group.add_developer(user2)
+
+ visit group_group_members_path(group)
+
+ page.within(second_row) do
+ click_button('Developer')
+
+ click_link('Owner')
+
+ expect(page).to have_button('Owner')
+ end
+ end
+
def first_row
page.all('ul.content-list > li')[0]
end
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index b56e562b2b6..45185f2dd1f 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -19,6 +19,51 @@ feature "New project", feature: true do
end
end
+ context "Namespace selector" do
+ context "with user namespace" do
+ before do
+ visit new_project_path
+ end
+
+ it "selects the user namespace" do
+ namespace = find("#project_namespace_id")
+
+ expect(namespace.text).to eq user.username
+ end
+ end
+
+ context "with group namespace" do
+ let(:group) { create(:group, :private, owner: user) }
+
+ before do
+ group.add_owner(user)
+ visit new_project_path(namespace_id: group.id)
+ end
+
+ it "selects the group namespace" do
+ namespace = find("#project_namespace_id option[selected]")
+
+ expect(namespace.text).to eq group.name
+ end
+
+ context "on validation error" do
+ before do
+ fill_in('project_path', with: 'private-group-project')
+ choose('Internal')
+ click_button('Create project')
+
+ expect(page).to have_css '.project-edit-errors .alert.alert-danger'
+ end
+
+ it "selects the group namespace" do
+ namespace = find("#project_namespace_id option[selected]")
+
+ expect(namespace.text).to eq group.name
+ end
+ end
+ end
+ end
+
context 'Import project options' do
before do
visit new_project_path
diff --git a/spec/features/projects/ref_switcher_spec.rb b/spec/features/projects/ref_switcher_spec.rb
index 4eafac1acd8..3b8f0b2d3f8 100644
--- a/spec/features/projects/ref_switcher_spec.rb
+++ b/spec/features/projects/ref_switcher_spec.rb
@@ -20,6 +20,8 @@ feature 'Ref switcher', feature: true, js: true do
input.set 'binary'
wait_for_ajax
+ expect(find('.dropdown-content ul')).to have_selector('li', count: 6)
+
page.within '.dropdown-content ul' do
input.native.send_keys :enter
end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index e94ca4fcfd2..e007044868c 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -101,6 +101,16 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
end
end
+ describe '#concurrent_foreign_key_name' do
+ it 'returns the name for a foreign key' do
+ name = model.concurrent_foreign_key_name(:this_is_a_very_long_table_name,
+ :with_a_very_long_column_name)
+
+ expect(name).to be_an_instance_of(String)
+ expect(name.length).to eq(13)
+ end
+ end
+
describe '#disable_statement_timeout' do
context 'using PostgreSQL' do
it 'disables statement timeouts' do
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index 2069d2a7c75..f35e963a14b 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -107,46 +107,47 @@ describe API::Todos, api: true do
end
end
- describe 'DELETE /todos/:id' do
+ describe 'POST /todos/:id/mark_as_done' do
context 'when unauthenticated' do
it 'returns authentication error' do
- delete api("/todos/#{pending_1.id}")
+ post api("/todos/#{pending_1.id}/mark_as_done")
- expect(response.status).to eq(401)
+ expect(response).to have_http_status(401)
end
end
context 'when authenticated' do
it 'marks a todo as done' do
- delete api("/todos/#{pending_1.id}", john_doe)
+ post api("/todos/#{pending_1.id}/mark_as_done", john_doe)
- expect(response.status).to eq(200)
+ expect(response).to have_http_status(201)
+ expect(json_response['id']).to eq(pending_1.id)
+ expect(json_response['state']).to eq('done')
expect(pending_1.reload).to be_done
end
it 'updates todos cache' do
expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original
- delete api("/todos/#{pending_1.id}", john_doe)
+ post api("/todos/#{pending_1.id}/mark_as_done", john_doe)
end
end
end
- describe 'DELETE /todos' do
+ describe 'POST /mark_as_done' do
context 'when unauthenticated' do
it 'returns authentication error' do
- delete api('/todos')
+ post api('/todos/mark_as_done')
- expect(response.status).to eq(401)
+ expect(response).to have_http_status(401)
end
end
context 'when authenticated' do
it 'marks all todos as done' do
- delete api('/todos', john_doe)
+ post api('/todos/mark_as_done', john_doe)
- expect(response.status).to eq(200)
- expect(response.body).to eq('3')
+ expect(response).to have_http_status(204)
expect(pending_1.reload).to be_done
expect(pending_2.reload).to be_done
expect(pending_3.reload).to be_done
@@ -155,7 +156,7 @@ describe API::Todos, api: true do
it 'updates todos cache' do
expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original
- delete api("/todos", john_doe)
+ post api("/todos/mark_as_done", john_doe)
end
end
end
diff --git a/spec/requests/api/v3/todos_spec.rb b/spec/requests/api/v3/todos_spec.rb
new file mode 100644
index 00000000000..80fa697e949
--- /dev/null
+++ b/spec/requests/api/v3/todos_spec.rb
@@ -0,0 +1,73 @@
+require 'spec_helper'
+
+describe API::V3::Todos, api: true do
+ include ApiHelpers
+
+ let(:project_1) { create(:empty_project) }
+ let(:project_2) { create(:empty_project) }
+ let(:author_1) { create(:user) }
+ let(:author_2) { create(:user) }
+ let(:john_doe) { create(:user, username: 'john_doe') }
+ let!(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe) }
+ let!(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) }
+ let!(:pending_3) { create(:todo, project: project_1, author: author_2, user: john_doe) }
+ let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) }
+
+ before do
+ project_1.team << [john_doe, :developer]
+ project_2.team << [john_doe, :developer]
+ end
+
+ describe 'DELETE /todos/:id' do
+ context 'when unauthenticated' do
+ it 'returns authentication error' do
+ delete v3_api("/todos/#{pending_1.id}")
+
+ expect(response.status).to eq(401)
+ end
+ end
+
+ context 'when authenticated' do
+ it 'marks a todo as done' do
+ delete v3_api("/todos/#{pending_1.id}", john_doe)
+
+ expect(response.status).to eq(200)
+ expect(pending_1.reload).to be_done
+ end
+
+ it 'updates todos cache' do
+ expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original
+
+ delete v3_api("/todos/#{pending_1.id}", john_doe)
+ end
+ end
+ end
+
+ describe 'DELETE /todos' do
+ context 'when unauthenticated' do
+ it 'returns authentication error' do
+ delete v3_api('/todos')
+
+ expect(response.status).to eq(401)
+ end
+ end
+
+ context 'when authenticated' do
+ it 'marks all todos as done' do
+ delete v3_api('/todos', john_doe)
+
+ expect(response.status).to eq(200)
+ expect(response.body).to eq('3')
+ expect(pending_1.reload).to be_done
+ expect(pending_2.reload).to be_done
+ expect(pending_3.reload).to be_done
+ end
+
+ it 'updates todos cache' do
+ expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original
+
+ delete v3_api("/todos", john_doe)
+ end
+ end
+ end
+end