2019-05-02 17:17:27 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2014-08-04 04:07:55 -05:00
|
|
|
require 'ipaddr'
|
|
|
|
|
|
|
|
# awkward TopicView is taken
|
|
|
|
class TopicViewItem < ActiveRecord::Base
|
|
|
|
self.table_name = 'topic_views'
|
|
|
|
belongs_to :user
|
2020-04-07 16:32:18 -05:00
|
|
|
belongs_to :topic
|
2014-08-04 04:07:55 -05:00
|
|
|
validates_presence_of :topic_id, :ip_address, :viewed_at
|
|
|
|
|
2017-07-27 20:20:09 -05:00
|
|
|
def self.add(topic_id, ip, user_id = nil, at = nil, skip_redis = false)
|
2018-05-21 13:38:29 -05:00
|
|
|
# Only store a view once per day per thing per (user || ip)
|
2015-09-13 22:17:28 -05:00
|
|
|
at ||= Date.today
|
2019-05-02 17:17:27 -05:00
|
|
|
redis_key = +"view:#{topic_id}:#{at}"
|
2014-08-04 04:07:55 -05:00
|
|
|
if user_id
|
|
|
|
redis_key << ":user-#{user_id}"
|
|
|
|
else
|
|
|
|
redis_key << ":ip-#{ip}"
|
|
|
|
end
|
|
|
|
|
2019-12-03 03:05:53 -06:00
|
|
|
if skip_redis || Discourse.redis.setnx(redis_key, "1")
|
|
|
|
skip_redis || Discourse.redis.expire(redis_key, SiteSetting.topic_view_duration_hours.hours)
|
2014-08-04 04:07:55 -05:00
|
|
|
|
|
|
|
TopicViewItem.transaction do
|
2014-08-06 22:14:39 -05:00
|
|
|
# this is called real frequently, working hard to avoid exceptions
|
|
|
|
sql = "INSERT INTO topic_views (topic_id, ip_address, viewed_at, user_id)
|
|
|
|
SELECT :topic_id, :ip_address, :viewed_at, :user_id
|
|
|
|
WHERE NOT EXISTS (
|
|
|
|
SELECT 1 FROM topic_views
|
|
|
|
/*where*/
|
|
|
|
)"
|
|
|
|
|
2018-06-20 02:48:02 -05:00
|
|
|
builder = DB.build(sql)
|
2014-08-06 22:14:39 -05:00
|
|
|
|
|
|
|
if !user_id
|
2015-05-14 02:21:02 -05:00
|
|
|
builder.where("ip_address = :ip_address AND topic_id = :topic_id AND user_id IS NULL")
|
2014-08-06 22:14:39 -05:00
|
|
|
else
|
|
|
|
builder.where("user_id = :user_id AND topic_id = :topic_id")
|
2018-05-21 13:38:29 -05:00
|
|
|
ip = nil # do not store IP of logged in users
|
2014-08-06 22:14:39 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
result = builder.exec(topic_id: topic_id, ip_address: ip, viewed_at: at, user_id: user_id)
|
|
|
|
|
2015-03-04 22:25:05 -06:00
|
|
|
Topic.where(id: topic_id).update_all 'views = views + 1'
|
|
|
|
|
2018-06-20 02:48:02 -05:00
|
|
|
if result > 0
|
2014-08-06 23:20:42 -05:00
|
|
|
UserStat.where(user_id: user_id).update_all 'topics_entered = topics_entered + 1' if user_id
|
2014-08-06 22:14:39 -05:00
|
|
|
end
|
2014-08-04 04:07:55 -05:00
|
|
|
|
|
|
|
# Update the views count in the parent, if it exists.
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: topic_views
|
|
|
|
#
|
|
|
|
# topic_id :integer not null
|
|
|
|
# viewed_at :date not null
|
|
|
|
# user_id :integer
|
2018-05-21 13:36:06 -05:00
|
|
|
# ip_address :inet
|
2014-08-04 04:07:55 -05:00
|
|
|
#
|
|
|
|
# Indexes
|
|
|
|
#
|
|
|
|
# index_topic_views_on_topic_id_and_viewed_at (topic_id,viewed_at)
|
2017-03-22 01:26:53 -05:00
|
|
|
# index_topic_views_on_user_id_and_viewed_at (user_id,viewed_at)
|
2014-08-04 04:07:55 -05:00
|
|
|
# index_topic_views_on_viewed_at_and_topic_id (viewed_at,topic_id)
|
2018-05-21 13:36:06 -05:00
|
|
|
# uniq_ip_or_user_id_topic_views (user_id,ip_address,topic_id) UNIQUE
|
2014-08-04 04:07:55 -05:00
|
|
|
#
|