first_click_free 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +97 -0
- data/Rakefile +30 -0
- data/config/domains.yml +195 -0
- data/lib/first_click_free.rb +42 -0
- data/lib/first_click_free/concerns/controller.rb +108 -0
- data/lib/first_click_free/exceptions/subsequent_access_exception.rb +6 -0
- data/lib/first_click_free/helpers/google.rb +41 -0
- data/lib/first_click_free/helpers/path.rb +22 -0
- data/lib/first_click_free/helpers/referrer.rb +26 -0
- data/lib/first_click_free/version.rb +3 -0
- data/lib/tasks/first_click_free_tasks.rake +24 -0
- data/spec/concerns/controller_spec.rb +128 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +23 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +16 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +18 -0
- data/spec/dummy/log/test.log +548 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/exceptions/subsequent_access_exception_spec.rb +5 -0
- data/spec/first_click_free_spec.rb +46 -0
- data/spec/helpers/google_spec.rb +104 -0
- data/spec/helpers/path_spec.rb +35 -0
- data/spec/helpers/referrer_spec.rb +39 -0
- data/spec/spec_helper.rb +18 -0
- metadata +185 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 77ff2ae4a9b5357d67a37ed73451b4c62d9dec19
|
4
|
+
data.tar.gz: e5e39506a08daf5c744fa21cb6e0ccd5a9aa7f3e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d2788937dec98a853231e51023d0e5df183041f19efc4b35d45fe1fb1de5358ffd570943cd34579d62884b6df95cb6e0811607f698968cd0e16387455e3d199c
|
7
|
+
data.tar.gz: 1cb34f11618f073a0ebae026a2df2f06403f09b42d22b6076255bcc3c15b9c55a017d40716c4514ec94ee10e9886177f7359b1c8a2c1f0f7525b0ce1883a664c
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
First Click Free
|
2
|
+
===
|
3
|
+
|
4
|
+
[![Build Status](https://travis-ci.org/3months/first_click_free.svg)](https://travis-ci.org/3months/first_click_free)
|
5
|
+
|
6
|
+
[First Click Free](https://support.google.com/webmasters/answer/74536?hl=en) is one of three methods recommended officially by Google for improving search rankings for subscription, paywall and other restricted access sites.
|
7
|
+
|
8
|
+
The technique involves making available the first n 'clicks', or pageviews for each user, and giving Google's crawling bots full access to index site content. This way, users coming from social media sites and search results are able to 'preview' the content they have been looking for, and search engines are able to fully index a site, even though it would normally require registration and/or payment.
|
9
|
+
|
10
|
+
This gem aims to simplify and centralize the process of adding first click free support to a Rails application. It's fully tested, and used in production with many of our clients at [3months.com](https://3months.com).
|
11
|
+
|
12
|
+
Use
|
13
|
+
---
|
14
|
+
|
15
|
+
**Rails is required to use this gem**
|
16
|
+
|
17
|
+
1. Install: Add `gem 'first_click_free'` to your `Gemfile` and run `bundle install`
|
18
|
+
2. For any controller that should have first click free activated, simply call `allow_first_click_free` in your controller definition, for example:
|
19
|
+
``` ruby
|
20
|
+
class PagesController
|
21
|
+
allow_first_click_free
|
22
|
+
end
|
23
|
+
```
|
24
|
+
You may pass through `only`, or `except` to restrict which actions will have first click free turned on, or you can put this in your `ApplicationController` to turn on first click free for all controllers.
|
25
|
+
3. Handle the exception that is raised when a user tries to visit more than one page without being signed in:
|
26
|
+
``` ruby
|
27
|
+
rescue_from FirstClickFree::Exceptions::SubsequentAccessException do
|
28
|
+
redirect_to root_path, alert: 'Please sign in to continue.'
|
29
|
+
end
|
30
|
+
```
|
31
|
+
4. Good to go!
|
32
|
+
|
33
|
+
Optional use
|
34
|
+
---
|
35
|
+
|
36
|
+
1. You may also permit certain individual paths to bypass first click free by setting them in an initializer like so
|
37
|
+
`FirstClickFree.permitted_paths = [ '/about', '/contact' ]`. These paths do not set or reset the users' first click free status.
|
38
|
+
2. By default users will get just 1 free click, however by setting `FirstClickFree.free_clicks` in an initializer you can allow n free clicks to content.
|
39
|
+
3. A count of users' free clicks are available in request.env["first_click_free_count"].
|
40
|
+
|
41
|
+
#### Registered Users
|
42
|
+
|
43
|
+
If you have registered users that should always be allowed through (they shouldn't be affected by any first click free rules), then you can override the `user_for_first_click_free` method in `ApplicationController`, or any of your controllers using `allow_first_click_free`. This method should return either a falsy value if no-one is signed in, or the current user.
|
44
|
+
|
45
|
+
Example:
|
46
|
+
|
47
|
+
``` ruby
|
48
|
+
class ApplicationController
|
49
|
+
# …snip
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def user_for_first_click_free
|
54
|
+
current_member
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
How it works
|
62
|
+
---
|
63
|
+
|
64
|
+
##### For visitors
|
65
|
+
|
66
|
+
* When a user first lands in a controller marked as being first click free, a session variable is set.
|
67
|
+
* If that same user attempts to access any other URL marked as first click free, an exception is raised so that the application can redirect or display a message to that user.
|
68
|
+
|
69
|
+
##### For visitors coming from a Google, Bing, or Yahoo search
|
70
|
+
|
71
|
+
* When a user's HTTP referrer matches a list of known search engine domains, the request is allowed to override any previously set first click free.
|
72
|
+
* It does not disable first click free, it just modifies which page that user may access.
|
73
|
+
* For example, if a user searches for a page on your site using Google, and clicks on the first result, that page will be marked as first click free for them - any subsequent clicks from that page will trigger the first click free error. If they go back to the search results though, and then click on the second result, that page will take the place of the first and they will be able to access that page as normal.
|
74
|
+
|
75
|
+
|
76
|
+
##### For Google's indexing services
|
77
|
+
|
78
|
+
* If the requesting agent is recognized as a 'Googlebot', the request is allowed though as if they were a registered user, so that the content may be indexed.
|
79
|
+
* Googlebot recognition is based on two factors:
|
80
|
+
* User agent: Google's indexers request a page with a user agent string of 'Googlebot' - this is used as the first-level of checking to make sure the page should be displayed. A user-agent string can be spoofed though, so the second check is:
|
81
|
+
* DNS: A reverse DNS request is issued against the remote IP, to ensure that the hostname returned matches a 'googlebot.com' domain. A forward DNS request is then issued against the hostname, to ensure that it matches back up with the original IP address.
|
82
|
+
|
83
|
+
Contributing
|
84
|
+
---
|
85
|
+
|
86
|
+
* Contributions are welcome!
|
87
|
+
* Please fork this repository, and run `bundle install` to install the development dependencies (RSpec and SQLite).
|
88
|
+
* Create a new git branch to contain your changes. Try and limit commits to this branch to the specific changes you want to be merged in.
|
89
|
+
* Push up your branch to Github, and create a pull request. Please don't change the gem version or anything, I can do that bit.
|
90
|
+
* All pull requests will be reviewed ASAP. If it's not ready for merge, I'll help you to get it to a stage where it is!
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
License
|
95
|
+
---
|
96
|
+
|
97
|
+
This project rocks and uses MIT-LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'FirstClickFree'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
load 'tasks/first_click_free_tasks.rake'
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
require 'rspec/core'
|
25
|
+
require 'rspec/core/rake_task'
|
26
|
+
|
27
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
28
|
+
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
|
29
|
+
|
30
|
+
task :default => :spec
|
data/config/domains.yml
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
---
|
2
|
+
- .google.com
|
3
|
+
- .google.ad
|
4
|
+
- .google.ae
|
5
|
+
- .google.com.af
|
6
|
+
- .google.com.ag
|
7
|
+
- .google.com.ai
|
8
|
+
- .google.al
|
9
|
+
- .google.am
|
10
|
+
- .google.co.ao
|
11
|
+
- .google.com.ar
|
12
|
+
- .google.as
|
13
|
+
- .google.at
|
14
|
+
- .google.com.au
|
15
|
+
- .google.az
|
16
|
+
- .google.ba
|
17
|
+
- .google.com.bd
|
18
|
+
- .google.be
|
19
|
+
- .google.bf
|
20
|
+
- .google.bg
|
21
|
+
- .google.com.bh
|
22
|
+
- .google.bi
|
23
|
+
- .google.bj
|
24
|
+
- .google.com.bn
|
25
|
+
- .google.com.bo
|
26
|
+
- .google.com.br
|
27
|
+
- .google.bs
|
28
|
+
- .google.bt
|
29
|
+
- .google.co.bw
|
30
|
+
- .google.by
|
31
|
+
- .google.com.bz
|
32
|
+
- .google.ca
|
33
|
+
- .google.cd
|
34
|
+
- .google.cf
|
35
|
+
- .google.cg
|
36
|
+
- .google.ch
|
37
|
+
- .google.ci
|
38
|
+
- .google.co.ck
|
39
|
+
- .google.cl
|
40
|
+
- .google.cm
|
41
|
+
- .google.cn
|
42
|
+
- .google.com.co
|
43
|
+
- .google.co.cr
|
44
|
+
- .google.com.cu
|
45
|
+
- .google.cv
|
46
|
+
- .google.com.cy
|
47
|
+
- .google.cz
|
48
|
+
- .google.de
|
49
|
+
- .google.dj
|
50
|
+
- .google.dk
|
51
|
+
- .google.dm
|
52
|
+
- .google.com.do
|
53
|
+
- .google.dz
|
54
|
+
- .google.com.ec
|
55
|
+
- .google.ee
|
56
|
+
- .google.com.eg
|
57
|
+
- .google.es
|
58
|
+
- .google.com.et
|
59
|
+
- .google.fi
|
60
|
+
- .google.com.fj
|
61
|
+
- .google.fm
|
62
|
+
- .google.fr
|
63
|
+
- .google.ga
|
64
|
+
- .google.ge
|
65
|
+
- .google.gg
|
66
|
+
- .google.com.gh
|
67
|
+
- .google.com.gi
|
68
|
+
- .google.gl
|
69
|
+
- .google.gm
|
70
|
+
- .google.gp
|
71
|
+
- .google.gr
|
72
|
+
- .google.com.gt
|
73
|
+
- .google.gy
|
74
|
+
- .google.com.hk
|
75
|
+
- .google.hn
|
76
|
+
- .google.hr
|
77
|
+
- .google.ht
|
78
|
+
- .google.hu
|
79
|
+
- .google.co.id
|
80
|
+
- .google.ie
|
81
|
+
- .google.co.il
|
82
|
+
- .google.im
|
83
|
+
- .google.co.in
|
84
|
+
- .google.iq
|
85
|
+
- .google.is
|
86
|
+
- .google.it
|
87
|
+
- .google.je
|
88
|
+
- .google.com.jm
|
89
|
+
- .google.jo
|
90
|
+
- .google.co.jp
|
91
|
+
- .google.co.ke
|
92
|
+
- .google.com.kh
|
93
|
+
- .google.ki
|
94
|
+
- .google.kg
|
95
|
+
- .google.co.kr
|
96
|
+
- .google.com.kw
|
97
|
+
- .google.kz
|
98
|
+
- .google.la
|
99
|
+
- .google.com.lb
|
100
|
+
- .google.li
|
101
|
+
- .google.lk
|
102
|
+
- .google.co.ls
|
103
|
+
- .google.lt
|
104
|
+
- .google.lu
|
105
|
+
- .google.lv
|
106
|
+
- .google.com.ly
|
107
|
+
- .google.co.ma
|
108
|
+
- .google.md
|
109
|
+
- .google.me
|
110
|
+
- .google.mg
|
111
|
+
- .google.mk
|
112
|
+
- .google.ml
|
113
|
+
- .google.com.mm
|
114
|
+
- .google.mn
|
115
|
+
- .google.ms
|
116
|
+
- .google.com.mt
|
117
|
+
- .google.mu
|
118
|
+
- .google.mv
|
119
|
+
- .google.mw
|
120
|
+
- .google.com.mx
|
121
|
+
- .google.com.my
|
122
|
+
- .google.co.mz
|
123
|
+
- .google.com.na
|
124
|
+
- .google.com.nf
|
125
|
+
- .google.com.ng
|
126
|
+
- .google.com.ni
|
127
|
+
- .google.ne
|
128
|
+
- .google.nl
|
129
|
+
- .google.no
|
130
|
+
- .google.com.np
|
131
|
+
- .google.nr
|
132
|
+
- .google.nu
|
133
|
+
- .google.co.nz
|
134
|
+
- .google.com.om
|
135
|
+
- .google.com.pa
|
136
|
+
- .google.com.pe
|
137
|
+
- .google.com.pg
|
138
|
+
- .google.com.ph
|
139
|
+
- .google.com.pk
|
140
|
+
- .google.pl
|
141
|
+
- .google.pn
|
142
|
+
- .google.com.pr
|
143
|
+
- .google.ps
|
144
|
+
- .google.pt
|
145
|
+
- .google.com.py
|
146
|
+
- .google.com.qa
|
147
|
+
- .google.ro
|
148
|
+
- .google.ru
|
149
|
+
- .google.rw
|
150
|
+
- .google.com.sa
|
151
|
+
- .google.com.sb
|
152
|
+
- .google.sc
|
153
|
+
- .google.se
|
154
|
+
- .google.com.sg
|
155
|
+
- .google.sh
|
156
|
+
- .google.si
|
157
|
+
- .google.sk
|
158
|
+
- .google.com.sl
|
159
|
+
- .google.sn
|
160
|
+
- .google.so
|
161
|
+
- .google.sm
|
162
|
+
- .google.st
|
163
|
+
- .google.com.sv
|
164
|
+
- .google.td
|
165
|
+
- .google.tg
|
166
|
+
- .google.co.th
|
167
|
+
- .google.com.tj
|
168
|
+
- .google.tk
|
169
|
+
- .google.tl
|
170
|
+
- .google.tm
|
171
|
+
- .google.tn
|
172
|
+
- .google.to
|
173
|
+
- .google.com.tr
|
174
|
+
- .google.tt
|
175
|
+
- .google.com.tw
|
176
|
+
- .google.co.tz
|
177
|
+
- .google.com.ua
|
178
|
+
- .google.co.ug
|
179
|
+
- .google.co.uk
|
180
|
+
- .google.com.uy
|
181
|
+
- .google.co.uz
|
182
|
+
- .google.com.vc
|
183
|
+
- .google.co.ve
|
184
|
+
- .google.vg
|
185
|
+
- .google.co.vi
|
186
|
+
- .google.com.vn
|
187
|
+
- .google.vu
|
188
|
+
- .google.ws
|
189
|
+
- .google.rs
|
190
|
+
- .google.co.za
|
191
|
+
- .google.co.zm
|
192
|
+
- .google.co.zw
|
193
|
+
- .google.cat
|
194
|
+
- .bing.com
|
195
|
+
- .yahoo.com
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module FirstClickFree
|
2
|
+
require 'first_click_free/exceptions/subsequent_access_exception'
|
3
|
+
require 'first_click_free/helpers/google'
|
4
|
+
require 'first_click_free/helpers/path'
|
5
|
+
require 'first_click_free/helpers/referrer'
|
6
|
+
require 'first_click_free/concerns/controller'
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
require 'yaml'
|
11
|
+
|
12
|
+
attr_accessor :test_mode, :permitted_paths, :free_clicks
|
13
|
+
|
14
|
+
def root
|
15
|
+
File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
16
|
+
end
|
17
|
+
|
18
|
+
def permitted_domains
|
19
|
+
@permitted_domains ||= YAML.load_file(File.join(FirstClickFree.root, 'config', 'domains.yml'))
|
20
|
+
end
|
21
|
+
|
22
|
+
def permitted_paths
|
23
|
+
@permitted_paths || []
|
24
|
+
end
|
25
|
+
|
26
|
+
def free_clicks
|
27
|
+
@free_clicks || 1 # default is 1 click free
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_mode
|
31
|
+
@test_mode || false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Railtie < Rails::Railtie
|
36
|
+
initializer "first_click_free.action_controller" do
|
37
|
+
ActiveSupport.on_load(:action_controller) do
|
38
|
+
include FirstClickFree::Concerns::Controller
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module FirstClickFree
|
4
|
+
module Concerns
|
5
|
+
module Controller
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include FirstClickFree::Helpers::Google
|
8
|
+
include FirstClickFree::Helpers::Path
|
9
|
+
include FirstClickFree::Helpers::Referrer
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
# Public: Turn 'on' first click free for this controller.
|
14
|
+
#
|
15
|
+
# options - The options to pass through to `before_filter`.
|
16
|
+
# Common options are `only` and `except`, to limit
|
17
|
+
# which actions are affected.
|
18
|
+
#
|
19
|
+
# DEPRECATION: `before_filter` is deprecated in favour of `before_action`
|
20
|
+
# in Rails 4.
|
21
|
+
#
|
22
|
+
# Returns the result of the call to `before_filter`.
|
23
|
+
def allow_first_click_free(options = {})
|
24
|
+
before_filter :record_or_reject_first_click_free!, options
|
25
|
+
end
|
26
|
+
|
27
|
+
# Public: Skip first click free for a controller or action.
|
28
|
+
#
|
29
|
+
# options - The options to pass through to `skip_before_filter`,
|
30
|
+
# for example to limit which actions should be skipped.
|
31
|
+
#
|
32
|
+
# DEPRECATION: `skip_before_filter` is deprecated in favour of
|
33
|
+
# with `skip_before_action` in Rails 4.
|
34
|
+
#
|
35
|
+
# Returns the result of the call to `skip_before_filter`.
|
36
|
+
def skip_first_click_free(options = {})
|
37
|
+
skip_before_filter :record_or_reject_first_click_free!, options
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: Return the user to use when bypassing first click free
|
43
|
+
# (i.e. there is a user signed in at the time).
|
44
|
+
#
|
45
|
+
# This method is intended to be overridden in the controller
|
46
|
+
# with the appropriate method call (e.g. current_user).
|
47
|
+
#
|
48
|
+
# Returns nil, which will cause first click free to always be active.
|
49
|
+
def user_for_first_click_free
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Public: Either record a first click free request, or reject
|
55
|
+
# the request for a subsequent content access.
|
56
|
+
#
|
57
|
+
# Raises FirstClickFree::Exceptions::SubsequentAccessException if
|
58
|
+
# a first click has already been recorded for this user.
|
59
|
+
#
|
60
|
+
# Returns true if the referrer User agent is GoogleBot, or
|
61
|
+
# if this is the first click recorded for this session.
|
62
|
+
def record_or_reject_first_click_free!
|
63
|
+
# Always allow requests from Googlebot
|
64
|
+
return true if googlebot?
|
65
|
+
|
66
|
+
# Always allow requests from authenticated users
|
67
|
+
return true if user_for_first_click_free
|
68
|
+
|
69
|
+
# Always allow requests to particular paths
|
70
|
+
return true if permitted_path?
|
71
|
+
|
72
|
+
# Reset first click free if the domain is permitted
|
73
|
+
# (new first click free will be set)
|
74
|
+
reset_first_click_free! if permitted_domain?
|
75
|
+
|
76
|
+
if session[:first_click] && session[:first_click].include?(checksum(url_for))
|
77
|
+
# already visited, can visit again
|
78
|
+
elsif session[:first_click] && session[:first_click].length < FirstClickFree.free_clicks
|
79
|
+
# new page but within free click limit
|
80
|
+
session[:first_click] << checksum(url_for)
|
81
|
+
elsif session[:first_click] && session[:first_click].length == FirstClickFree.free_clicks
|
82
|
+
raise FirstClickFree::Exceptions::SubsequentAccessException
|
83
|
+
else
|
84
|
+
# first click!
|
85
|
+
session[:first_click] = [ checksum(url_for) ]
|
86
|
+
end
|
87
|
+
request.env["first_click_free_count"] = session[:first_click].length
|
88
|
+
return true
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# Private: Reset first click free session.
|
94
|
+
#
|
95
|
+
# Returns the value set in the first click session (nil)
|
96
|
+
def reset_first_click_free!
|
97
|
+
session.delete(:first_click)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Private: Create a checksum string.
|
101
|
+
#
|
102
|
+
# Returns a checksum of the url as a string
|
103
|
+
def checksum(url)
|
104
|
+
Zlib.adler32(url).to_s
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|