summaryrefslogtreecommitdiff
path: root/app/services/design_management/move_designs_service.rb
blob: ca715b103519cf25644a9fee9736da0578bcc360 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# frozen_string_literal: true

module DesignManagement
  class MoveDesignsService < DesignService
    # @param user [User] The current user
    # @param [Hash] params
    # @option params [DesignManagement::Design] :current_design
    # @option params [DesignManagement::Design] :previous_design (nil)
    # @option params [DesignManagement::Design] :next_design (nil)
    def initialize(user, params)
      super(nil, user, params.merge(issue: nil))
    end

    def execute
      return error(:no_focus) unless current_design.present?
      return error(:cannot_move) unless current_user.can?(:move_design, current_design)
      return error(:no_neighbors) unless neighbors.present?
      return error(:not_distinct) unless all_distinct?
      return error(:not_adjacent) if any_in_gap?
      return error(:not_same_issue) unless all_same_issue?

      move_nulls_to_end
      current_design.move_between(previous_design, next_design)
      current_design.save!
      success
    end

    def error(message)
      ServiceResponse.error(message: message)
    end

    def success
      ServiceResponse.success
    end

    private

    delegate :issue, :project, to: :current_design

    def move_nulls_to_end
      moved_records = current_design.class.move_nulls_to_end(issue.designs.in_creation_order)
      return if moved_records == 0

      current_design.reset
      next_design&.reset
      previous_design&.reset
    end

    def neighbors
      [previous_design, next_design].compact
    end

    def all_distinct?
      ids.uniq.size == ids.size
    end

    def any_in_gap?
      return false unless previous_design&.relative_position && next_design&.relative_position

      !previous_design.immediately_before?(next_design)
    end

    def all_same_issue?
      issue.designs.id_in(ids).count == ids.size
    end

    def ids
      @ids ||= [current_design, *neighbors].map(&:id)
    end

    def current_design
      params[:current_design]
    end

    def previous_design
      params[:previous_design]
    end

    def next_design
      params[:next_design]
    end
  end
end