From 3a1c02844e1d40490c3fe7b6a7dbb76cbad791bc Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Fri, 16 Sep 2016 05:01:42 -0300 Subject: Add CRUD functionality to global labels --- app/assets/stylesheets/pages/labels.scss | 2 +- app/controllers/admin/labels_controller.rb | 41 +++--- app/helpers/labels_helper.rb | 8 +- app/services/labels/base_service.rb | 4 +- app/services/labels/create_service.rb | 62 ++++++--- app/services/labels/destroy_service.rb | 46 +++++-- app/services/labels/generate_service.rb | 16 +-- app/services/labels/toggle_subscription_service.rb | 46 +++++-- app/services/labels/update_service.rb | 49 +++++-- app/views/admin/labels/_label.html.haml | 55 +++++++- app/views/admin/labels/_label_row.html.haml | 6 + app/views/admin/labels/edit.html.haml | 7 +- app/views/admin/labels/index.html.haml | 32 +++-- app/views/admin/labels/new.html.haml | 7 +- config/routes.rb | 6 +- features/admin/labels.feature | 1 + features/steps/admin/labels.rb | 8 +- spec/services/labels/create_service_spec.rb | 70 +++++++++- spec/services/labels/destroy_service_spec.rb | 129 ++++++++++++++++-- spec/services/labels/generate_service_spec.rb | 2 +- .../labels/toggle_subscription_service_spec.rb | 147 +++++++++++++++++++-- spec/services/labels/update_service_spec.rb | 144 +++++++++++++++++--- 22 files changed, 729 insertions(+), 159 deletions(-) create mode 100644 app/views/admin/labels/_label_row.html.haml diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index 1fc6fe9c55c..01777f0d38c 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -142,7 +142,7 @@ } } -.group-labels, .project-labels { +.global-labels, .group-labels, .project-labels { margin-top: 30px; .remove-priority { diff --git a/app/controllers/admin/labels_controller.rb b/app/controllers/admin/labels_controller.rb index d496f08a598..e539b17907a 100644 --- a/app/controllers/admin/labels_controller.rb +++ b/app/controllers/admin/labels_controller.rb @@ -1,11 +1,8 @@ class Admin::LabelsController < Admin::ApplicationController - before_action :set_label, only: [:show, :edit, :update, :destroy] + before_action :label, only: [:edit, :update, :destroy, :toggle_subscription] def index - @labels = Label.templates.page(params[:page]) - end - - def show + @labels = Label.global_labels.page(params[:page]) end def new @@ -16,40 +13,52 @@ class Admin::LabelsController < Admin::ApplicationController end def create - @label = Label.new(label_params) - @label.template = true + service = Labels::CreateService.new(nil, current_user, label_params.merge(label_type: :global_label)) + + @label = service.execute - if @label.save - redirect_to admin_labels_url, notice: "Label was created" + if @label.valid? + redirect_to admin_labels_url, notice: 'Label was created.' else render :new end end def update - if @label.update(label_params) - redirect_to admin_labels_path, notice: 'label was successfully updated.' + service = Labels::UpdateService.new(nil, current_user, label_params) + + if service.execute(@label) + redirect_to admin_labels_path, notice: 'Label was successfully updated.' else render :edit end end def destroy - @label.destroy - @labels = Label.templates + Labels::DestroyService.new(nil, current_user).execute(@label) + + @labels = Label.global_labels respond_to do |format| format.html do - redirect_to(admin_labels_path, notice: 'Label was removed') + redirect_to admin_labels_path, notice: 'Label was removed.' end format.js end end + def toggle_subscription + return unless current_user + + Labels::ToggleSubscriptionService.new(nil, current_user).execute(@label) + + head :ok + end + private - def set_label - @label = Label.find(params[:id]) + def label + @label = Label.with_type(:global_label).find(params[:id]) end def label_params diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index c0b4646bcc6..9959eae577b 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -44,15 +44,19 @@ module LabelsHelper end def label_filter_path(subject, label, type: issue) - if subject.is_a?(Project) + case subject + when Project send("namespace_project_#{type.to_s.pluralize}_path", subject.namespace, subject, label_name: [label.name]) - else + when Group send("#{type.to_s.pluralize}_group_path", subject, label_name: [label.name]) + else + send("#{type.to_s.pluralize}_dashboard_path", + label_name: [label.name]) end end diff --git a/app/services/labels/base_service.rb b/app/services/labels/base_service.rb index 48df8811a80..ff5d3f7a23b 100644 --- a/app/services/labels/base_service.rb +++ b/app/services/labels/base_service.rb @@ -8,8 +8,8 @@ module Labels attr_reader :subject, :user, :params - def find_labels(subject, title) - Label.with_type(:group_label).where(subject: subject, title: title) + def find_labels(subject, label_type, title) + Label.with_type(label_type).where(subject: subject, title: title) end end end diff --git a/app/services/labels/create_service.rb b/app/services/labels/create_service.rb index 97281b7c048..e7ca812778e 100644 --- a/app/services/labels/create_service.rb +++ b/app/services/labels/create_service.rb @@ -1,33 +1,61 @@ module Labels class CreateService < Labels::BaseService def execute - Label.transaction do - label = subject.labels.build(params) - label.label_type = subject.is_a?(Group) ? :group_label : :project_label + label = Label.new(params.merge(subject: subject)) - return label if subject.is_a?(Project) && exists_at_group_level? + return label if label_already_exists?(label) - if label.save && subject.is_a?(Group) - replicate_labels_to_projects + Label.transaction do + if label.save + replicate_global_label if label.global_label? + replicate_group_label if label.group_label? end - - label end + + label end private - def exists_at_group_level? - subject.group && subject.group.labels.where(title: params[:title]).exists? + def label_already_exists?(label) + return false if label.global_label? + return label_exists_at_global_level? if label.group_label? + + label_exists_at_global_level? || label_exists_at_group_level? end - def replicate_labels_to_projects - subject.projects.each do |project| - project.labels.find_or_create_by!(title: params[:title]) do |label| - label.color = params[:color] - label.description = params[:description] - label.label_type = :group_label - end + def label_exists_at_global_level? + find_labels(nil, :global_label, params[:title]).exists? + end + + def label_exists_at_group_level? + return false unless subject.group.present? + + find_labels(subject.group, :group_label, params[:title]).exists? + end + + def replicate_global_label + replicate_label_to_groups(Group.all) + replicate_label_to_projects(Project.all) + end + + def replicate_group_label + replicate_label_to_projects(subject.projects) + end + + def replicate_label_to_groups(groups) + groups.each { |group| replicate_label_to_resource(group) } + end + + def replicate_label_to_projects(projects) + projects.each { |project| replicate_label_to_resource(project) } + end + + def replicate_label_to_resource(resource) + resource.labels.find_or_create_by!(title: params[:title]) do |label| + label.color = params[:color] + label.description = params[:description] + label.label_type = params[:label_type] end end end diff --git a/app/services/labels/destroy_service.rb b/app/services/labels/destroy_service.rb index 82a1dba3aee..16d07e9687b 100644 --- a/app/services/labels/destroy_service.rb +++ b/app/services/labels/destroy_service.rb @@ -4,23 +4,47 @@ module Labels Label.transaction do label.destroy - return unless label.group_label? + return if label.project_label? - if subject.is_a?(Group) - destroy_labels(subject.projects, label.title) - end - - if subject.is_a?(Project) - destroy_labels(subject.group, label.title) - destroy_labels(subject.group.projects - [subject], label.title) - end + destroy_global_label(label.label_type, label.title) if label.global_label? + destroy_group_label(label.label_type, label.title) if label.group_label? end end private - def destroy_labels(subject, title) - find_labels(subject, title).each(&:destroy) + def destroy_global_label(label_type, title) + if subject.nil? + destroy_labels(Group.all, label_type, title) + destroy_labels(Project.all, label_type, title) + end + + if subject.is_a?(Group) + destroy_labels(nil, label_type, title) + destroy_labels(Group.where.not(id: subject), label_type, title) + destroy_labels(Project.all, label_type, title) + end + + if subject.is_a?(Project) + destroy_labels(nil, label_type, title) + destroy_labels(Group.all, label_type, title) + destroy_labels(Project.where.not(id: subject), label_type, title) + end + end + + def destroy_group_label(label_type, title) + if subject.is_a?(Group) + destroy_labels(subject.projects, label_type, title) + end + + if subject.is_a?(Project) + destroy_labels(subject.group, label_type, title) + destroy_labels(subject.group.projects.where.not(id: subject), label_type, title) + end + end + + def destroy_labels(subject, label_type, title) + find_labels(subject, label_type, title).each(&:destroy) end end end diff --git a/app/services/labels/generate_service.rb b/app/services/labels/generate_service.rb index 01039b04c11..8c24b570404 100644 --- a/app/services/labels/generate_service.rb +++ b/app/services/labels/generate_service.rb @@ -15,14 +15,14 @@ module Labels green = '#5cb85c' [ - { title: 'bug', color: red }, - { title: 'critical', color: red }, - { title: 'confirmed', color: red }, - { title: 'documentation', color: yellow }, - { title: 'support', color: yellow }, - { title: 'discussion', color: blue }, - { title: 'suggestion', color: blue }, - { title: 'enhancement', color: green } + { title: 'bug', color: red, label_type: params[:label_type] }, + { title: 'critical', color: red, label_type: params[:label_type] }, + { title: 'confirmed', color: red, label_type: params[:label_type] }, + { title: 'documentation', color: yellow, label_type: params[:label_type] }, + { title: 'support', color: yellow, label_type: params[:label_type] }, + { title: 'discussion', color: blue, label_type: params[:label_type] }, + { title: 'suggestion', color: blue, label_type: params[:label_type] }, + { title: 'enhancement', color: green, label_type: params[:label_type] } ] end end diff --git a/app/services/labels/toggle_subscription_service.rb b/app/services/labels/toggle_subscription_service.rb index 343f8ba3eee..c643c82c3f2 100644 --- a/app/services/labels/toggle_subscription_service.rb +++ b/app/services/labels/toggle_subscription_service.rb @@ -4,23 +4,47 @@ module Labels Label.transaction do label.toggle_subscription(user) - return unless label.group_label? + return if label.project_label? - if subject.is_a?(Group) - toggle_subscription(subject.projects, label.title) - end - - if subject.is_a?(Project) - toggle_subscription(subject.group, label.title) - toggle_subscription(subject.group.projects - [subject], label.title) - end + toggle_subscription_to_global_label(label.label_type, label.title) if label.global_label? + toggle_subscription_to_group_label(label.label_type, label.title) if label.group_label? end end private - def toggle_subscription(subject, title) - find_labels(subject, title).each { |label| label.toggle_subscription(user) } + def toggle_subscription_to_global_label(label_type, title) + if subject.nil? + toggle_subscription(Group.all, label_type, title) + toggle_subscription(Project.all, label_type, title) + end + + if subject.is_a?(Group) + toggle_subscription(nil, label_type, title) + toggle_subscription(Group.where.not(id: subject), label_type, title) + toggle_subscription(Project.all, label_type, title) + end + + if subject.is_a?(Project) + toggle_subscription(nil, label_type, title) + toggle_subscription(Group.all, label_type, title) + toggle_subscription(Project.where.not(id: subject), label_type, title) + end + end + + def toggle_subscription_to_group_label(label_type, title) + if subject.is_a?(Group) + toggle_subscription(subject.projects, label_type, title) + end + + if subject.is_a?(Project) + toggle_subscription(subject.group, label_type, title) + toggle_subscription(subject.group.projects.where.not(id: subject), label_type, title) + end + end + + def toggle_subscription(subject, label_type, title) + find_labels(subject, label_type, title).each { |label| label.toggle_subscription(user) } end end end diff --git a/app/services/labels/update_service.rb b/app/services/labels/update_service.rb index dd24e8894a1..12f40120822 100644 --- a/app/services/labels/update_service.rb +++ b/app/services/labels/update_service.rb @@ -1,20 +1,15 @@ module Labels class UpdateService < Labels::BaseService def execute(label) + previous_title = label.title.dup + Label.transaction do - previous_title = label.title.dup label.update(params) - return label unless label.valid? && label.group_label? - - if subject.is_a?(Group) - update_labels(subject.projects, previous_title) - end + return label unless label.valid? - if subject.is_a?(Project) - update_labels(subject.group, previous_title) - update_labels(subject.group.projects - [subject], previous_title) - end + replicate_global_label(label.label_type, previous_title) if label.global_label? + replicate_group_label(label.label_type, previous_title) if label.group_label? label end @@ -22,8 +17,38 @@ module Labels private - def update_labels(subject, title) - find_labels(subject, title).update_all(params) + def replicate_global_label(label_type, title) + if subject.nil? + replicate_label(Group.all, label_type, title) + replicate_label(Project.all, label_type, title) + end + + if subject.is_a?(Group) + replicate_label(nil, label_type, title) + replicate_label(Group.where.not(id: subject), label_type, title) + replicate_label(Project.all, label_type, title) + end + + if subject.is_a?(Project) + replicate_label(nil, label_type, title) + replicate_label(Group.all, label_type, title) + replicate_label(Project.where.not(id: subject), label_type, title) + end + end + + def replicate_group_label(label_type, title) + if subject.is_a?(Group) + replicate_label(subject.projects, label_type, title) + end + + if subject.is_a?(Project) + replicate_label(subject.group, label_type, title) + replicate_label(subject.group.projects.where.not(id: subject), label_type, title) + end + end + + def replicate_label(subject, label_type, title) + find_labels(subject, label_type, title).update_all(params) end end end diff --git a/app/views/admin/labels/_label.html.haml b/app/views/admin/labels/_label.html.haml index f417b2e44a4..c6d5c9edce9 100644 --- a/app/views/admin/labels/_label.html.haml +++ b/app/views/admin/labels/_label.html.haml @@ -1,7 +1,48 @@ -%li{id: dom_id(label)} - .label-row - = render_colored_label(label, tooltip: false) - = markdown(label.description, pipeline: :single_line) - .pull-right - = link_to 'Edit', edit_admin_label_path(label), class: 'btn btn-sm' - = link_to 'Delete', admin_label_path(label), class: 'btn btn-sm btn-remove remove-row', method: :delete, remote: true, data: {confirm: "Delete this label? Are you sure?"} +- label_css_id = dom_id(label) +- open_issues_count = label.open_issues_count(current_user) +- open_merge_requests_count = label.open_merge_requests_count(current_user) + +%li{id: label_css_id, data: { id: label.id } } + = render 'label_row', label: label + + .visible-xs.visible-sm-inline-block.visible-md-inline-block.dropdown + %button.btn.btn-default.label-options-toggle{ data: { toggle: 'dropdown' } } + Options + %span.caret + .dropdown-menu.dropdown-menu-align-right + %ul + %li + = link_to_label(label, type: :merge_request) do + = pluralize open_merge_requests_count, 'merge request' + %li + = link_to_label(label) do + = pluralize open_issues_count, 'open issue' + %li.label-subscription{ data: { url: toggle_subscription_admin_label_path(label) } } + %a.js-subscribe-button.label-subscribe-button.subscription-status{ role: "button", href: "#", data: { toggle: "tooltip", status: label_subscription_status(label) } } + %span= label_subscription_toggle_button_text(label) + %li + = link_to 'Edit', edit_admin_label_path(label) + %li + = link_to 'Delete', admin_label_path(label), title: 'Delete', method: :delete, remote: true, data: { confirm: 'Remove this label? Are you sure?' } + + .pull-right.hidden-xs.hidden-sm.hidden-md + = link_to_label(label, type: :merge_request, css_class: 'btn btn-transparent btn-action') do + = pluralize label.open_merge_requests_count, 'merge request' + = link_to_label(label, css_class: 'btn btn-transparent btn-action') do + = pluralize open_issues_count, 'open issue' + + .label-subscription.inline{ data: { url: toggle_subscription_admin_label_path(label) } } + %button.js-subscribe-button.label-subscribe-button.btn.btn-transparent.btn-action.subscription-status{ type: "button", title: label_subscription_toggle_button_text(label), data: { toggle: "tooltip", status: label_subscription_status(label) } } + %span.sr-only= label_subscription_toggle_button_text(label) + = icon('eye', class: 'label-subscribe-button-icon') + = icon('spinner spin', class: 'label-subscribe-button-loading') + + = link_to edit_admin_label_path(label), title: 'Edit', class: 'btn btn-transparent btn-action', data: { toggle: 'tooltip' } do + %span.sr-only Edit + = icon('pencil-square-o') + = link_to admin_label_path(label), title: 'Delete', class: 'btn btn-transparent btn-action remove-row', method: :delete, remote: true, data: { confirm: 'Remove this label? Are you sure?', toggle: 'tooltip' } do + %span.sr-only Delete + = icon('trash-o') + + :javascript + new Subscription('##{dom_id(label)} .label-subscription'); diff --git a/app/views/admin/labels/_label_row.html.haml b/app/views/admin/labels/_label_row.html.haml new file mode 100644 index 00000000000..84c5c44ddcb --- /dev/null +++ b/app/views/admin/labels/_label_row.html.haml @@ -0,0 +1,6 @@ +%span.label-row + %span.label-name + = render_colored_label(label, tooltip: false) + - if label.description + %span.label-description + = markdown(label.description, pipeline: :single_line) diff --git a/app/views/admin/labels/edit.html.haml b/app/views/admin/labels/edit.html.haml index 309aedceded..35ce01ccfbf 100644 --- a/app/views/admin/labels/edit.html.haml +++ b/app/views/admin/labels/edit.html.haml @@ -1,5 +1,8 @@ -- page_title "Edit", @label.name, "Labels" +- page_title 'Edit', @label.name, 'Labels' + %h3.page-title - Edit Label + = icon('globe') + Edit Global Label %hr + = render 'form' diff --git a/app/views/admin/labels/index.html.haml b/app/views/admin/labels/index.html.haml index 05d6b9ed238..58c2bdae9f5 100644 --- a/app/views/admin/labels/index.html.haml +++ b/app/views/admin/labels/index.html.haml @@ -1,18 +1,22 @@ -- page_title "Labels" +- page_title 'Labels' -%div - = link_to new_admin_label_path, class: "pull-right btn btn-nr btn-new" do - New label - %h3.page-title - Labels -%hr +.top-area.adjust + .nav-text + Labels can be applied to issues and merge requests. + + .nav-controls + = link_to new_admin_label_path, class: 'btn btn-new' do + New label .labels - - if @labels.present? - %ul.bordered-list.manage-labels-list - = render @labels + .global-labels + %h5 + = icon('globe') + Global Labels + %ul.content-list.manage-labels-list.js-global-labels + - if @labels.present? + = render @labels = paginate @labels, theme: 'gitlab' - - else - .light-well - .nothing-here-block There are no labels yet - + - if @labels.blank? + .nothing-here-block + There are no labels yet diff --git a/app/views/admin/labels/new.html.haml b/app/views/admin/labels/new.html.haml index 0135ad0723d..1ab87bc8ec1 100644 --- a/app/views/admin/labels/new.html.haml +++ b/app/views/admin/labels/new.html.haml @@ -1,5 +1,8 @@ -- page_title "New Label" +- page_title 'New Global Label' + %h3.page-title - New Label + = icon('globe') + New Global Label %hr + = render 'form' diff --git a/config/routes.rb b/config/routes.rb index 180576d7252..f8d610099ef 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -314,7 +314,11 @@ Rails.application.routes.draw do put :clear_repository_check_states end - resources :labels + resources :labels, except: [:show], constraints: { id: /\d+/ } do + member do + post :toggle_subscription + end + end resources :runners, only: [:index, :show, :update, :destroy] do member do diff --git a/features/admin/labels.feature b/features/admin/labels.feature index 1af0e700bd4..9632c679ee1 100644 --- a/features/admin/labels.feature +++ b/features/admin/labels.feature @@ -25,6 +25,7 @@ Feature: Admin Issues Labels @javascript Scenario: I delete all labels When I delete all labels + And I visit admin labels page Then I should see labels help message Scenario: I create a label with invalid color diff --git a/features/steps/admin/labels.rb b/features/steps/admin/labels.rb index 55ddcc25085..c362c98d66d 100644 --- a/features/steps/admin/labels.rb +++ b/features/steps/admin/labels.rb @@ -23,13 +23,13 @@ class Spinach::Features::AdminIssuesLabels < Spinach::FeatureSteps step 'I have labels: "bug", "feature", "enhancement"' do ["bug", "feature", "enhancement"].each do |title| - Label.create(title: title, template: true) + Label.create(title: title, label_type: Label.label_types[:global_label]) end end step 'I delete all labels' do - page.within '.labels' do - page.all('.btn-remove').each do |remove| + page.within '.global-labels' do + page.all('.fa-trash-o').each do |remove| remove.click sleep 0.05 end @@ -112,6 +112,6 @@ class Spinach::Features::AdminIssuesLabels < Spinach::FeatureSteps end def bug_label - Label.templates.find_or_create_by(title: 'bug') + Label.global_labels.find_or_create_by(title: 'bug') end end diff --git a/spec/services/labels/create_service_spec.rb b/spec/services/labels/create_service_spec.rb index 8dfa6f70a6f..298c15b6ec6 100644 --- a/spec/services/labels/create_service_spec.rb +++ b/spec/services/labels/create_service_spec.rb @@ -13,10 +13,54 @@ describe Labels::CreateService, services: true do } end - context 'with a group as subject' do - subject(:service) { described_class.new(group, double, params) } + context 'with a global label' do + subject(:service) { described_class.new(nil, double, params.merge(label_type: :global_label)) } - it 'creates a label' do + it 'creates the global label' do + expect { service.execute }.to change(Label.where(subject: nil, label_type: Label.label_types[:global_label]), :count).by(1) + end + + it 'sets label_type to global_label' do + service.execute + + expect(Label.last).to have_attributes(label_type: 'global_label') + end + + it 'becames available to all already existing groups' do + service.execute + + expect(Label.where(params.merge(subject: group, label_type: Label.label_types[:global_label]))).not_to be_empty + end + + it 'becames available to all already existing projects' do + service.execute + + expect(project.labels.where(params.merge(label_type: Label.label_types[:global_label]))).not_to be_empty + end + + it 'does not overwrite label that already exists in a group' do + params = { title: 'Security', color: '#FF0000', description: 'Sample', label_type: Label.label_types[:group_label] } + group.labels.create(params) + + service.execute + + expect(group.labels.where(params)).not_to be_empty + end + + it 'does not overwrite label that already exists in a project' do + params = { title: 'Security', color: '#FF0000', description: 'Sample', label_type: Label.label_types[:project_label] } + project.labels.create(params) + + service.execute + + expect(project.labels.where(params)).not_to be_empty + end + end + + context 'with a group label' do + subject(:service) { described_class.new(group, double, params.merge(label_type: :group_label)) } + + it 'creates the group label' do expect { service.execute }.to change(group.labels, :count).by(1) end @@ -32,8 +76,14 @@ describe Labels::CreateService, services: true do expect(project.labels.where(params.merge(label_type: Label.label_types[:group_label]))).not_to be_empty end + it 'does not create a label that already exists on the global level' do + Label.create(params.merge(label_type: Label.label_types[:global_label])) + + expect { service.execute }.not_to change(group.labels, :count) + end + it 'does not overwrite label that already exists in the project' do - params = { title: 'Security', color: '#FF0000', description: 'Sample' } + params = { title: 'Security', color: '#FF0000', description: 'Sample', label_type: Label.label_types[:project_label] } project.labels.create(params) service.execute @@ -42,10 +92,10 @@ describe Labels::CreateService, services: true do end end - context 'with a project as subject' do - subject(:service) { described_class.new(project, double, params) } + context 'with a project label' do + subject(:service) { described_class.new(project, double, params.merge(label_type: :project_label)) } - it 'creates a label' do + it 'creates the project label' do expect { service.execute }.to change(project.labels, :count).by(1) end @@ -55,6 +105,12 @@ describe Labels::CreateService, services: true do expect(Label.last).to have_attributes(label_type: 'project_label') end + it 'does not create a label that already exists on the global level' do + Label.create(params.merge(label_type: Label.label_types[:global_label])) + + expect { service.execute }.not_to change(project.labels, :count) + end + it 'does not create a label that already exists on the group level' do group.labels.create(params.merge(label_type: Label.label_types[:group_label])) diff --git a/spec/services/labels/destroy_service_spec.rb b/spec/services/labels/destroy_service_spec.rb index 6d3810154e6..9452fdf6df2 100644 --- a/spec/services/labels/destroy_service_spec.rb +++ b/spec/services/labels/destroy_service_spec.rb @@ -2,20 +2,51 @@ require 'spec_helper' describe Labels::DestroyService, services: true do describe '#execute' do - let!(:group) { create(:group) } - let!(:project1) { create(:empty_project, group: group) } - let!(:project2) { create(:empty_project, group: group) } + let!(:group1) { create(:group) } + let!(:group2) { create(:group) } + let!(:project1) { create(:empty_project, group: group1) } + let!(:project2) { create(:empty_project, group: group1) } + + context 'with a global label' do + let!(:label) { create(:global_label, title: 'Bug') } + + subject(:service) { described_class.new(nil, double) } + + it 'removes the global label' do + expect { service.execute(label) }.to change(Label.where(subject: nil, label_type: Label.label_types[:global_label]), :count).by(-1) + end + + it 'removes the label of all groups that have the label' do + create(:global_label, subject: group1, title: 'Bug') + create(:global_label, subject: group2, title: 'Bug') + + service.execute(label) + + expect(group1.reload.labels).to be_empty + expect(group2.reload.labels).to be_empty + end + + it 'removes the label of all projects that have the label' do + create(:global_label, subject: project1, title: 'Bug') + create(:global_label, subject: project2, title: 'Bug') + + service.execute(label) + + expect(project1.reload.labels).to be_empty + expect(project2.reload.labels).to be_empty + end + end context 'with a group label' do - let!(:label) { create(:group_label, subject: group, title: 'Bug') } + let!(:label) { create(:group_label, subject: group1, title: 'Bug') } - subject(:service) { described_class.new(group, double) } + subject(:service) { described_class.new(group1, double) } it 'removes the group label' do - expect { service.execute(label) }.to change(group.labels, :count).by(-1) + expect { service.execute(label) }.to change(group1.labels, :count).by(-1) end - it 'removes the label from all projects inside the group' do + it 'removes the label from all projects inside the group that have the label' do create(:group_label, subject: project1, title: 'Bug') create(:group_label, subject: project2, title: 'Bug') @@ -24,6 +55,41 @@ describe Labels::DestroyService, services: true do expect(project1.labels.where(title: 'Bug')).to be_empty expect(project2.labels.where(title: 'Bug')).to be_empty end + + context 'inherited from a global label' do + let!(:label) { create(:global_label, subject: group1, title: 'Bug') } + + it 'removes the global label' do + create(:global_label, subject: nil, title: 'Bug') + + expect { service.execute(label) }.to change(Label.where(subject: nil, label_type: Label.label_types[:global_label]), :count).by(-1) + end + + it 'removes the group label' do + create(:global_label, subject: nil, title: 'Bug') + + expect { service.execute(label) }.to change(group1.labels, :count).by(-1) + end + + it 'removes the label of all groups that have the label' do + create(:global_label, subject: group2, title: 'Bug') + + expect { service.execute(label) }.to change(group2.labels, :count).by(-1) + end + + it 'removes the label of all projects that have the label' do + project3 = create(:empty_project, group: group2) + create(:global_label, subject: project1, title: 'Bug') + create(:global_label, subject: project2, title: 'Bug') + create(:global_label, subject: project3, title: 'Bug') + + service.execute(label) + + expect(project1.reload.labels).to be_empty + expect(project2.reload.labels).to be_empty + expect(project3.reload.labels).to be_empty + end + end end context 'with a project label' do @@ -35,26 +101,61 @@ describe Labels::DestroyService, services: true do expect { service.execute(label) }.to change(project1.labels, :count).by(-1) end + context 'inherited from a global label' do + let!(:label) { create(:global_label, subject: project1, title: 'Bug') } + + it 'removes the global label' do + create(:global_label, subject: nil, title: 'Bug') + + expect { service.execute(label) }.to change(Label.where(subject: nil, label_type: Label.label_types[:global_label]), :count).by(-1) + end + + it 'removes the project label' do + expect { service.execute(label) }.to change(project1.labels, :count).by(-1) + end + + it 'removes the label of all groups that have the label' do + create(:global_label, subject: group1, title: 'Bug') + create(:global_label, subject: group2, title: 'Bug') + + service.execute(label) + + expect(group1.reload.labels).to be_empty + expect(group2.reload.labels).to be_empty + end + + it 'removes the label of all projects that have the label' do + project3 = create(:empty_project, group: group2) + create(:global_label, subject: project2, title: 'Bug') + create(:global_label, subject: project3, title: 'Bug') + + service.execute(label) + + expect(project2.reload.labels).to be_empty + expect(project3.reload.labels).to be_empty + end + end + context 'inherited from a group' do let!(:label) { create(:group_label, subject: project1, title: 'Bug') } it 'removes the group label' do - create(:group_label, subject: group, title: 'Bug') + create(:group_label, subject: group1, title: 'Bug') + + expect { service.execute(label) }.to change(group1.labels, :count).by(-1) + end - expect { service.execute(label) }.to change(group.labels, :count).by(-1) + it 'removes the project label' do + expect { service.execute(label) }.to change(project1.labels, :count).by(-1) end - it 'removes the label from all projects inside the group' do + it 'removes the label from all projects inside the group that have the label' do create(:group_label, subject: project2, title: 'Bug') service.execute(label) expect(project2.labels.where(title: 'Bug')).to be_empty end - - it 'removes the project label' do - expect { service.execute(label) }.to change(project1.labels, :count).by(-1) - end end end end diff --git a/spec/services/labels/generate_service_spec.rb b/spec/services/labels/generate_service_spec.rb index e6c27fbe4e3..e07ccac99cb 100644 --- a/spec/services/labels/generate_service_spec.rb +++ b/spec/services/labels/generate_service_spec.rb @@ -4,7 +4,7 @@ describe Labels::GenerateService, services: true do describe '#execute' do let(:project) { create(:empty_project) } - subject(:service) { described_class.new(project, double) } + subject(:service) { described_class.new(project, double, label_type: :project_label) } context 'when project labels is empty' do it 'creates the default labels' do diff --git a/spec/services/labels/toggle_subscription_service_spec.rb b/spec/services/labels/toggle_subscription_service_spec.rb index e2cc7af0d5d..82a1958eaa7 100644 --- a/spec/services/labels/toggle_subscription_service_spec.rb +++ b/spec/services/labels/toggle_subscription_service_spec.rb @@ -3,14 +3,55 @@ require 'spec_helper' describe Labels::ToggleSubscriptionService, services: true do describe '#execute' do let(:user) { create(:user) } - let!(:group) { create(:group) } - let!(:project1) { create(:empty_project, group: group) } - let!(:project2) { create(:empty_project, group: group) } + let!(:group1) { create(:group) } + let!(:group2) { create(:group) } + let!(:project1) { create(:empty_project, group: group1) } + let!(:project2) { create(:empty_project, group: group1) } + + it 'delegates the subscription management to Label#toggle_subscription' do + label = create(:label, subject: project1) + + expect(label).to receive(:toggle_subscription).once + + described_class.new(project1, user).execute(label) + end + + context 'with a global label' do + let(:label) { create(:global_label, title: 'Bug') } + + subject(:service) { described_class.new(nil, user) } + + it 'subscribes to global label' do + service.execute(label) + + expect(label.subscribed?(user)).to eq true + end + + it 'subscribes to labels of all groups that have the label' do + label1 = create(:global_label, subject: group1, title: 'Bug') + label2 = create(:global_label, subject: group2, title: 'Bug') + + service.execute(label) + + expect(label1.subscribed?(user)).to eq true + expect(label2.subscribed?(user)).to eq true + end + + it 'subscribes to label of all projects that have the label' do + label1 = create(:global_label, subject: project1, title: 'Bug') + label2 = create(:global_label, subject: project2, title: 'Bug') + + service.execute(label) + + expect(label1.subscribed?(user)).to eq true + expect(label2.subscribed?(user)).to eq true + end + end context 'with a group label' do - let(:label) { create(:group_label, subject: group, title: 'Bug') } + let(:label) { create(:group_label, subject: group1, title: 'Bug') } - subject(:service) { described_class.new(group, user) } + subject(:service) { described_class.new(group1, user) } it 'subscribes to group label' do service.execute(label) @@ -18,7 +59,7 @@ describe Labels::ToggleSubscriptionService, services: true do expect(label.subscribed?(user)).to eq true end - it 'subscribes to labels from all projects inside the group' do + it 'subscribes to labels from all projects inside the group that have the label' do label1 = create(:group_label, subject: project1, title: 'Bug') label2 = create(:group_label, subject: project2, title: 'Bug') @@ -27,6 +68,46 @@ describe Labels::ToggleSubscriptionService, services: true do expect(label1.subscribed?(user)).to eq true expect(label2.subscribed?(user)).to eq true end + + context 'inherited from a global label' do + it 'subscribes to global label' do + label1 = create(:global_label, title: 'Bug') + label2 = create(:global_label, subject: group1, title: 'Bug') + + service.execute(label2) + + expect(label1.subscribed?(user)).to eq true + end + + it 'subscribes to group label' do + label = create(:group_label, subject: group1, title: 'Bug') + + service.execute(label) + + expect(label.subscribed?(user)).to eq true + end + + it 'subscribes to label of all groups that have the label' do + label1 = create(:global_label, subject: group1, title: 'Bug') + label2 = create(:global_label, subject: group2, title: 'Bug') + + service.execute(label1) + + expect(label2.subscribed?(user)).to eq true + end + + it 'subscribes to label of all projects that have the label' do + project3 = create(:empty_project, group: group2) + label1 = create(:global_label, subject: project1, title: 'Bug') + label2 = create(:global_label, subject: project2, title: 'Bug') + label3 = create(:global_label, subject: project3, title: 'Bug') + + service.execute(label1) + + expect(label2.subscribed?(user)).to eq true + expect(label3.subscribed?(user)).to eq true + end + end end context 'with a project label' do @@ -40,19 +121,53 @@ describe Labels::ToggleSubscriptionService, services: true do expect(label.subscribed?(user)).to eq true end - context 'inherited from a group' do - let(:label1) { create(:group_label, subject: project1, title: 'Bug') } + context 'inherited from a global label' do + it 'subscribes to global label' do + label1 = create(:global_label, title: 'Bug') + label2 = create(:global_label, subject: project1, title: 'Bug') - it 'subscribes to group label' do - label2 = create(:group_label, subject: group, title: 'Bug') + service.execute(label2) + + expect(label1.subscribed?(user)).to eq true + end + + it 'subscribes to project label' do + label = create(:global_label, subject: project1, title: 'Bug') + + service.execute(label) + + expect(label.subscribed?(user)).to eq true + end + + it 'subscribes to label of all groups that have the label' do + label1 = create(:global_label, subject: project1, title: 'Bug') + label2 = create(:global_label, subject: group1, title: 'Bug') + label3 = create(:global_label, subject: group2, title: 'Bug') service.execute(label1) expect(label2.subscribed?(user)).to eq true + expect(label3.subscribed?(user)).to eq true end - it 'subscribes to labels from all projects inside the group' do - label2 = create(:group_label, subject: project2, title: 'Bug') + it 'subscribes to label of all projects that have the label' do + project3 = create(:empty_project, group: group2) + label1 = create(:global_label, subject: project1, title: 'Bug') + label2 = create(:global_label, subject: project2, title: 'Bug') + label3 = create(:global_label, subject: project3, title: 'Bug') + + service.execute(label1) + + expect(label2.subscribed?(user)).to eq true + expect(label3.subscribed?(user)).to eq true + end + end + + context 'inherited from a group' do + let(:label1) { create(:group_label, subject: project1, title: 'Bug') } + + it 'subscribes to group label' do + label2 = create(:group_label, subject: group1, title: 'Bug') service.execute(label1) @@ -64,6 +179,14 @@ describe Labels::ToggleSubscriptionService, services: true do expect(label1.subscribed?(user)).to eq true end + + it 'subscribes to labels from all projects inside the group that have the label' do + label2 = create(:group_label, subject: project2, title: 'Bug') + + service.execute(label1) + + expect(label2.subscribed?(user)).to eq true + end end end end diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb index 24123ca22d9..7a4e6778989 100644 --- a/spec/services/labels/update_service_spec.rb +++ b/spec/services/labels/update_service_spec.rb @@ -2,9 +2,10 @@ require 'spec_helper' describe Labels::UpdateService, services: true do describe '#execute' do - let!(:group) { create(:group) } - let!(:project1) { create(:empty_project, group: group) } - let!(:project2) { create(:empty_project, group: group) } + let!(:group1) { create(:group) } + let!(:group2) { create(:group) } + let!(:project1) { create(:empty_project, group: group1) } + let!(:project2) { create(:empty_project, group: group1) } let(:params) do { @@ -14,10 +15,42 @@ describe Labels::UpdateService, services: true do } end + context 'with a global label' do + let(:label) { create(:global_label, title: 'Bug') } + + subject(:service) { described_class.new(nil, double, params) } + + it 'updates the global label' do + service.execute(label) + + expect(label).to have_attributes(params) + end + + it 'updates the label of all groups that have the label' do + label1 = create(:global_label, subject: group1, title: 'Bug') + label2 = create(:global_label, subject: group2, title: 'Bug') + + service.execute(label) + + expect(label1.reload).to have_attributes(params) + expect(label2.reload).to have_attributes(params) + end + + it 'updates the label of all projects that have the label' do + label1 = create(:global_label, subject: project1, title: 'Bug') + label2 = create(:global_label, subject: project2, title: 'Bug') + + service.execute(label) + + expect(label1.reload).to have_attributes(params) + expect(label2.reload).to have_attributes(params) + end + end + context 'with a group label' do - let(:label) { create(:label, subject: group, title: 'Bug') } + let(:label) { create(:group_label, subject: group1, title: 'Bug') } - subject(:service) { described_class.new(group, double, params) } + subject(:service) { described_class.new(group1, double, params) } it 'updates the group label' do service.execute(label) @@ -25,15 +58,55 @@ describe Labels::UpdateService, services: true do expect(label).to have_attributes(params) end - it 'updates the label of all projects inside the group' do + it 'updates the label of all projects inside the group that have the label' do label1 = create(:group_label, subject: project1, title: 'Bug') label2 = create(:group_label, subject: project2, title: 'Bug') - service.execute(label1) + service.execute(label) expect(label1.reload).to have_attributes(params) expect(label2.reload).to have_attributes(params) end + + context 'inherited from a global label' do + it 'updates the global label' do + label1 = create(:global_label, title: 'Bug') + label2 = create(:global_label, subject: group1, title: 'Bug') + + service.execute(label2) + + expect(label1.reload).to have_attributes(params) + end + + it 'updates the group label' do + label = create(:group_label, subject: group1, title: 'Bug') + + service.execute(label) + + expect(label.reload).to have_attributes(params) + end + + it 'updates the label of all groups that have the label' do + label1 = create(:global_label, subject: group1, title: 'Bug') + label2 = create(:global_label, subject: group2, title: 'Bug') + + service.execute(label1) + + expect(label2.reload).to have_attributes(params) + end + + it 'updates the label of all projects that have the label' do + project3 = create(:empty_project, group: group2) + label1 = create(:global_label, subject: project1, title: 'Bug') + label2 = create(:global_label, subject: project2, title: 'Bug') + label3 = create(:global_label, subject: project3, title: 'Bug') + + service.execute(label1) + + expect(label2.reload).to have_attributes(params) + expect(label3.reload).to have_attributes(params) + end + end end context 'with a project label' do @@ -47,24 +120,56 @@ describe Labels::UpdateService, services: true do expect(label).to have_attributes(params) end - context 'inherited from a group' do - it 'updates the group label' do - label1 = create(:group_label, subject: group, title: 'Bug') - label2 = create(:group_label, subject: project1, title: 'Bug') + context 'inherited from a global label' do + it 'updates the global label' do + label1 = create(:global_label, title: 'Bug') + label2 = create(:global_label, subject: project1, title: 'Bug') service.execute(label2) expect(label1.reload).to have_attributes(params) end - it 'updates the label of all projects inside the group' do - label1 = create(:group_label, subject: project1, title: 'Bug') - label2 = create(:group_label, subject: project2, title: 'Bug') + it 'updates the project label' do + label = create(:global_label, subject: project1, title: 'Bug') + + service.execute(label) + + expect(label.reload).to have_attributes(params) + end + + it 'updates the label of all groups that have the label' do + label1 = create(:global_label, subject: project1, title: 'Bug') + label2 = create(:global_label, subject: group1, title: 'Bug') + label3 = create(:global_label, subject: group2, title: 'Bug') service.execute(label1) - expect(label1.reload).to have_attributes(params) expect(label2.reload).to have_attributes(params) + expect(label3.reload).to have_attributes(params) + end + + it 'updates the label of all projects that have the label' do + project3 = create(:empty_project, group: group2) + label1 = create(:global_label, subject: project1, title: 'Bug') + label2 = create(:global_label, subject: project2, title: 'Bug') + label3 = create(:global_label, subject: project3, title: 'Bug') + + service.execute(label1) + + expect(label2.reload).to have_attributes(params) + expect(label3.reload).to have_attributes(params) + end + end + + context 'inherited from a group label' do + it 'updates the group label' do + label1 = create(:group_label, subject: group1, title: 'Bug') + label2 = create(:group_label, subject: project1, title: 'Bug') + + service.execute(label2) + + expect(label1.reload).to have_attributes(params) end it 'updates the project label' do @@ -74,6 +179,15 @@ describe Labels::UpdateService, services: true do expect(label).to have_attributes(params) end + + it 'updates the label of all projects inside the group that have the label' do + label1 = create(:group_label, subject: project1, title: 'Bug') + label2 = create(:group_label, subject: project2, title: 'Bug') + + service.execute(label1) + + expect(label2.reload).to have_attributes(params) + end end end end -- cgit v1.2.1