2013-02-05 14:16:51 -05:00
require_dependency 'discourse'
require 'ipaddr'
2015-02-22 20:47:18 +01:00
require 'url_helper'
2013-02-05 14:16:51 -05:00
class TopicLinkClick < ActiveRecord :: Base
belongs_to :topic_link , counter_cache : :clicks
belongs_to :user
validates_presence_of :topic_link_id
2013-06-24 18:30:32 -04:00
validates_presence_of :ip_address
2013-02-05 14:16:51 -05:00
2015-04-01 22:59:25 +02:00
WHITELISTED_REDIRECT_HOSTNAMES = Set . new ( %W{ www.youtube.com youtu.be } )
2013-02-05 14:16:51 -05:00
# Create a click from a URL and post_id
def self . create_from ( args = { } )
2015-09-25 14:07:04 -04:00
url = args [ :url ] [ 0 ... TopicLink . max_url_length ]
2015-02-22 20:47:18 +01:00
return nil if url . blank?
uri = URI . parse ( url ) rescue nil
2013-02-07 16:45:24 +01:00
2015-02-22 20:47:18 +01:00
urls = Set . new
urls << url
if url =~ / ^http /
urls << url . sub ( / ^https / , 'http' )
urls << url . sub ( / ^http: / , 'https:' )
2015-06-12 12:02:36 +02:00
urls << UrlHelper . schemaless ( url )
2014-01-14 14:59:51 -05:00
end
2015-06-12 12:02:36 +02:00
urls << UrlHelper . absolute_without_cdn ( url )
2015-02-22 20:47:18 +01:00
urls << uri . path if uri . try ( :host ) == Discourse . current_hostname
urls << url . sub ( / \ ?.*$ / , '' ) if url . include? ( '?' )
2015-08-05 12:15:08 +10:00
# add a cdn link
2016-06-28 15:52:38 -04:00
if uri
if Discourse . asset_host . present?
cdn_uri = URI . parse ( Discourse . asset_host ) rescue nil
if cdn_uri && cdn_uri . hostname == uri . hostname && uri . path . starts_with? ( cdn_uri . path )
is_cdn_link = true
2016-06-30 16:55:01 +02:00
urls << uri . path [ cdn_uri . path . length .. - 1 ]
2016-06-28 15:52:38 -04:00
end
end
if SiteSetting . s3_cdn_url . present?
cdn_uri = URI . parse ( SiteSetting . s3_cdn_url ) rescue nil
if cdn_uri && cdn_uri . hostname == uri . hostname && uri . path . starts_with? ( cdn_uri . path )
is_cdn_link = true
2016-06-30 16:55:01 +02:00
path = uri . path [ cdn_uri . path . length .. - 1 ]
2016-06-28 15:52:38 -04:00
urls << path
urls << " #{ Discourse . store . absolute_base_url } #{ path } "
end
2015-08-05 12:15:08 +10:00
end
end
2015-02-22 20:47:18 +01:00
link = TopicLink . select ( [ :id , :user_id ] )
# test for all possible URLs
link = link . where ( Array . new ( urls . count , " url = ? " ) . join ( " OR " ) , * urls )
2014-01-14 14:59:51 -05:00
2013-02-05 14:16:51 -05:00
# Find the forum topic link
link = link . where ( post_id : args [ :post_id ] ) if args [ :post_id ] . present?
# If we don't have a post, just find the first occurance of the link
link = link . where ( topic_id : args [ :topic_id ] ) if args [ :topic_id ] . present?
link = link . first
2015-02-22 20:47:18 +01:00
# If no link is found...
2013-07-27 13:18:37 -04:00
unless link . present?
2015-02-22 20:47:18 +01:00
# ... return the url for relative links or when using the same host
2016-06-30 16:55:01 +02:00
return url if url =~ / ^ \/ [^ \/ ] / || uri . try ( :host ) == Discourse . current_hostname
2014-11-20 14:01:48 -05:00
2015-02-22 20:47:18 +01:00
# If we have it somewhere else on the site, just allow the redirect.
# This is likely due to a onebox of another topic.
link = TopicLink . find_by ( url : url )
2015-04-01 22:59:25 +02:00
return link . url if link . present?
2015-05-06 11:22:53 +10:00
return nil unless uri
2015-04-01 22:59:25 +02:00
# Only redirect to whitelisted hostnames
2015-08-05 12:15:08 +10:00
return url if WHITELISTED_REDIRECT_HOSTNAMES . include? ( uri . hostname ) || is_cdn_link
2015-08-05 11:49:11 +10:00
return nil
2013-07-27 13:18:37 -04:00
end
2015-02-22 20:47:18 +01:00
return url if args [ :user_id ] && link . user_id == args [ :user_id ]
2013-07-26 17:29:43 -04:00
2013-02-05 14:16:51 -05:00
# Rate limit the click counts to once in 24 hours
rate_key = " link-clicks: #{ link . id } : #{ args [ :user_id ] || args [ :ip ] } "
if $redis . setnx ( rate_key , " 1 " )
$redis . expire ( rate_key , 1 . day . to_i )
2013-06-24 18:30:32 -04:00
create! ( topic_link_id : link . id , user_id : args [ :user_id ] , ip_address : args [ :ip ] )
2013-02-05 14:16:51 -05:00
end
2015-02-22 20:47:18 +01:00
url
2013-02-05 14:16:51 -05:00
end
end
2013-05-24 12:48:32 +10:00
# == Schema Information
#
# Table name: topic_link_clicks
#
# id :integer not null, primary key
# topic_link_id :integer not null
# user_id :integer
2014-08-27 15:19:25 +10:00
# created_at :datetime not null
# updated_at :datetime not null
2013-12-05 17:40:35 +11:00
# ip_address :inet not null
2013-05-24 12:48:32 +10:00
#
# Indexes
#
2014-05-28 11:49:50 +10:00
# by_link (topic_link_id)
2013-05-24 12:48:32 +10:00
#