Class: TagUser

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/tag_user.rb

Class Method Summary collapse

Class Method Details

.auto_track(opts) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'app/models/tag_user.rb', line 186

def self.auto_track(opts)
  builder = DB.build <<~SQL
    UPDATE topic_users
    SET notification_level = :tracking, notifications_reason_id = :auto_track_tag
    FROM (
        SELECT DISTINCT tu.topic_id, tu.user_id
        FROM topic_users tu
        JOIN topic_tags ON tu.topic_id = topic_tags.topic_id
        JOIN tag_users ON tag_users.user_id = tu.user_id
                            AND topic_tags.tag_id = tag_users.tag_id
                            AND tag_users.notification_level = :tracking
        /*where*/
    ) as X
    WHERE
      topic_users.notification_level = :regular AND
      topic_users.topic_id = X.topic_id AND
      topic_users.user_id = X.user_id
  SQL

  if topic_id = opts[:topic_id]
    builder.where("tu.topic_id = :topic_id", topic_id: topic_id)
  end

  if user_id = opts[:user_id]
    builder.where("tu.user_id = :user_id", user_id: user_id)
  end

  builder.exec(
    tracking: notification_levels[:tracking],
    regular: notification_levels[:regular],
    auto_track_tag: TopicUser.notification_reasons[:auto_track_tag],
  )
end

.auto_watch(opts) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'app/models/tag_user.rb', line 133

def self.auto_watch(opts)
  builder = DB.build <<~SQL
    UPDATE topic_users
    SET notification_level = CASE WHEN should_watch THEN :watching ELSE :tracking END,
        notifications_reason_id = CASE WHEN should_watch THEN :auto_watch_tag ELSE NULL END
    FROM
    (
    SELECT tu.topic_id, tu.user_id, CASE
        WHEN MAX(tag_users.notification_level) = :watching THEN true
        ELSE false
        END
      should_watch,

        CASE WHEN MAX(tag_users.notification_level) IS NULL AND
          tu.notification_level = :watching AND
          tu.notifications_reason_id = :auto_watch_tag
        THEN true
        ELSE false
        END
      should_track

    FROM topic_users tu
    LEFT JOIN topic_tags ON tu.topic_id = topic_tags.topic_id
    LEFT JOIN tag_users ON tag_users.user_id = tu.user_id
                        AND topic_tags.tag_id = tag_users.tag_id
                        AND tag_users.notification_level = :watching
    /*where*/
    GROUP BY tu.topic_id, tu.user_id, tu.notification_level, tu.notifications_reason_id
    ) AS X
    WHERE X.topic_id = topic_users.topic_id AND
          X.user_id = topic_users.user_id AND
          (should_track OR should_watch)

  SQL

  builder.where("tu.notification_level in (:tracking, :regular, :watching)")

  if topic_id = opts[:topic_id]
    builder.where("tu.topic_id = :topic_id", topic_id: topic_id)
  end

  if user_id = opts[:user_id]
    builder.where("tu.user_id = :user_id", user_id: user_id)
  end

  builder.exec(
    watching: notification_levels[:watching],
    tracking: notification_levels[:tracking],
    regular: notification_levels[:regular],
    auto_watch_tag: TopicUser.notification_reasons[:auto_watch_tag],
  )
end

.batch_set(user, level, tags) ⇒ Object



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
# File 'app/models/tag_user.rb', line 37

def self.batch_set(user, level, tags)
  tags ||= []
  changed = false

  records = TagUser.where(user: user, notification_level: notification_levels[level])
  old_ids = records.pluck(:tag_id)

  tag_ids =
    if tags.empty?
      []
    elsif tags.first&.is_a?(String)
      Tag.where_name(tags).pluck(:id)
    else
      tags
    end

  Tag
    .where(id: tag_ids)
    .joins(:target_tag)
    .each { |tag| tag_ids[tag_ids.index(tag.id)] = tag.target_tag_id }

  tag_ids.uniq!

  if tag_ids.present? &&
       TagUser
         .where(user_id: user.id, tag_id: tag_ids)
         .where.not(notification_level: notification_levels[level])
         .update_all(notification_level: notification_levels[level]) > 0
    changed = true
  end

  remove = (old_ids - tag_ids)
  if remove.present?
    records.where("tag_id in (?)", remove).destroy_all
    changed = true
  end

  now = Time.zone.now

  new_records_attrs =
    (tag_ids - old_ids).map do |tag_id|
      {
        user_id: user.id,
        tag_id: tag_id,
        notification_level: notification_levels[level],
        created_at: now,
        updated_at: now,
      }
    end

  unless new_records_attrs.empty?
    result = TagUser.insert_all(new_records_attrs)
    changed = true if result.rows.length > 0
  end

  if changed
    auto_watch(user_id: user.id)
    auto_track(user_id: user.id)
  end

  changed
end

.change(user_id, tag_id, level) ⇒ Object



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
# File 'app/models/tag_user.rb', line 100

def self.change(user_id, tag_id, level)
  if tag_id.is_a?(::Tag)
    tag = tag_id
    tag_id = tag.id
  else
    tag = Tag.find_by_id(tag_id)
  end

  tag_id = tag.target_tag_id if tag.synonym?

  user_id = user_id.id if user_id.is_a?(::User)

  tag_id = tag_id.to_i
  user_id = user_id.to_i

  tag_user = TagUser.where(user_id: user_id, tag_id: tag_id).first

  if tag_user
    return tag_user if tag_user.notification_level == level
    tag_user.notification_level = level
    tag_user.save
  else
    tag_user = TagUser.create(user_id: user_id, tag_id: tag_id, notification_level: level)
  end

  auto_watch(user_id: user_id)
  auto_track(user_id: user_id)

  tag_user
rescue ActiveRecord::RecordNotUnique
  # In case of a race condition to insert, do nothing
end

.lookup(user, level) ⇒ Object



33
34
35
# File 'app/models/tag_user.rb', line 33

def self.lookup(user, level)
  where(user: user, notification_level: notification_levels[level])
end

.notification_levelsObject



29
30
31
# File 'app/models/tag_user.rb', line 29

def self.notification_levels
  NotificationLevels.all
end

.notification_levels_for(user) ⇒ Object



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'app/models/tag_user.rb', line 220

def self.notification_levels_for(user)
  # Anonymous users have all default tags set to regular tracking,
  # except for default muted tags which stay muted.
  if user.blank?
    notification_levels =
      [
        SiteSetting.default_tags_watching_first_post.split("|"),
        SiteSetting.default_tags_watching.split("|"),
        SiteSetting.default_tags_tracking.split("|"),
      ].flatten.map { |name| [name, self.notification_levels[:regular]] }

    notification_levels +=
      SiteSetting
        .default_tags_muted
        .split("|")
        .map { |name| [name, self.notification_levels[:muted]] }
  else
    notification_levels =
      TagUser
        .notification_level_visible
        .where(user: user)
        .joins(:tag)
        .pluck("tags.name", :notification_level)
  end

  Hash[*notification_levels.flatten]
end