-
Notifications
You must be signed in to change notification settings - Fork 729
/
can_be_published.rb
156 lines (114 loc) · 4.13 KB
/
can_be_published.rb
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
module CanBePublished
extend ActiveSupport::Concern
def can_be_published_aasm
@can_be_published_aasm ||= StateMachine.new(self)
end
def visible?
can_be_published_aasm.published?
end
def visible_internally?
can_be_published_aasm.internal? || visible?
end
class_methods do
def inverse_relation_name(scope_name)
"can_be_published_#{scope_name}_#{model_name.plural}"
end
end
included do
validate :archived_after_internal
validate :archived_after_published
validate :published_after_internal
before_save :update_user_references
after_save :schedule_touch
after_save :update_active_publicly
after_destroy :update_active_publicly
after_touch :update_active_publicly
%i[archived published internal].each do |scope_name|
local = "#{scope_name}_by".to_sym
remote = inverse_relation_name(scope_name).to_sym
belongs_to local, class_name: 'User', inverse_of: remote, optional: true
User.has_many remote, class_name: model_name, inverse_of: local, foreign_key: "#{local}_id"
User.association_attributes_ignored remote
end
scope :published, lambda {
timestamp = Time.zone.now
date_earlier(:published_at, timestamp).date_later_or_nil(:archived_at, timestamp)
}
scope :archived, lambda {
timestamp = Time.zone.now
date_earlier(:archived_at, timestamp)
}
scope :only_internal, lambda {
timestamp = Time.zone.now
date_earlier(:internal_at, timestamp)
.date_later_or_nil(:archived_at, timestamp)
.date_later_or_nil(:published_at, timestamp)
}
scope :internal, lambda {
timestamp = Time.zone.now
internal = arel_table[:internal_at].lt(timestamp)
published = arel_table[:published_at].lt(timestamp)
where(internal.or(published))
.date_later_or_nil(:archived_at, timestamp)
}
scope :date_earlier, lambda { |field, timestamp|
where arel_table[field].lt(timestamp)
}
scope :date_later_or_nil, lambda { |field, timestamp|
where arel_table[field].gt(timestamp).or(arel_table[field].eq(nil))
}
scope :check_published_unless_editor, lambda { |user|
return if user&.permissions? 'knowledge_base.editor'
published
}
scope :check_internal_unless_editor, lambda { |user|
return if user&.permissions? 'knowledge_base.editor'
return internal if user&.permissions? 'knowledge_base.reader'
published
}
end
def update_user_references
return if can_be_published_aasm.aasm.current_event.present? # state machine is handling it
%i[archived internal published].each do |scope_name|
update_user_reference_item(scope_name)
end
end
def update_user_reference_item(scope_name)
return if !send("#{scope_name}_at_changed?")
send("#{scope_name}_by_id=", UserInfo.current_user_id)
end
def archived_after_internal
return if internal_at.nil? || archived_at.nil? || archived_at >= internal_at
errors.add(:archived_at, 'date must be no earlier than internal at date')
end
def archived_after_published
return if published_at.nil? || archived_at.nil? || archived_at >= published_at
errors.add(:archived_at, 'date must be no earlier than published at date')
end
def published_after_internal
return if published_at.nil? || internal_at.nil? || published_at >= internal_at
errors.add(:published_at, 'date must be no earlier than internal at date')
end
def schedule_touch_for(attr)
date = saved_changes[attr]&.last
return if date.nil? || date <= Time.zone.now
ScheduledTouchJob.touch_at(self, date)
end
def schedule_touch
%i[published_at archived_at].each { |attr| schedule_touch_for(attr) }
end
def update_active_publicly
CanBePublished.update_active_publicly!
end
def self.update_active_publicly!
Setting.set('kb_active_publicly', active_publicly?)
end
def self.active_publicly?
KnowledgeBase::Answer
.published
.joins(category: :knowledge_base)
.where(knowledge_bases: { active: true })
.exists?
end
end