catptcha 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/{README → README.markdown} +14 -5
- data/Rakefile +6 -19
- data/catptcha.gemspec +2 -1
- data/generators/catptcha_migration/templates/migration.rb +7 -2
- data/lib/catptcha/photo.rb +8 -0
- data/lib/catptcha/photo_group.rb +8 -46
- data/lib/catptcha/seed.rb +31 -2
- data/lib/catptcha.rb +12 -1
- data/lib/tasks/catptcha.rake +6 -0
- data/test/catptcha_seed_test.rb +24 -0
- data/test/catptcha_test.rb +21 -0
- data/test/photo_group_test.rb +27 -0
- data/test/test_helper.rb +28 -0
- metadata +29 -8
data/{README → README.markdown}
RENAMED
@@ -9,20 +9,29 @@ This is still experimental and incomplete. Don't use it.
|
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
12
|
-
|
12
|
+
From within your Rails application:
|
13
13
|
|
14
|
-
|
14
|
+
Add the gem to your Gemfile and load the rake tasks.
|
15
|
+
|
16
|
+
echo "gem 'catptcha'" >> Gemfile
|
17
|
+
echo "load 'tasks/catptcha.rake'" >> Rakefile
|
15
18
|
|
16
19
|
Put your flickr keys in config/flickr.yml, see flickr.example.yml.
|
17
20
|
|
18
|
-
Generate the migration
|
21
|
+
Generate and run the migration.
|
19
22
|
|
20
|
-
|
23
|
+
ruby script/generate catptcha_migration add_catptcha_tables
|
24
|
+
rake db:migrate
|
21
25
|
|
22
|
-
Seed the images
|
26
|
+
Seed the images.
|
23
27
|
|
24
28
|
rake catptcha:seed
|
25
29
|
|
30
|
+
Run the tests.
|
31
|
+
|
32
|
+
rake db:test:prepare
|
33
|
+
rake catptcha:test
|
34
|
+
|
26
35
|
## Author
|
27
36
|
|
28
37
|
Copyright (c) 2012 ENTP, released under the MIT license
|
data/Rakefile
CHANGED
@@ -1,23 +1,10 @@
|
|
1
|
-
require 'rake'
|
2
|
-
require 'rake/testtask'
|
3
|
-
require 'rdoc/task'
|
4
1
|
|
5
|
-
desc 'Default:
|
6
|
-
task :default => :
|
2
|
+
desc 'Default: build the gem'
|
3
|
+
task :default => :gem
|
7
4
|
|
8
|
-
desc '
|
9
|
-
|
10
|
-
|
11
|
-
t.libs << 'test'
|
12
|
-
t.pattern = 'test/**/*_test.rb'
|
13
|
-
t.verbose = true
|
5
|
+
desc 'Build the gem'
|
6
|
+
task :gem do
|
7
|
+
sh 'gem build catptcha.gemspec'
|
14
8
|
end
|
15
9
|
|
16
|
-
|
17
|
-
RDoc::Task.new(:rdoc) do |rdoc|
|
18
|
-
rdoc.rdoc_dir = 'rdoc'
|
19
|
-
rdoc.title = 'Catptcha'
|
20
|
-
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
-
rdoc.rdoc_files.include('README')
|
22
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
-
end
|
10
|
+
|
data/catptcha.gemspec
CHANGED
@@ -4,12 +4,13 @@ require 'catptcha'
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "catptcha"
|
6
6
|
s.version = Catptcha::VERSION
|
7
|
-
s.summary = 'Visual
|
7
|
+
s.summary = 'Visual captcha plugin for Rails 2.3'
|
8
8
|
s.description = <<-EOD
|
9
9
|
Choose the kitten!
|
10
10
|
EOD
|
11
11
|
s.add_dependency "commonthread-flickr_fu", "0.3.0"
|
12
12
|
s.add_dependency "activerecord", "~>2.3"
|
13
|
+
s.add_development_dependency "rr"
|
13
14
|
s.authors = ['Zack Hobson']
|
14
15
|
s.files = `git ls-files`.split("\n")
|
15
16
|
s.test_files = `git ls-files -- test/*`.split("\n")
|
@@ -2,18 +2,23 @@ class <%= class_name %> < ActiveRecord::Migration
|
|
2
2
|
def self.up
|
3
3
|
create_table :catptcha_photos do |t|
|
4
4
|
t.belongs_to :photo_group
|
5
|
+
t.string :key
|
5
6
|
t.string :url
|
6
|
-
t.index :catptcha_group_id
|
7
7
|
end
|
8
|
+
add_index :catptcha_photos, :photo_group_id
|
9
|
+
add_index :catptcha_photos, :key, :unique => true
|
10
|
+
|
8
11
|
create_table :catptcha_photo_groups do |t|
|
9
12
|
t.string :name
|
10
13
|
t.string :flickr_group_id
|
11
14
|
t.timestamp :photos_updated_at
|
12
15
|
t.integer :photos_count
|
13
16
|
t.boolean :kittens
|
14
|
-
t.index :kittens
|
15
17
|
end
|
18
|
+
add_index :catptcha_photo_groups, :flickr_group_id, :unique => true
|
19
|
+
add_index :catptcha_photo_groups, :kittens
|
16
20
|
end
|
21
|
+
|
17
22
|
def self.down
|
18
23
|
drop_table :catptcha_photos
|
19
24
|
drop_table :catptcha_photo_groups
|
data/lib/catptcha/photo.rb
CHANGED
@@ -2,4 +2,12 @@
|
|
2
2
|
class Catptcha::Photo < ActiveRecord::Base
|
3
3
|
set_table_name "catptcha_photos"
|
4
4
|
belongs_to :photo_group, :counter_cache => :photos_count, :class_name => 'Catptcha::PhotoGroup'
|
5
|
+
|
6
|
+
before_validation_on_create :generate_key
|
7
|
+
validates_uniqueness_of :key, :on => :create
|
8
|
+
validates_presence_of :photo_group_id
|
9
|
+
|
10
|
+
def generate_key
|
11
|
+
self.key = Digest::SHA1.hexdigest(url)
|
12
|
+
end
|
5
13
|
end
|
data/lib/catptcha/photo_group.rb
CHANGED
@@ -4,62 +4,24 @@
|
|
4
4
|
class Catptcha::PhotoGroup < ActiveRecord::Base
|
5
5
|
set_table_name 'catptcha_photo_groups'
|
6
6
|
|
7
|
+
validates_presence_of :name, :flickr_group_id
|
7
8
|
validates_uniqueness_of :name
|
8
|
-
validates_uniqueness_of :flickr_group_id
|
9
9
|
|
10
10
|
has_many :photos, :class_name => 'Catptcha::Photo'
|
11
11
|
named_scope :kittens, :conditions => {:kittens => true}
|
12
12
|
named_scope :not_kittens, :conditions => {:kittens => false}
|
13
13
|
|
14
14
|
def self.photos_count
|
15
|
-
|
15
|
+
sum(:photos_count)
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.random count
|
19
|
-
# TODO
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
conditions << results.map(&:id)
|
26
|
-
end
|
27
|
-
results << Photo.first(
|
28
|
-
:conditions => conditions,
|
29
|
-
:offset => rand(photos_count).to_i
|
30
|
-
)
|
31
|
-
end
|
32
|
-
results
|
33
|
-
end
|
34
|
-
|
35
|
-
def update_images flickr
|
36
|
-
get_photos(flickr) do |photo|
|
37
|
-
photos.create(:url => photo.url(:square))
|
38
|
-
end
|
39
|
-
update_attributes(:photos_updated_at => DateTime.now.utc)
|
40
|
-
end
|
41
|
-
|
42
|
-
# fetches up to 2000 photos
|
43
|
-
def get_photos flickr
|
44
|
-
params = {
|
45
|
-
:group_id => flickr_group_id, :safe_search => 1, :content_type => 1,
|
46
|
-
:per_page => 500, :page => 1
|
47
|
-
}
|
48
|
-
params[:min_upload_date] = photos_updated_at if photos_updated_at
|
49
|
-
|
50
|
-
total_pages = nil
|
51
|
-
loop do
|
52
|
-
result = flickr.photos.search(params)
|
53
|
-
result.each do |photo|
|
54
|
-
yield photo
|
55
|
-
end
|
56
|
-
if total_pages.nil?
|
57
|
-
total_pages = [result.pages, 4].min
|
58
|
-
else
|
59
|
-
params[:page] += 1
|
60
|
-
break if params[:page] > total_pages
|
61
|
-
end
|
62
|
-
end
|
19
|
+
# TODO generate an identity/key column that isn't easy to guess
|
20
|
+
Catptcha::Photo.all(
|
21
|
+
:conditions => ['photo_group_id in (?)', all.map(&:id)],
|
22
|
+
:offset => rand(photos_count-count).to_i,
|
23
|
+
:limit => count
|
24
|
+
)
|
63
25
|
end
|
64
26
|
|
65
27
|
end
|
data/lib/catptcha/seed.rb
CHANGED
@@ -14,7 +14,7 @@ module Catptcha::Seed
|
|
14
14
|
@flickr ||= Flickr.new(Rails.root.join("config/flickr.yml").to_s)
|
15
15
|
end
|
16
16
|
|
17
|
-
def update
|
17
|
+
def update silent=false
|
18
18
|
SEED_GROUP_KITTENS.each do |name, id|
|
19
19
|
Catptcha::PhotoGroup.create(:name => name.to_s, :flickr_group_id => id, :kittens => true)
|
20
20
|
end
|
@@ -22,8 +22,37 @@ module Catptcha::Seed
|
|
22
22
|
Catptcha::PhotoGroup.create(:name => name.to_s, :flickr_group_id => id, :kittens => false)
|
23
23
|
end
|
24
24
|
Catptcha::PhotoGroup.all.each do |group|
|
25
|
-
group.
|
25
|
+
puts "updating photos for `#{group.name}`..." unless silent
|
26
|
+
count = update_photos group
|
27
|
+
puts "...done, #{count} photos imported" unless silent
|
26
28
|
end
|
27
29
|
end
|
30
|
+
|
31
|
+
# fetches up to 2500 photos
|
32
|
+
def update_photos group
|
33
|
+
params = {
|
34
|
+
:group_id => group.flickr_group_id, :safe_search => 1, :content_type => 1,
|
35
|
+
:per_page => 500, :page => 1
|
36
|
+
}
|
37
|
+
params[:min_upload_date] = group.photos_updated_at if group.photos_updated_at
|
38
|
+
|
39
|
+
total_pages = nil
|
40
|
+
photo_count = 0
|
41
|
+
loop do
|
42
|
+
result = flickr.photos.search(params)
|
43
|
+
result.each do |photo|
|
44
|
+
group.photos.create(:url => photo.url(:square))
|
45
|
+
photo_count += 1
|
46
|
+
end
|
47
|
+
if total_pages.nil?
|
48
|
+
total_pages = [result.pages, 5].min
|
49
|
+
else
|
50
|
+
params[:page] += 1
|
51
|
+
end
|
52
|
+
break if params[:page] >= total_pages
|
53
|
+
end
|
54
|
+
group.update_attributes(:photos_updated_at => DateTime.now.utc)
|
55
|
+
photo_count
|
56
|
+
end
|
28
57
|
end
|
29
58
|
end
|
data/lib/catptcha.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Catptcha
|
2
|
-
VERSION = '0.0.
|
2
|
+
VERSION = '0.0.3'
|
3
3
|
|
4
4
|
class << self
|
5
5
|
# Get a list of 3 kitten photos
|
@@ -11,9 +11,20 @@ module Catptcha
|
|
11
11
|
def not_kittens
|
12
12
|
PhotoGroup.not_kittens.random(6)
|
13
13
|
end
|
14
|
+
|
15
|
+
def check_guesses *ids
|
16
|
+
guesses = ids.flatten.compact
|
17
|
+
if guesses.size != 3
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
3 == Photo.count(:include => 'photo_group', :conditions => [
|
21
|
+
'catptcha_photos.id in (?) and kittens = ?', guesses, true
|
22
|
+
])
|
23
|
+
end
|
14
24
|
end
|
15
25
|
|
16
26
|
autoload :Photo, 'catptcha/photo'
|
17
27
|
autoload :PhotoGroup, 'catptcha/photo_group'
|
18
28
|
autoload :Seed, 'catptcha/seed'
|
29
|
+
|
19
30
|
end
|
data/lib/tasks/catptcha.rake
CHANGED
@@ -3,5 +3,11 @@ namespace :catptcha do
|
|
3
3
|
task :seed => :environment do
|
4
4
|
Catptcha::Seed.update
|
5
5
|
end
|
6
|
+
|
7
|
+
desc 'run catptcha plugin tests'
|
8
|
+
Rake::TestTask.new do |t|
|
9
|
+
t.test_files = FileList[File.dirname(__FILE__)+'/../../test/**/*_test.rb']
|
10
|
+
t.verbose = true
|
11
|
+
end
|
6
12
|
end
|
7
13
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/test_helper.rb'
|
2
|
+
|
3
|
+
class CatptchaSeedTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Catptcha::PhotoGroup.delete_all
|
6
|
+
Catptcha::Photo.delete_all
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_seed_with_no_photos
|
10
|
+
stub(Catptcha::Seed).flickr { build_flickr_stub [] }
|
11
|
+
Catptcha::Seed.update :silent
|
12
|
+
assert_equal 3, Catptcha::PhotoGroup.count
|
13
|
+
assert_equal 0, Catptcha::Photo.count
|
14
|
+
# doesn't recreate groups
|
15
|
+
Catptcha::Seed.update :silent
|
16
|
+
assert_equal 3, Catptcha::PhotoGroup.count
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_seed_with_photos
|
20
|
+
stub(Catptcha::Seed).flickr { build_flickr_stub { [ build_flickr_photo_stub ] } }
|
21
|
+
Catptcha::Seed.update :silent
|
22
|
+
assert_equal 3, Catptcha::Photo.count
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/test_helper.rb'
|
2
|
+
|
3
|
+
class CatptchaTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
Catptcha::Photo.delete_all
|
7
|
+
Catptcha::PhotoGroup.delete_all
|
8
|
+
kittens = Catptcha::PhotoGroup.create!(:name => 'kittens', :flickr_group_id => 'x', :kittens => true)
|
9
|
+
3.times {|i| kittens.photos.create!(:url => "http://#{i}") }
|
10
|
+
not_kittens = Catptcha::PhotoGroup.create!(:name => 'not_kittens', :flickr_group_id => 'y', :kittens => false)
|
11
|
+
6.times {|i| not_kittens.photos.create!(:url => "http://#{i+3}") }
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_kittens
|
15
|
+
assert Catptcha.check_guesses(Catptcha.kittens.map(&:id))
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_not_kittens
|
19
|
+
assert !Catptcha.check_guesses(Catptcha.not_kittens.map(&:id)[0,3])
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/test_helper.rb'
|
2
|
+
|
3
|
+
class PhotoGroupTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
Catptcha::Photo.delete_all
|
7
|
+
Catptcha::PhotoGroup.delete_all
|
8
|
+
kittens = Catptcha::PhotoGroup.create!(:name => 'kittens', :flickr_group_id => 'x', :kittens => true)
|
9
|
+
3.times {|i| kittens.photos.create!(:url => "http://#{i}") }
|
10
|
+
kittens = Catptcha::PhotoGroup.create!(:name => 'more_kittens', :flickr_group_id => 'a', :kittens => true)
|
11
|
+
3.times {|i| kittens.photos.create!(:url => "http://#{i+3}") }
|
12
|
+
not_kittens = Catptcha::PhotoGroup.create!(:name => 'tacos', :flickr_group_id => 'y', :kittens => false)
|
13
|
+
6.times {|i| not_kittens.photos.create!(:url => "http://#{i+6}") }
|
14
|
+
not_kittens = Catptcha::PhotoGroup.create!(:name => 'yaks', :flickr_group_id => 'b', :kittens => false)
|
15
|
+
6.times {|i| not_kittens.photos.create!(:url => "http://#{i+12}") }
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_photo_count
|
19
|
+
assert_equal 6, Catptcha::PhotoGroup.kittens.photos_count
|
20
|
+
assert_equal 12, Catptcha::PhotoGroup.not_kittens.photos_count
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_random
|
24
|
+
assert_equal 3, Catptcha::PhotoGroup.kittens.random(3).size
|
25
|
+
assert_equal 6, Catptcha::PhotoGroup.not_kittens.random(6).size
|
26
|
+
end
|
27
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
ENV['RAILS_ENV'] = 'test'
|
2
|
+
require "./config/environment"
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rr'
|
5
|
+
|
6
|
+
class Test::Unit::TestCase
|
7
|
+
include RR::Adapters::RRMethods
|
8
|
+
|
9
|
+
# Stub out a flickr photo with a unique url
|
10
|
+
def build_flickr_photo_stub
|
11
|
+
@index ||= 0
|
12
|
+
@index += 1
|
13
|
+
Object.new.tap do |photo|
|
14
|
+
stub(photo).url { "http://#{@index}" }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Stub out a flickr search query using the provided photos,
|
19
|
+
# for lazy evaluation pass the photos in a block instead
|
20
|
+
def build_flickr_stub value=nil
|
21
|
+
Object.new.tap do |flickr|
|
22
|
+
photos = Object.new
|
23
|
+
stub(flickr).photos { stub(photos).search {
|
24
|
+
(value || yield).tap {|result| stub(result).pages { 1 } }
|
25
|
+
}}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: catptcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Zack Hobson
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-05-
|
18
|
+
date: 2012-05-17 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -49,6 +49,20 @@ dependencies:
|
|
49
49
|
version: "2.3"
|
50
50
|
type: :runtime
|
51
51
|
version_requirements: *id002
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: rr
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
type: :development
|
65
|
+
version_requirements: *id003
|
52
66
|
description: " Choose the kitten!\n"
|
53
67
|
email:
|
54
68
|
executables: []
|
@@ -60,7 +74,7 @@ extra_rdoc_files: []
|
|
60
74
|
files:
|
61
75
|
- .gitignore
|
62
76
|
- MIT-LICENSE
|
63
|
-
- README
|
77
|
+
- README.markdown
|
64
78
|
- Rakefile
|
65
79
|
- catptcha.gemspec
|
66
80
|
- generators/catptcha_migration/catptcha_migration_generator.rb
|
@@ -72,6 +86,10 @@ files:
|
|
72
86
|
- lib/catptcha/seed.rb
|
73
87
|
- lib/tasks/catptcha.rake
|
74
88
|
- rails/init.rb
|
89
|
+
- test/catptcha_seed_test.rb
|
90
|
+
- test/catptcha_test.rb
|
91
|
+
- test/photo_group_test.rb
|
92
|
+
- test/test_helper.rb
|
75
93
|
- uninstall.rb
|
76
94
|
has_rdoc: true
|
77
95
|
homepage:
|
@@ -106,6 +124,9 @@ rubyforge_project:
|
|
106
124
|
rubygems_version: 1.6.2
|
107
125
|
signing_key:
|
108
126
|
specification_version: 3
|
109
|
-
summary: Visual
|
110
|
-
test_files:
|
111
|
-
|
127
|
+
summary: Visual captcha plugin for Rails 2.3
|
128
|
+
test_files:
|
129
|
+
- test/catptcha_seed_test.rb
|
130
|
+
- test/catptcha_test.rb
|
131
|
+
- test/photo_group_test.rb
|
132
|
+
- test/test_helper.rb
|