287 lines
7.6 KiB
Ruby
287 lines
7.6 KiB
Ruby
require "pathname"
|
||
require "markaby"
|
||
require "camping/session"
|
||
|
||
Markaby::Builder.set(:indent, 2)
|
||
|
||
Camping.goes :Anne
|
||
|
||
IMAGE_DIR = Pathname.new(__FILE__).dirname + "images"
|
||
|
||
module Anne
|
||
|
||
include Camping::Session
|
||
secret "JeMoeder"
|
||
|
||
def self.create
|
||
Anne::Models.create_schema
|
||
end
|
||
|
||
end
|
||
|
||
module Anne::Models
|
||
|
||
class User < Base
|
||
end
|
||
|
||
class Vote < Base
|
||
belongs_to :user
|
||
end
|
||
|
||
class BasicFields < V 1.0
|
||
def self.up
|
||
create_table User.table_name do |t|
|
||
t.string :study, :gender, :spaciousness, :email
|
||
t.integer :study_year
|
||
t.boolean :colorblind, :prize, :results
|
||
t.timestamps
|
||
end
|
||
create_table Vote.table_name do |t|
|
||
t.string :image, :choice
|
||
t.integer :user_id
|
||
end
|
||
end
|
||
|
||
def self.down
|
||
drop_table User.table_name
|
||
drop_table Vote.table_name
|
||
end
|
||
end
|
||
|
||
end
|
||
|
||
module Anne::Helpers
|
||
|
||
def next_image
|
||
all_images =
|
||
Pathname.glob(IMAGE_DIR + "*.jpg").map { |img| img.basename.to_s }
|
||
all_votes =
|
||
Anne::Models::Vote.find(:all,
|
||
:conditions => { :user_id => @state["user"].id })
|
||
voted_images = all_votes.map { |vote| vote.image }
|
||
remaining_images = all_images - voted_images
|
||
return nil, 100 if remaining_images.empty?
|
||
return remaining_images.sort_by { rand }.first,
|
||
100 - (remaining_images.length * 100.0 / all_images.length).ceil
|
||
end
|
||
|
||
end
|
||
|
||
module Anne::Controllers
|
||
|
||
class Index
|
||
def get
|
||
render :intro
|
||
end
|
||
end
|
||
|
||
class Start
|
||
def get
|
||
return redirect Vote if @state["user"]
|
||
render :start
|
||
end
|
||
|
||
def post
|
||
@state["user"] = User.create(
|
||
:study => @input.user_study,
|
||
:study_year => @input.user_study_year,
|
||
:gender => @input.user_gender,
|
||
:colorblind => @input.user_colorblind == "ja",
|
||
:spaciousness => @input.user_spaciousness)
|
||
redirect Vote
|
||
end
|
||
end
|
||
|
||
class Vote
|
||
def get
|
||
return redirect Index if not @state["user"]
|
||
image, progress = next_image
|
||
return redirect Finish if image.nil?
|
||
render :vote, image, progress
|
||
end
|
||
|
||
def post
|
||
choice = if @input.left then "left"
|
||
elsif @input.right then "right"
|
||
else raise "no choice made!"
|
||
end
|
||
vote = Anne::Models::Vote.create( :user_id => @state["user"].id,
|
||
:image => @input.image,
|
||
:choice => choice )
|
||
redirect Vote
|
||
end
|
||
end
|
||
|
||
class ImageX
|
||
def get(file)
|
||
unless file =~ /\.\./
|
||
headers["Content-Type"] = "image/jpeg"
|
||
headers["X-Sendfile"] = (IMAGE_DIR + file).to_s
|
||
else
|
||
@status = 403
|
||
"You're not allowed to retrieve #{file}!"
|
||
end
|
||
end
|
||
end
|
||
|
||
class Finish
|
||
def get
|
||
return redirect Index if not @state["user"]
|
||
return redirect Vote unless next_image.first.nil?
|
||
# FIXME: check whether email/prize/results have been sent, and redirect to Thanks.
|
||
render :finish
|
||
end
|
||
|
||
def post
|
||
user = User.find(@state["user"].id)
|
||
raise "unknown user" if user.nil?
|
||
user.email = @input.email
|
||
user.prize = !@input.prize.nil?
|
||
user.results = !@input.results.nil?
|
||
user.save
|
||
redirect Thanks
|
||
end
|
||
end
|
||
|
||
class Style < R '/style\.css'
|
||
STYLE = File.read(__FILE__).gsub(/.*__END__/m, '')
|
||
|
||
def get
|
||
@headers['Content-Type'] = 'text/css; charset=utf-8'
|
||
STYLE
|
||
end
|
||
end
|
||
|
||
class Thanks
|
||
def get
|
||
render :thanks
|
||
end
|
||
end
|
||
|
||
end
|
||
|
||
module Anne::Views
|
||
|
||
def layout
|
||
xhtml_strict do
|
||
head do
|
||
title "Enquête ruimtelijke effecten"
|
||
link :rel => "stylesheet", :type => "text/css",
|
||
:media => "screen", :href => "/style.css"
|
||
end
|
||
body do
|
||
div.header! do
|
||
h1 "Enquête ruimtelijke effecten"
|
||
end
|
||
div.content! { self << yield }
|
||
div.footer! { "Copyright © 2010 Anne Pijl, Bram Senders, Paul van Tilburg" }
|
||
end
|
||
end
|
||
end
|
||
|
||
def intro
|
||
p "Met deze enquête worden een aantal ruimtelijke effecten onderzocht. " +
|
||
"Je krijgt 39 keer een plaatje met twee afbeeldingen te zien. " +
|
||
"Je kiest welke afbeelding, de linker of de rechter afbeelding, " +
|
||
"je ruimtelijker ervaart. " +
|
||
"In welk plaatje zie je meer diepte, welk plaatje lijkt jou het meest " +
|
||
"3-dimensionaal? Als je het niet weet, klik je op een willekeurige " +
|
||
"afbeelding. De test duurt 5 á 10 minuten. Succes!"
|
||
p "Doe de test volledig om kans te maken op de prijs."
|
||
p "– Anne Pijl"
|
||
a "Start de enquête!", :href => R(Start)
|
||
p "(Jij logt in vanaf #{@env["REMOTE_ADDR"]}.)"
|
||
end
|
||
|
||
def make_select(label_name, name, options)
|
||
p do
|
||
label label_name, :for => name
|
||
select :name => name do
|
||
options.each { |option_str| option option_str }
|
||
end
|
||
end
|
||
end
|
||
|
||
def start
|
||
h2 "Persoonlijke karakteristieken"
|
||
p "Graag zou ik ten behoeve van de statistiek het volgende van je willen weten:"
|
||
|
||
form :action => R(Start), :method => :post do
|
||
make_select "Faculteit:", "user_study",
|
||
["niet van toepassing",
|
||
"Biomedische Technologie",
|
||
"Bouwkunde",
|
||
"Electrical Engineering",
|
||
"Industrial Design",
|
||
"Scheikundige Technologie",
|
||
"Industrial Engineering & Innovation Sciences",
|
||
"Technische Natuurkunde",
|
||
"Werktuigbouwkunde",
|
||
"Wiskunde & Informatica"]
|
||
make_select "Studiejaar", "user_study_year", ["niet van toepassing"] + (1998..2009).to_a
|
||
make_select "Geslacht", "user_gender", ["", "man", "vrouw"]
|
||
make_select "Ben je kleurenblind?", "user_colorblind", ["nee", "ja"]
|
||
make_select "Vind je dat je een goed ruimtelijk voorstellingsvermogen hebt?",
|
||
"user_spaciousness", ["neutraal", "ja", "nee"]
|
||
|
||
input :type => "submit", :value => "Start de enquete"
|
||
end
|
||
end
|
||
|
||
def vote(image, progress = 0)
|
||
h2 "Welk beeld is ruimtelijker?"
|
||
# FIXME: resize all images
|
||
# FIXME: split all images in two parts and make it possible two select an image.
|
||
img :src => R(ImageX, image), :width => "80%"
|
||
form :action => R(Vote), :method => :post do
|
||
input :type => "hidden", :name => "image", :value => image
|
||
input :type => "submit", :name => "left", :value => "Links"
|
||
input :type => "submit", :name => "right", :value => "Rechts"
|
||
end
|
||
# FIXME: make a nice div with two spans of the following.
|
||
p "Woep, je bent al op #{progress}%!"
|
||
end
|
||
|
||
def finish
|
||
h2 "Dank je wel voor het meedoen aan dit onderzoek."
|
||
p "Als je geïnteresseerd bent in de resultaten van de enquête of je wilt " +
|
||
"meedingen naar de prijs, vul dan hier je e-mailadres in."
|
||
|
||
form :action => R(Finish), :method => :post do
|
||
p do
|
||
label "E-mailadres", :for => "email"
|
||
input :type => "text", :name => "email"
|
||
end
|
||
p do
|
||
input :type => "checkbox", :name => "prize", :checked => true
|
||
label "Ik wil een vette prijs winnen!", :for => "prize"
|
||
end
|
||
p do
|
||
input :type => "checkbox", :name => "results", :checked => true
|
||
label "Ik ben een nieuwsgierig aagje en ik wil het naadje van je kous weten!", :for => "results"
|
||
end
|
||
|
||
p "Je e-mailadres wordt enkel gebruikt voor de enquête resultaten en "
|
||
"om je op de hoogte te stellen als je gewonnen hebt."
|
||
|
||
input :type => "submit", :value => "Verstuur"
|
||
end
|
||
end
|
||
|
||
def thanks
|
||
h2 "Bedankt!"
|
||
|
||
p "Je antwoorden zijn verstuurd."
|
||
end
|
||
|
||
end
|
||
|
||
# FIXME: Insert some TU/e styling here
|
||
__END__
|
||
/* Style sheet for the Anne Survey Camping app */
|
||
|
||
body {
|
||
color: white;
|
||
background-color: black;
|
||
}
|