card 1.96.1 → 1.96.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/config/locales/de.yml +18 -23
  4. data/config/locales/en.yml +16 -21
  5. data/config/locales/es.yml +16 -21
  6. data/lib/card.rb +1 -3
  7. data/lib/card/codename.rb +2 -1
  8. data/lib/card/error.rb +73 -57
  9. data/lib/card/format.rb +2 -2
  10. data/lib/card/format/error.rb +17 -18
  11. data/lib/card/format/nesting/mode.rb +1 -1
  12. data/lib/card/format/permission.rb +8 -10
  13. data/lib/card/format/render.rb +1 -2
  14. data/lib/card/model/save_helper.rb +20 -12
  15. data/lib/card/query.rb +1 -1
  16. data/lib/card/query/card_query.rb +2 -2
  17. data/lib/card/query/card_query/found_by.rb +43 -0
  18. data/lib/card/query/card_query/match_attributes.rb +72 -0
  19. data/lib/card/query/card_query/relational_attributes.rb +19 -0
  20. data/lib/card/view.rb +0 -1
  21. data/lib/card/view/cache_action.rb +1 -10
  22. data/mod/account/set/right/token.rb +1 -3
  23. data/mod/account/set/self/account_links.rb +9 -12
  24. data/mod/basic_formats/set/all/json.rb +19 -54
  25. data/mod/basic_formats/spec/set/all/json_spec.rb +13 -3
  26. data/mod/basic_formats/spec/shared_context/json_shared_context.rb +3 -8
  27. data/mod/basic_types/set/type/json.rb +13 -1
  28. data/mod/bootstrap/set/abstract/bootswatch_theme/html_views.rb +0 -1
  29. data/mod/bootstrap/set/all/bootstrap/helper.rb +7 -0
  30. data/mod/bootstrap/set/self/script_bootstrap.rb +1 -2
  31. data/mod/core/set/all/content.rb +4 -6
  32. data/mod/core/set/all/export.rb +39 -15
  33. data/mod/core/set/all/fetch.rb +9 -0
  34. data/mod/core/set/all/permissions.rb +0 -4
  35. data/mod/core/set/all/phases.rb +1 -1
  36. data/mod/core/set/all/subcards.rb +1 -0
  37. data/mod/core/set/all/trash.rb +6 -2
  38. data/mod/core/set/all/type.rb +1 -1
  39. data/mod/core/set/all/utils.rb +13 -1
  40. data/mod/core/spec/set/all/fetch_spec.rb +17 -4
  41. data/mod/history/set/all/history.rb +34 -57
  42. data/mod/history/set/all/{act_view.rb → history/act_listing.rb} +0 -13
  43. data/mod/history/set/all/history/actions.rb +119 -0
  44. data/mod/history/set/all/history/acts.rb +12 -0
  45. data/mod/history/set/all/history/events.rb +94 -0
  46. data/mod/history/set/all/history/last.rb +97 -0
  47. data/mod/history/set/all/history/revision.rb +54 -0
  48. data/mod/history/set/all/history/selected.rb +64 -0
  49. data/mod/history/set/all/history/views.rb +34 -0
  50. data/mod/history/spec/set/all/history/views_spec.rb +29 -0
  51. data/mod/item/spec/set/all/bar_spec.rb +2 -2
  52. data/mod/machines/file/all_script_machine_output/file.js +66 -30621
  53. data/mod/machines/file/all_style_machine_output/file.css +2 -2
  54. data/mod/machines/file/script_html5shiv_printshiv_machine_output/file.js +1 -1
  55. data/mod/machines/lib/javascript/decko.js.coffee +1 -1
  56. data/mod/pointer/lib/javascript/script_pointer_config.js.coffee +1 -1
  57. data/mod/pointer/set/abstract/01_paging.rb +1 -0
  58. data/mod/pointer/set/abstract/02_pointer/html_views.rb +2 -2
  59. data/mod/pointer/set/abstract/02_pointer/html_views/checkbox_input.haml +2 -2
  60. data/mod/pointer/set/abstract/02_pointer/html_views/filter/filter_items.haml +1 -1
  61. data/mod/pointer/set/abstract/02_pointer/html_views/radio_input.haml +4 -4
  62. data/mod/pointer/set/abstract/02_pointer/options_api.rb +25 -1
  63. data/mod/pointer/set/abstract/02_pointer/other_views.rb +4 -0
  64. data/mod/pointer/spec/set/abstract/pointer/options_api_spec.rb +35 -0
  65. data/mod/search/set/abstract/search.rb +4 -114
  66. data/mod/search/set/abstract/search/views.rb +156 -0
  67. data/mod/search/set/abstract/wql_search.rb +10 -0
  68. data/mod/search/set/self/search.rb +3 -10
  69. data/mod/search/set/type/search_type.rb +5 -1
  70. data/mod/search/template/abstract/03_filter/filter_form.haml +1 -1
  71. data/mod/standard/set/all/error.rb +24 -192
  72. data/mod/standard/set/all/rich_html/content.rb +1 -1
  73. data/mod/standard/set/all/rich_html/error.rb +177 -0
  74. data/mod/standard/{template/all → set/all/rich_html}/error/not_found.haml +0 -0
  75. data/mod/standard/{template/all → set/all/rich_html}/error/server_error.haml +0 -0
  76. data/mod/standard/set/all/rich_html/form.rb +9 -9
  77. data/mod/standard/set/all/rich_html/menu.rb +14 -5
  78. data/mod/standard/spec/content/chunk/include_spec.rb +1 -2
  79. data/mod/standard/spec/set/type/search_type_spec.rb +1 -1
  80. data/mod/utility/set/abstract/bs_badge/bs_badge.haml +1 -1
  81. data/mod/utility/set/abstract/media.rb +3 -1
  82. metadata +20 -16
  83. data/lib/card/query/card_query/attribute_helper.rb +0 -74
  84. data/lib/card/query/card_query/special_attributes.rb +0 -49
  85. data/mod/history/set/all/action_view.rb +0 -52
  86. data/mod/history/set/all/actions.rb +0 -185
  87. data/mod/history/set/all/acts.rb +0 -16
  88. data/mod/history/set/all/content_history.rb +0 -180
  89. data/mod/history/spec/set/all/act_view_spec.rb +0 -16
  90. data/mod/history/spec/set/all/action_view_spec.rb +0 -10
  91. data/mod/history/spec/set/all/history_spec.rb +0 -11
@@ -1,10 +1,6 @@
1
1
  ACTS_PER_PAGE = Card.config.acts_per_page
2
2
 
3
3
  format :html do
4
- view :act, cache: :never do
5
- act_listing act_from_context
6
- end
7
-
8
4
  def act_from_context
9
5
  if (act_id = params["act_id"])
10
6
  Act.find(act_id) || raise(Card::NotFound, "act not found")
@@ -13,15 +9,6 @@ format :html do
13
9
  end
14
10
  end
15
11
 
16
- view :act_legend do
17
- bs_layout do
18
- row md: [12, 12], lg: [7, 5] do
19
- col action_legend
20
- col content_legend, class: "text-right"
21
- end
22
- end
23
- end
24
-
25
12
  # used (by history and recent)for rendering act lists with legend and paging
26
13
  #
27
14
  # @param acts [ActiveRecord::Relation] relation that will return acts objects
@@ -0,0 +1,119 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ def all_action_ids
4
+ Card::Action.where(card_id: id).pluck :id
5
+ end
6
+
7
+ def action_from_id action_id
8
+ return unless action_id.is_a?(Integer) || action_id =~ /^\d+$/
9
+ # if not an integer revision id is probably a mod (e.g. if you request
10
+ # files/:logo/standard.png)
11
+ action = Action.fetch action_id
12
+ return unless action.card_id == id
13
+ action
14
+ end
15
+
16
+ def old_actions
17
+ actions.where("id != ?", last_action_id)
18
+ end
19
+
20
+ def create_action
21
+ @create_action ||= actions.first
22
+ end
23
+
24
+ def nth_action index
25
+ index = index.to_i
26
+ return unless id && index.positive?
27
+ Action.where("draft is not true AND card_id = #{id}")
28
+ .order(:id).limit(1).offset(index - 1).first
29
+ end
30
+
31
+ def new_content_action_id
32
+ return unless @current_action && current_action_changes_content?
33
+ @current_action.id
34
+ end
35
+
36
+ def current_action_changes_content?
37
+ new_card? || @current_action.new_content? || db_content_is_changing?
38
+ end
39
+
40
+ format :html do
41
+ def action_from_context
42
+ if (action_id = voo.action_id || params[:action_id])
43
+ Action.fetch action_id
44
+ else
45
+ card.last_action
46
+ end
47
+ end
48
+
49
+ def action_content action, view_type
50
+ return "" unless action.present?
51
+ wrap do
52
+ [action_content_toggle(action, view_type),
53
+ content_diff(action, view_type)]
54
+ end
55
+ end
56
+
57
+ def content_diff action, view_type
58
+ diff = action.new_content? && content_changes(action, view_type)
59
+ return "<i>empty</i>" unless diff.present?
60
+ diff
61
+ end
62
+
63
+ def action_content_toggle action, view_type
64
+ return unless show_action_content_toggle?(action, view_type)
65
+ toggle_action_content_link action, view_type
66
+ end
67
+
68
+ def show_action_content_toggle? action, view_type
69
+ view_type == :expanded || action.summary_diff_omits_content?
70
+ end
71
+
72
+ def toggle_action_content_link action, view_type
73
+ other_view_type = view_type == :expanded ? :summary : :expanded
74
+ link_to_view "action_#{other_view_type}",
75
+ icon_tag(action_arrow_dir(view_type)),
76
+ class: "slotter revision-#{action.card_act_id} float-right",
77
+ path: { action_id: action.id, look_in_trash: true }
78
+ end
79
+
80
+ def action_arrow_dir view_type
81
+ view_type == :expanded ? :triangle_left : :triangle_right
82
+ end
83
+
84
+ def revert_actions_link act, link_text,
85
+ revert_to: :this, slot_selector: nil, html_args: {}
86
+ return unless card.ok? :update
87
+ html_args.merge! remote: true, method: :post, rel: "nofollow",
88
+ path: { action: :update, view: :open, look_in_trash: true,
89
+ revert_actions: act.actions.map(&:id),
90
+ revert_to: revert_to }
91
+
92
+ html_args[:path]["data-slot-selector"] = slot_selector if slot_selector
93
+ add_class html_args, "slotter"
94
+ link_to link_text, html_args
95
+ end
96
+
97
+ def action_legend
98
+ types = %i[create update delete]
99
+ legend = types.map do |action_type|
100
+ "#{action_icon(action_type)} #{action_type}d"
101
+ end
102
+ legend << _render_draft_legend if voo.show?(:draft_legend)
103
+ "<small>Actions: #{legend.join ' | '}</small>"
104
+ end
105
+
106
+ def content_legend
107
+ legend = [Card::Content::Diff.render_added_chunk("Additions"),
108
+ Card::Content::Diff.render_deleted_chunk("Subtractions")]
109
+ "<small>Content changes: #{legend.join ' | '}</small>"
110
+ end
111
+
112
+ def content_changes action, diff_type, hide_diff=false
113
+ if hide_diff
114
+ action.raw_view
115
+ else
116
+ action.content_diff diff_type
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,12 @@
1
+ def act_card?
2
+ self == Card::ActManager.act_card
3
+ end
4
+
5
+ # all acts with actions on self and on cards included in self (ie, acts shown in history)
6
+ def history_acts
7
+ @history_acts ||= Act.all_with_actions_on(history_card_ids, true).order id: :desc
8
+ end
9
+
10
+ def draft_acts
11
+ drafts.created_by(Card::Auth.current_id).map(&:act)
12
+ end
@@ -0,0 +1,94 @@
1
+
2
+ # must be called on all actions and before :set_name, :process_subcards and
3
+ # :validate_delete_children
4
+ event :assign_action, :initialize, when: :actionable? do
5
+ act = director.need_act
6
+ @current_action = Card::Action.create(
7
+ card_act_id: act.id,
8
+ action_type: @action,
9
+ draft: (Env.params["draft"] == "true")
10
+ )
11
+ if @supercard && @supercard != self
12
+ @current_action.super_action = @supercard.current_action
13
+ end
14
+ end
15
+
16
+ # can we store an action? (can be overridden, eg in files)
17
+ def actionable?
18
+ history?
19
+ end
20
+
21
+ event :detect_conflict, :validate, on: :update, when: :edit_conflict? do
22
+ errors.add :conflict, tr(:error_not_latest_revision)
23
+ end
24
+
25
+ def edit_conflict?
26
+ last_action_id_before_edit &&
27
+ last_action_id_before_edit.to_i != last_action_id &&
28
+ (la = last_action) &&
29
+ la.act.actor_id != Auth.current_id
30
+ end
31
+
32
+ # stores changes in the changes table and assigns them to the current action
33
+ # removes the action if there are no changes
34
+ event :finalize_action, :finalize, when: :finalize_action? do
35
+ if changed_fields.present?
36
+ @current_action.update_attributes! card_id: id
37
+
38
+ # Note: #last_change_on uses the id to sort by date
39
+ # so the changes for the create changes have to be created before the first change
40
+ store_card_changes_for_create_action if first_change?
41
+ store_card_changes if @current_action.action_type != :create
42
+ elsif @current_action.card_changes.reload.empty?
43
+ @current_action.delete
44
+ @current_action = nil
45
+ end
46
+ end
47
+
48
+ # changes for the create action are stored after the first update
49
+ def store_card_changes_for_create_action
50
+ store_each_history_field create_action.id do |field|
51
+ attribute_before_act field
52
+ end
53
+ end
54
+
55
+ def store_card_changes
56
+ store_each_history_field @current_action.id, changed_fields do |field|
57
+ self[field]
58
+ end
59
+ end
60
+
61
+ def store_each_history_field action_id, fields=nil
62
+ # FIXME: should be one bulk insert
63
+ fields ||= Card::Change::TRACKED_FIELDS
64
+ fields.each do |field|
65
+ Card::Change.create field: field,
66
+ value: yield(field),
67
+ card_action_id: action_id
68
+ end
69
+ end
70
+
71
+ def finalize_action?
72
+ actionable? && current_action
73
+ end
74
+
75
+ event :rollback_actions, :prepare_to_validate, on: :update, when: :rollback_request? do
76
+ update_args = process_revert_actions
77
+ Env.params["revert_actions"] = nil
78
+ update_attributes! update_args
79
+ clear_drafts
80
+ abort :success
81
+ end
82
+
83
+ event :finalize_act, after: :finalize_action, when: :act_card? do
84
+ Card::ActManager.act.update_attributes! card_id: id
85
+ end
86
+
87
+ event :remove_empty_act, :integrate_with_delay_final, when: :remove_empty_act? do
88
+ # Card::ActManager.act.delete
89
+ # Card::ActManager.act = nil
90
+ end
91
+
92
+ def remove_empty_act?
93
+ act_card? && ActManager.act&.ar_actions&.reload&.empty?
94
+ end
@@ -0,0 +1,97 @@
1
+
2
+ def acted_at
3
+ last_act.acted_at
4
+ end
5
+
6
+ def revised_at
7
+ (last_action && (act = last_action.act) && act.acted_at) || Time.zone.now
8
+ end
9
+
10
+ def last_change_on field, opts={}
11
+ action_id = extract_action_id(opts[:before] || opts[:not_after])
12
+
13
+ # If there is only one action then there are no entries in the changes table,
14
+ # so we can't do a sql search but the changes are accessible via the action.
15
+ if no_last_change? action_id, opts[:before]
16
+ nil
17
+ elsif create_action_last_change? action_id
18
+ create_action.change field
19
+ else
20
+ last_change_from_action_id action_id, field, opts
21
+ end
22
+ end
23
+
24
+ def no_last_change? action_id, before
25
+ before && action_id == create_action.id
26
+ end
27
+
28
+ def create_action_last_change? action_id
29
+ action_id == create_action.id || (!action_id && create_action.sole?)
30
+ end
31
+
32
+ def last_change_from_action_id action_id, field, opts
33
+ Change.joins(:action).where(
34
+ last_change_sql_conditions(opts),
35
+ card_id: id,
36
+ action_id: action_id,
37
+ field: Card::Change.field_index(field)
38
+ ).order(:id).last
39
+ end
40
+
41
+ def last_change_sql_conditions opts
42
+ cond = "card_actions.card_id = :card_id AND field = :field"
43
+ cond += " AND (draft is not true)" unless opts[:including_drafts]
44
+ operator = "<" if opts[:before]
45
+ operator = "<=" if opts[:not_after]
46
+ cond += " AND card_action_id #{operator} :action_id" if operator
47
+ cond
48
+ end
49
+
50
+ def last_action_id
51
+ last_action&.id
52
+ end
53
+
54
+ def last_action
55
+ actions.where("id IS NOT NULL").last
56
+ end
57
+
58
+ def last_content_action
59
+ last_change_on(:db_content)&.action
60
+ end
61
+
62
+ def last_content_action_id
63
+ last_change_on(:db_content)&.card_action_id
64
+ end
65
+
66
+ def last_actor
67
+ last_act.actor
68
+ end
69
+
70
+ def last_act
71
+ @last_act ||=
72
+ if (action = last_action)
73
+ last_act_on_self = acts.last
74
+ act_of_last_action = action.act
75
+ return act_of_last_action unless last_act_on_self
76
+ return last_act_on_self unless act_of_last_action
77
+
78
+ return last_act_on_self if act_of_last_action == last_act_on_self
79
+ if last_act_on_self.acted_at > act_of_last_action.acted_at
80
+ last_act_on_self
81
+ else
82
+ act_of_last_action
83
+ end
84
+ end
85
+ end
86
+
87
+ def previous_action action_id
88
+ return unless action_id
89
+ action_index = actions.find_index { |a| a.id == action_id }
90
+ all_actions[action_index - 1] if action_index.to_i.nonzero?
91
+ end
92
+
93
+ private
94
+
95
+ def extract_action_id action_arg
96
+ action_arg.is_a?(Card::Action) ? action_arg.id : action_arg
97
+ end
@@ -0,0 +1,54 @@
1
+ def revision action, before_action=false
2
+ # a "revision" refers to the state of all tracked fields
3
+ # at the time of a given action
4
+ action = Card::Action.fetch(action) if action.is_a? Integer
5
+ return unless action
6
+ if before_action
7
+ revision_before_action action
8
+ else
9
+ revision_attributes action
10
+ end
11
+ end
12
+
13
+ def revision_attributes action
14
+ Card::Change::TRACKED_FIELDS.each_with_object({}) do |field, attr_changes|
15
+ last_change = action.change(field) || last_change_on(field, not_after: action)
16
+ attr_changes[field.to_sym] = (last_change ? last_change.value : self[field])
17
+ end
18
+ end
19
+
20
+ def revision_before_action action
21
+ if (prev_action = action.previous_action)
22
+ revision prev_action
23
+ else
24
+ { trash: true }
25
+ end
26
+ end
27
+
28
+ def rollback_request?
29
+ history? && actions_to_revert.any?
30
+ end
31
+
32
+ def process_revert_actions
33
+ update_args = { subcards: {} }
34
+ reverting_to_previous = Env.params["revert_to"] == "previous"
35
+ actions_to_revert.each do |action|
36
+ merge_revert_action! action, update_args, reverting_to_previous
37
+ end
38
+ update_args
39
+ end
40
+
41
+ def actions_to_revert
42
+ Array.wrap(Env.params["revert_actions"]).map do |a_id|
43
+ Action.fetch(a_id) || nil
44
+ end.compact
45
+ end
46
+
47
+ def merge_revert_action! action, update_args, reverting_to_previous
48
+ rev = action.card.revision(action, reverting_to_previous)
49
+ if action.card_id == id
50
+ update_args.merge! rev
51
+ else
52
+ update_args[:subcards][action.card.name] = rev
53
+ end
54
+ end
@@ -0,0 +1,64 @@
1
+
2
+ # if these aren't in a nested module, the methods just overwrite the base
3
+ # methods, but we need a distinct module so that super will be able to refer to
4
+ # the base methods.
5
+ def content
6
+ @selected_action_id ? selected_content : super
7
+ end
8
+
9
+ def content= value
10
+ @selected_content = nil
11
+ super
12
+ end
13
+
14
+ def select_action_by_params params
15
+ action = nth_action(params[:rev]) || action_from_id(params[:rev_id])
16
+ return unless action
17
+ select_action action.id
18
+ end
19
+
20
+ def select_action action_id
21
+ run_callbacks :select_action do
22
+ self.selected_action_id = action_id
23
+ end
24
+ end
25
+
26
+ def selected_action_id
27
+ @selected_action_id || (@current_action&.id) || last_action_id
28
+ end
29
+
30
+ def selected_action_id= action_id
31
+ @selected_content = nil
32
+ @selected_action_id = action_id
33
+ end
34
+
35
+ def selected_action
36
+ selected_action_id && Action.fetch(selected_action_id)
37
+ end
38
+
39
+ def selected_content
40
+ @selected_content ||= content_at_time_of_selected_action || db_content
41
+ end
42
+
43
+ def content_at_time_of_selected_action
44
+ lc = last_change_on(:db_content, not_after: @selected_action_id, including_drafts: true)
45
+ lc&.value
46
+ end
47
+
48
+ def with_selected_action_id action_id
49
+ current_action_id = @selected_action_id
50
+ select_action_id action_id
51
+ result = yield
52
+ select_action_id current_action_id
53
+ result
54
+ end
55
+
56
+ def select_action_id action_id
57
+ run_callbacks :select_action do
58
+ self.selected_action_id = action_id
59
+ end
60
+ end
61
+
62
+ def selected_content_action_id
63
+ @selected_action_id || new_content_action_id || last_content_action_id
64
+ end