diff --git a/app/models/photo.rb b/app/models/photo.rb
index db5c2b6..7b44db7 100644
--- a/app/models/photo.rb
+++ b/app/models/photo.rb
@@ -14,8 +14,8 @@ class Photo < ActiveRecord::Base
before_create :hashify_email
before_save :set_oneness
- after_create :create_directories
- before_destroy :destroy_directories
+ after_create :create_directories, :if => lambda { |x| x.facebook_id.nil? }
+ before_destroy :destroy_directories, :if => lambda { |x| x.facebook_id.nil? }
##
# Returns the path of the image relative to Merb's root.
@@ -77,6 +77,7 @@ class Photo < ActiveRecord::Base
# Checks to make sure that the file exists and is an image.
#
def validate_image_sanity
+ return true if self.facebook_id
if self.file.empty? or self.file[:tempfile].nil?
self.errors.add(:file, 'is not a file')
elsif self.file[:content_type] !~ /image\/\w+/
diff --git a/app/models/user.rb b/app/models/user.rb
index cb2942f..91355ee 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -4,10 +4,11 @@ class User < ActiveRecord::Base
attr_protected :auth_token
attr_protected :authorized
- validates_presence_of :user_name
- validates_length_of :user_name, :within => (6..32)
- validates_uniqueness_of :user_name
- validates_format_of :user_name, :with => /[\w_-]+/
+ validates_presence_of :user_name, :if => lambda { |x| x.facebook_id.nil? }
+ validates_length_of :user_name, :within => (6..32), :if => lambda { |x| x.facebook_id.nil? }
+ validates_uniqueness_of :user_name, :if => lambda { |x| x.facebook_id.nil? }
+ validates_format_of :user_name, :with => /[\w_-]+/, :if => lambda { |x| x.facebook_id.nil? }
+ validates_presence_of :facebook_id, :if => lambda { |x| x.user_name.to_s.empty? }
has_many :photos, :dependent => :destroy
has_many :votes, :dependent => :destroy, :order => 'votes.photo_id ASC'
@@ -28,7 +29,7 @@ class User < ActiveRecord::Base
end
def self.salted_string(str)
- Digest::SHA1.hexdigest("#{Merb::Config[:session_secret_key]}--#{str}--")
+ Digest::SHA1.hexdigest("#{@@salt}--#{str}--")
end
def voted_for?(photo)
@@ -39,6 +40,7 @@ class User < ActiveRecord::Base
protected
def saltify_password
+ return true unless self.facebook_id.nil?
if !self.password.to_s.empty?
if self.password.to_s.size < 6
self.errors.add(:password, 'is too short')
@@ -51,4 +53,8 @@ class User < ActiveRecord::Base
self.errors.add(:password, 'is missing')
end
end
+
+ private
+
+ @@salt = '297d94827e16917483c130b7e7f4fd44d605dcdb'
end
diff --git a/app/models/vote.rb b/app/models/vote.rb
index f244453..e983a9f 100644
--- a/app/models/vote.rb
+++ b/app/models/vote.rb
@@ -3,8 +3,9 @@ class Vote < ActiveRecord::Base
belongs_to :user
validates_presence_of :photo_id
+ validate :photo_id_cannot_be_zero
validates_uniqueness_of :user_id, :scope => :photo_id
- validates_uniqueness_of :session_id, :scope => :photo_id
+ validates_uniqueness_of :session_id, :scope => [ :photo_id, :user_id ]
validates_presence_of :session_id, :if => lambda { |x| x.user_id.to_s.empty? }
validates_presence_of :user_id, :if => lambda { |x| x.session_id.to_s.empty? }
@@ -74,6 +75,14 @@ class Vote < ActiveRecord::Base
protected
+ ##
+ # Checks to make sure the photo_id is not zero. There will never be a zero
+ # id of a Photo.
+ #
+ def photo_id_cannot_be_zero
+ self.errors.add :photo_id, 'cannot be zero' if self.photo_id.to_i == 0
+ end
+
##
# Recalc the stats in the Photo for specific stats don't have to query the
# database.
diff --git a/binaryattraction_facebooker.rb b/binaryattraction_facebooker.rb
new file mode 100755
index 0000000..ae9249c
--- /dev/null
+++ b/binaryattraction_facebooker.rb
@@ -0,0 +1,522 @@
+#!/usr/bin/env ruby
+
+##
+# This is my Facebook application for BinaryAttraction. It should be quick and
+# easy to deal with. It has a simple interface into Facebook so that people
+# can play with the application in Facebook. I do not plan on adding all of the
+# features from the webapp into the Facebook application. Sorry. Get a life and
+# log in like the rest of ... everyone.
+#
+# Supports:
+# * hall of fame!
+# * voting
+# * adding facebook photos
+# * checking stats
+# * inviting your friends!
+#
+
+# libraries used
+%w(rubygems frankie active_record yaml memcache memcache_util).each do |lib|
+ require lib
+end
+# require AR models
+Dir.glob(File.dirname(__FILE__) + "/app/models/*.rb") { |m| require m }
+
+##
+# Logger setup for the Sinatra app.
+#
+def log
+ @_logger ||= Logger.new($stderr)
+end
+
+##
+# The BinaryAttraction User found by the facebook id of the currently logged
+# in user.
+#
+def ba_user
+ @_user ||= User.find_by_facebook_id(session[:facebook_session].user.id)
+end
+
+# Sinatra configuration
+configure do
+ set :sessions, true
+ set :logging, log
+ load_facebook_config File.dirname(__FILE__) + '/config/facebooker.yml', Sinatra.env
+ begin
+ log.debug "Using #{Sinatra.env} database environment"
+ db_config = YAML::load_file(File.dirname(__FILE__) + '/config/database.yml')[Sinatra.env]
+ ActiveRecord::Base.logger = log
+ ActiveRecord::Base.establish_connection db_config
+ ActiveRecord::Base.allow_concurrency = true
+ rescue => exception
+ log.fatal "There was a problem loading the database.yml file:"
+ exception.backtrace.each do |msg|
+ log.fatal "* #{msg}"
+ end
+ exit 1
+ end
+ config_path = File.dirname(__FILE__) + '/config/memcache.yml'
+ if File.file?(config_path) and File.readable?(config_path)
+ memcache_connection_str = YAML.load(File.read(config_path))
+ else
+ memcache_connection_str = 'localhost:11211'
+ end
+ CACHE = MemCache.new memcache_connection_str
+end
+
+configure :development do
+ log.level = Logger::DEBUG
+end
+
+configure :production do
+ log.level = Logger::FATAL
+end
+
+# facebooker helpers
+before do
+ ensure_authenticated_to_facebook
+ ensure_application_is_installed_by_facebook_user
+ User.create(:facebook_id => session[:facebook_session].user.id) if ba_user.nil?
+end
+
+# little welcome page, nothing much, really
+post '/' do
+ haml :index
+end
+
+# most oneable photos
+post '/hall_of_fame' do
+ @top_oneness = Photo.find :all, :order => 'oneness DESC, id DESC', :limit => 10, :conditions => 'oneness > 0'
+ haml :hall_of_fame
+end
+
+# go to vote on a photo
+post '/vote' do
+ if params[:save]
+ @vote = Vote.new :vote => (params[:one].to_s == 'true')
+ @vote.user = ba_user
+ @vote.photo = Photo.find(params[:photo_id].to_i) rescue nil
+ unless @vote.save
+ log.info "Failed to save the vote for some reason:"
+ @vote.errors.each_full { |m| log.info "* #{m}" }
+ end
+ end
+ @photo = Photo.next_available_votable_photo ba_user
+ haml :vote
+end
+
+# import photos of yourself from facebook into BA. automatically tags photos
+# uploaded with your facebook id so that you can look up the stats later. since
+# facebook doesn't do 'not' boolean logic, you have to find all the photos then
+# subtract all of the ones already added into ba
+post '/add_photos' do
+ @page = params[:page].to_i
+ per_page = 20
+ if params[:save]
+ (0..per_page).each do |pidx|
+ fb_photo_id = params["photo_ids[#{pidx}]"]
+ break if fb_photo_id.nil?
+ photo = Photo.new :facebook_id => fb_photo_id, :user_id => ba_user.id
+ photo.email_hash = ba_user.facebook_id
+ photo.approved = true
+ unless photo.save
+ log.info "Failed to save the photo:"
+ photo.errors.each_full { |msg| log.info "* #{msg}" }
+ end
+ end
+ end
+ cache_key = "photos_of_#{ba_user.id}"
+ @fb_photos = Cache.get(cache_key) if @page >= 0 or params[:save]
+ @fb_photos ||= session[:facebook_session].get_photos nil, session[:facebook_session].user.id
+ if @page == 0
+ ba_photos = ba_user.photos.find(:all, :select => 'facebook_id', :conditions => 'facebook_id IS NOT NULL').collect { |p| p.facebook_id.to_i }
+ @fb_photos.reject! { |p| ba_photos.include? p.pid.to_i } unless ba_photos.empty?
+ Cache.put(cache_key, @fb_photos)
+ end
+ @min_page = @page - 3 < 0 ? 0 : @page - 3
+ @max_page = @fb_photos.size / per_page
+ @total_photo_count = @fb_photos.size
+ @fb_photos = @fb_photos[@page * per_page, per_page]
+ haml :add_photos
+end
+
+# check your voting record and the stats on photos of you
+post '/stats' do
+ photo_ids = Photo.find(:all, :select => 'id', :conditions => [ 'email_hash = ?', ba_user.facebook_id ]).collect { |p| p.id } rescue []
+ @votes = Vote.find(:all, :conditions => "photo_id IN (#{photo_ids.join(',')})") rescue []
+ haml :stats
+end
+
+# invite your friends to BA!
+post '/invite' do
+ haml :invite
+end
+
+use_in_file_templates!
+
+__END__
+
+@@ index
+%style{ :type => 'text/css' }
+ :sass
+ h1
+ text-align: center
+ .ftabs
+ border-bottom: 1px solid #CCCCCC
+ padding:0 10px 0 8px
+ height: 24px
+ #ajax_loading
+ display: none
+ float: right
+ margin: 7px 16px 0 0
+ height: 8px
+ width: 28px
+ a
+ background: #F0F0F0 none repeat scroll 0 0
+ border-left: 1px solid #E5E5E5
+ border-right: 1px solid #CCCCCC
+ border-top: 1px solid #CCCCCC
+ color: #666666
+ display: block
+ float: left
+ margin-top: 1px
+ padding: 4px 8px
+ position: relative
+ .first
+ border-left: 1px solid #CCCCCC
+ margin-left: 0
+ .last
+ border-right: 1px solid #CCCCCC
+ a:hover
+ background: #fff
+ color: #444
+ text-decoration: none
+ a:focus
+ outline: 0px
+ .active
+ background: #FFFFFF none repeat scroll 0 0
+ border-bottom: 1px solid #FFFFFF
+ border-left: 1px solid #CCCCCC
+ color: #333333
+ margin-bottom: -1px
+ margin-left: -1px
+ margin-top: 0
+ padding-bottom: 4px
+ padding-top: 5px
+ .caption
+ color: #6F6F6F
+ font-size: 11px
+ font-weight: normal
+ margin: 3px 0
+ .photo_tabs
+ padding: 20px 0
+ h3
+ height: 21px
+ overflow: hidden
+ padding: 0 10px
+ .pagerpro
+ font-size: 11px
+ float: right
+ list-style: none
+ margin: 0
+ padding: 0
+ font-weight: normal
+ li
+ display: inline
+ float: left
+ a
+ display: block
+ padding: 3px 3px 2px
+ a:hover
+ background: #3B5998 none repeat scroll 0 0
+ border-bottom: 1px solid #3B5998
+ border-color: #D8DFEA #D8DFEA #3B5998
+ color: #FFFFFF
+ text-decoration: none
+ .current
+ a
+ color: #3B5998
+ cursor: pointer
+ outline-style: none
+ text-decoration: none
+ a:hover
+ background: transparent none repeat scroll 0 0
+ border-bottom: 2px solid #3B5998
+ border-color: #3B5998
+ color: #FFF
+ font-weight: bold
+ padding-left: 2px
+ padding-right: 2px
+ .photos_table
+ background: #F7F7F7 none repeat scroll 0 0
+ border: 1px solid #BBBBBB
+ margin: 0 0 20px
+ overflow: hidden
+ padding: 0
+ position: relative
+ width: 750px
+ .table_wrapper
+ padding: 0 5px
+ margin: 0
+ .photos_table_cell
+ margin: 0
+ padding: 10px 0
+ text-align: center
+ vertical-align: middle
+ width: 150px
+ img
+ background: white none repeat scroll 0 0
+ border: 1px solid #CCCCCC
+ padding: 5px
+ vertical-align: middle
+ img:hover
+ border: 1px solid #3B5998
+ a
+ color: #3B5998
+ cursor: pointer
+ outline-style: none
+ text-decoration: none
+ .top_oneness
+ list-style-type: none
+ width: 450px
+ margin-left: auto
+ margin-right: auto
+ li
+ background-color: #e9b96e
+ border: 1px solid #c17d11
+ padding: 3px 10px
+ margin-bottom: 10px
+ p
+ text-align: center
+ #vote_container
+ width: 604px
+ margin: 0 auto 10px auto
+ img
+ display: block
+ margin-left: auto
+ margin-right: auto
+ #vote_controls
+ margin-left: auto
+ margin-right: auto
+ border: 1px solid #c17d11
+ background-color: #e9b96e
+ width: 66px
+ height: 32px
+ img
+ padding: 5px
+ width: 22px
+ height: 22px
+ float: left
+
+:javascript
+ function run_ajax_request(url, params)
+ {
+ document.getElementById('ajax_loading').setStyle('display', 'inline');
+ var a_request = new Ajax();
+ a_request.responseType = Ajax.FBML;
+ a_request.requireLogin = true;
+ a_request.ondone = function(data) {
+ document.getElementById('ajax_loading').setStyle('display', 'none');
+ document.getElementById('ba_content').setInnerFBML(data);
+ if(document.getElementById('error').getStyle('display') != 'none')
+ Animation(document.getElementById('error')).to('height', '0px').to('opacity', 0).hide().go();
+ }
+ a_request.onerror = function() {
+ document.getElementById('ajax_loading').setStyle('display', 'none');
+ Animation(document.getElementById('error')).to('height', 'auto').from('0px').to('width', 'auto').from('0px').to('opacity', 1).from(0).blind().show().go();
+ }
+ a_request.post('http://facebook.binaryattraction.com/' + url, params);
+ }
+ var oldtab = '';
+ function switch_tab(name)
+ {
+ var oldtab_elem = document.getElementById('tab_' + oldtab);
+ if(oldtab_elem)
+ oldtab_elem.removeClassName('active');
+ oldtab = name;
+ document.getElementById('tab_' + oldtab).addClassName('active');
+ run_ajax_request(name);
+ }
+ function switch_photos(page)
+ {
+ run_ajax_request('add_photos', {'page':page});
+ }
+ function vote_photo(pid, one)
+ {
+ run_ajax_request('vote', {'photo_id':pid, 'save':true, 'one':one});
+ }
+ function highlight_photo(pid)
+ {
+ var img_elem = document.getElementById('photo_' + pid);
+ var input_elem = document.getElementById('input_' + pid); if(!input_elem.getChecked())
+ {
+ Animation(img_elem).to('background', '#ffff4b').from('#fff').go();
+ input_elem.setChecked(true);
+ } else {
+ Animation(img_elem).to('background', '#fff').from('#ffff4b').go();
+ input_elem.setChecked(false);
+ }
+ }
+ function add_photos()
+ {
+ run_ajax_request('add_photos', document.getElementById('add_photos_form').serialize());
+ }
+
+%div#error{ :style => 'display: none; overflow: hidden' }
+ %fb:error{ :message => 'Sorry, there was a problem communicating to the binary|Attraction servers...' }
+%div.ftabs
+ %a{ :id => 'tab_hall_of_fame', :href => '#', :onclick => "switch_tab('hall_of_fame');return false;", :class => "first" } Hall Of Fame
+ %a{ :id => 'tab_vote', :href => '#', :onclick => "switch_tab('vote');return false;" } Vote
+ %a{ :id => 'tab_add_photos', :href => '#', :onclick => "switch_tab('add_photos');return false;" } Add Photos
+ %a{ :id => 'tab_stats', :href => '#', :onclick => "switch_tab('stats');return false;" } Stats
+ %a{ :id => 'tab_invite', :href => '#', :onclick => "switch_tab('invite');return false;", :class => "last" } Invite Your Friends
+ %img#ajax_loading{ :alt => 'loading', :src => 'http://static.ak.fbcdn.net/images/upload_progress.gif?1:25923' }
+%br{ :style => 'clear: both' }
+%div#ba_content
+ %h1 Welcome to Binary Attraction
+ %p.caption{ :style => 'text-align: center' } Check out our home page | Produced by PenguinCoder
+ %p Check out all of the neat stuff we have lying around. Vote on some photos, upload some of yours, and check your stats. Beat your friends' oneness!
+
+@@ hall_of_fame
+%h1 Top oneness
+%ol.top_oneness
+ - @top_oneness.each_with_index do |p, index|
+ %li
+ - if p.facebook_id.to_i == 0
+ %img{ :style => 'display: block; margin: 0px auto', :src => "http://binaryattraction.com/photos/#{p.id}/thumbnail?width=300&height=300" }
+ - else
+ %fb:photo{ :pid => p.facebook_id, :size => 'album' }
+ %p{ :style => 'text-align: center' }== Oneness: #{p.oneness}% Votes 0: #{p.zero_votes} Votes 1: #{p.one_votes} Total Votes: #{p.votes_count}
+
+@@ vote
+- if @photo.nil?
+ %fb:explanation{ :message => 'You have run out of photos to vote! Try adding some more' }
+- else
+ %div#vote_container
+ - if @photo.facebook_id
+ %fb:photo{ :pid => @photo.facebook_id, :size => 'normal' }
+ - else
+ %img{ :src => "http://binaryattraction.com#{@photo.pathname}", :alt => @photo.filename, :width => @photo.width, :height => @photo.height }
+ %div#vote_controls
+ %a{ :href => '#', :onclick => "vote_photo(#{@photo.id}, false); return false;", :title => '0-able' }
+ %img{ :src => 'http://binaryattraction.com/images/0.png' }
+ %a{ :href => '#', :onclick => "vote_photo(#{@photo.id}, true); return false;", :title => '1-able' }
+ %img{ :src => 'http://binaryattraction.com/images/1.png' }
+
+@@ add_photos
+%div.photo_tabs
+ %h3
+ %ul.pagerpro
+ - if @page > 0
+ %li
+ %a{ :href => '#', :onclick => "switch_photos(#{@page - 1});return false;" } Prev
+ - @min_page.upto(@max_page) do |pnum|
+ - if pnum == @page
+ %li.current
+ %a{ :href => '#', :onclick => 'return false;' }= pnum + 1
+ - else
+ %li
+ %a{ :href => '#', :onclick => "switch_photos(#{pnum});return false;" }= pnum + 1
+ - if @page < @max_page
+ %li
+ %a{ :href => '#', :onclick => "switch_photos(#{@page + 1});return false;" } Next
+ %span== Photos of #{session[:facebook_session].user.first_name}
+ %span.caption== #{@total_photo_count} photos | Pick some photos | Try to choose images of just yourself
+ %form{ :id => 'add_photos_form' }
+ %input{ :type => 'hidden', :name => 'save', :value => 'true' }
+ %div.photos_table
+ %div.table_wrapper
+ %table
+ %tbody
+ - @fb_photos.each_slice(5) do |slice|
+ %tr
+ - slice.each do |photo|
+ %td.photos_table_cell
+ %fb:photo{ :pid => photo.pid, :size => 'small', :id => "photo_#{photo.pid}", :onclick => "highlight_photo('#{photo.pid}'); return false;" }
+ %input{ :style => 'display: none', :type => 'checkbox', :name => "photo_ids[]", :id => "input_#{photo.pid}", :value => photo.pid }
+ %input{ :type => 'button', :class => 'inputbutton', :value => 'Add Photos', :onclick => "add_photos(); return false;" }
+
+@@ stats
+%style{ :type => 'text/css' }
+ :sass
+ .poll_results
+ width: 420px
+ h2
+ background-color: #6D84B4
+ color: #FFF
+ font-size: 11px
+ padding: 5px
+ margin: 0
+ .poll_answers
+ background: #FFF none repeat scroll 0 0
+ border-color: #CCCCCC
+ border-style: solid
+ border-width: 0 1px 1px
+ padding: 5px
+ p
+ margin: 0
+ font-weight: bold
+ table
+ margin: 10px 0 10px 0
+ .label
+ padding-right: 10px
+ text-align: right
+ font-size: 11px
+ .bar
+ background-attachment: scroll
+ background-color: #3B5998
+ background-image: none
+ background-position: 0 0
+ background-repeat: repeat
+ float: left
+ height: 18px
+ margin-right: 5px
+ color: #FFF
+ text-align: left
+ font-weight: bold
+ font-size: 13px
+ padding: 1px 1px 1px 3px
+
+%div.poll_results
+ %h2== Your oneness from #{@votes.size} votes
+ %div.poll_answers
+ %table
+ %tbody
+ %tr
+ %td
+ %p.label Oneness
+ %td
+ - oneness = "%.1f" % (@votes.select { |v| v.one? }.size.to_f / @votes.size.to_f * 100.0)
+ %div.bar{ :style => "width: #{240 * oneness.to_i / 100}px" }== #{oneness}%
+ %tr
+ %td
+ %p.label Votes 1
+ %td= @votes.select { |v| v.one? }.size
+ %tr
+ %td
+ %p.label Votes 0
+ %td= @votes.select { |v| v.zero? }.size
+%br
+%div.poll_results
+ %h2== Your voting results for #{ba_user.votes.size} photos
+ %div.poll_answers
+ %table
+ %tbody
+ %tr
+ %td
+ %p.label Oneness
+ %td
+ - oneness = "%.1f" % (ba_user.votes.select { |v| v.one? }.size.to_f / ba_user.votes.size.to_f * 100.0)
+ %div.bar{ :style => "width: #{240 * oneness.to_i / 100}px" }== #{oneness}%
+ %tr
+ %td
+ %p.label Votes 1
+ %td= ba_user.votes.select { |v| v.one? }.size
+ %tr
+ %td
+ %p.label Votes 0
+ %td= ba_user.votes.select { |v| v.zero? }.size
+
+@@ invite
+%fb:request-form{ :type => 'Binary Attraction', :content => "Your friends think you should check out your oneness at ", :action => 'http://apps.binaryattraction.com/binaryattraction', :invite => true, :method => 'POST' }
+ %fb:multi-friend-selector{ :actiontext => "Invite your friends to vote on ones (and not ones)", :showborder => true, :exclude_ids => session[:facebook_session].user.friends_with_this_app.map(&:id).join(","), :bypass => "cancel" }
diff --git a/config/init.rb b/config/init.rb
index 451eff5..cdc953f 100644
--- a/config/init.rb
+++ b/config/init.rb
@@ -2,7 +2,10 @@ Gem.clear_paths
Gem.path.unshift(Merb.root / "gems")
$LOAD_PATH.unshift(Merb.root / "lib")
-dependencies 'haml', 'sass', 'merb_helpers', 'merb_has_flash', 'digest/sha1', 'merb-mailer', 'recaptcha'
+dependencies 'haml', 'merb_helpers', 'merb_has_flash', 'merb-mailer'
+require 'digest/sha1'
+require 'sass'
+require 'recaptcha'
require 'merb_exceptions'
require 'RMagick'
require 'memcache'
diff --git a/gems/facebooker-0.9.9.gem b/gems/facebooker-0.9.9.gem
new file mode 100644
index 0000000..864bbb6
Binary files /dev/null and b/gems/facebooker-0.9.9.gem differ
diff --git a/gems/frankie-0.2.5.gem b/gems/frankie-0.2.5.gem
new file mode 100644
index 0000000..c2ec2c8
Binary files /dev/null and b/gems/frankie-0.2.5.gem differ
diff --git a/gems/sinatra-0.3.2.gem b/gems/sinatra-0.3.2.gem
new file mode 100644
index 0000000..c573c7f
Binary files /dev/null and b/gems/sinatra-0.3.2.gem differ
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..2c3722a
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/schema/schema.rb b/schema/schema.rb
index c18045e..a415458 100644
--- a/schema/schema.rb
+++ b/schema/schema.rb
@@ -9,15 +9,15 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 8) do
+ActiveRecord::Schema.define(:version => 9) do
create_table "photo_favorites", :force => true do |t|
t.integer "photo_id"
t.integer "user_id"
end
- add_index "photo_favorites", ["user_id"], :name => "index_photo_favorites_on_user_id"
add_index "photo_favorites", ["photo_id"], :name => "index_photo_favorites_on_photo_id"
+ add_index "photo_favorites", ["user_id"], :name => "index_photo_favorites_on_user_id"
create_table "photo_flags", :force => true do |t|
t.integer "user_id"
@@ -25,8 +25,8 @@ ActiveRecord::Schema.define(:version => 8) do
t.string "session_id"
end
- add_index "photo_flags", ["photo_id"], :name => "index_photo_flags_on_photo_id"
add_index "photo_flags", ["user_id"], :name => "index_photo_flags_on_user_id"
+ add_index "photo_flags", ["photo_id"], :name => "index_photo_flags_on_photo_id"
create_table "photos", :force => true do |t|
t.string "filename"
@@ -36,19 +36,21 @@ ActiveRecord::Schema.define(:version => 8) do
t.integer "height"
t.integer "user_id"
t.datetime "created_at"
- t.boolean "approved", :default => false
- t.integer "votes_count", :default => 0
- t.integer "one_votes", :default => 0
- t.integer "zero_votes", :default => 0
+ t.boolean "approved", :default => false
+ t.integer "votes_count", :default => 0
+ t.integer "one_votes", :default => 0
+ t.integer "zero_votes", :default => 0
t.float "oneness"
- t.integer "photo_flags_count", :default => 0
+ t.integer "photo_flags_count", :default => 0
+ t.integer "facebook_id", :limit => 8
end
- add_index "photos", ["approved"], :name => "index_photos_on_approved"
- add_index "photos", ["oneness"], :name => "index_photos_on_oneness"
- add_index "photos", ["votes_count"], :name => "index_photos_on_votes_count"
- add_index "photos", ["user_id"], :name => "index_photos_on_user_id"
add_index "photos", ["email_hash"], :name => "index_photos_on_email_hash"
+ add_index "photos", ["user_id"], :name => "index_photos_on_user_id"
+ add_index "photos", ["votes_count"], :name => "index_photos_on_votes_count"
+ add_index "photos", ["oneness"], :name => "index_photos_on_oneness"
+ add_index "photos", ["approved"], :name => "index_photos_on_approved"
+ add_index "photos", ["facebook_id"], :name => "index_photos_on_facebook_id"
create_table "sessions", :force => true do |t|
t.string "session_id"
@@ -63,9 +65,11 @@ ActiveRecord::Schema.define(:version => 8) do
t.string "auth_token"
t.boolean "administrator"
t.datetime "created_at"
+ t.integer "facebook_id", :limit => 8
end
add_index "users", ["user_name"], :name => "index_users_on_user_name"
+ add_index "users", ["facebook_id"], :name => "index_users_on_facebook_id"
create_table "votes", :force => true do |t|
t.integer "photo_id"
@@ -74,8 +78,8 @@ ActiveRecord::Schema.define(:version => 8) do
t.boolean "vote"
end
- add_index "votes", ["session_id"], :name => "index_votes_on_session_id"
- add_index "votes", ["user_id"], :name => "index_votes_on_user_id"
add_index "votes", ["photo_id"], :name => "index_votes_on_photo_id"
+ add_index "votes", ["user_id"], :name => "index_votes_on_user_id"
+ add_index "votes", ["session_id"], :name => "index_votes_on_session_id"
end