From 5714af17c66f5b3d1e2a639a0824c395c6ffa2dd Mon Sep 17 00:00:00 2001 From: Richard Taylor Date: Thu, 29 Sep 2011 13:52:11 +0100 Subject: [PATCH] implemented challenge view page, added markdown support, added sample data --- Gemfile | 1 + Gemfile.lock | 2 + app/assets/stylesheets/application.css.scss | 4 +- app/controllers/home_controller.rb | 4 +- app/models/challenge.rb | 19 +++- app/models/user.rb | 2 + app/views/attempts/new.html.erb | 2 +- app/views/challenges/_disqus.html.erb | 20 ++++ app/views/challenges/show.html.erb | 30 +++++- app/views/home/index.html.erb | 12 ++- app/views/users/show.html.erb | 4 +- .../20110730114020_create_challenges.rb | 2 + db/seeds.rb | 95 ++++++++++++++++++- 13 files changed, 181 insertions(+), 16 deletions(-) create mode 100644 app/views/challenges/_disqus.html.erb diff --git a/Gemfile b/Gemfile index b85b5b9..a3ba356 100644 --- a/Gemfile +++ b/Gemfile @@ -15,6 +15,7 @@ gem 'colored' gem 'state_machine' gem 'rest-client' gem 'oa-oauth' +gem 'rdiscount' # To use debugger # gem 'ruby-debug19', :require => 'ruby-debug' diff --git a/Gemfile.lock b/Gemfile.lock index 39299df..f71d3d3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -105,6 +105,7 @@ GEM rdoc (~> 3.4) thor (~> 0.14.6) rake (0.9.2) + rdiscount (1.6.8) rdoc (3.8) rest-client (1.6.3) mime-types (>= 1.16) @@ -142,6 +143,7 @@ DEPENDENCIES oa-oauth pg rails (= 3.1.0.rc5) + rdiscount rest-client sass-rails (~> 3.1.0.rc) state_machine diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index f8cec82..a5794b2 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -76,4 +76,6 @@ h2 { font-size:16px; margin-top:10px; margin-bottom:10px; -} \ No newline at end of file +} + +p {margin-top:10px;} \ No newline at end of file diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 04bd18d..3bc122c 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -1,6 +1,6 @@ class HomeController < ApplicationController def index - @featured_challenge = Challenge.featured.first - @recent_challenges = Challenge.finished.limit(6).all - [@featured_challenge] + @active_challenges = Challenge.active + @past_challenges = Challenge.finished.limit(6).all end end diff --git a/app/models/challenge.rb b/app/models/challenge.rb index 326f4c9..c6ae705 100644 --- a/app/models/challenge.rb +++ b/app/models/challenge.rb @@ -12,8 +12,11 @@ class Challenge < ActiveRecord::Base validates_presence_of :title, :abstract, :level_id, :category_id, :platform_id, :user_id + default_scope :order => "activated_at DESC" + scope :community, where(:source => 'community') scope :admin, where(:source => 'admin') + scope :pending, where(:state => 'pending') scope :active, where(:state => 'active') scope :finished, where(:state => 'finished') scope :featured, where(:feature => true) @@ -46,8 +49,20 @@ class Challenge < ActiveRecord::Base self.state == 'reviewing' end - def open? - self.active? #and Time.now.utc > self.starts_at and Time.now.utc < self.ends_at + def reviewing? + self.state == 'judging' + end + + def open_for_submissions? + self.active? and Time.now.utc > self.activated_at and Time.now.utc < self.ends_at + end + + def open_for_voting? + open_for_comments? and (active? or reviewing? or judging?) + end + + def open_for_comments? + Time.now.utc > self.ends_at end def days_remaining diff --git a/app/models/user.rb b/app/models/user.rb index ada9f5a..d6776f3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -16,6 +16,8 @@ class User < ActiveRecord::Base attr_accessible :email, :password attr_accessible :judge, :admin, :reviewer, :as => :admin + scope :ordinary, where(:admin => false).where(:reviewer => false).where(:judge => false) + scope :admins, where(:admin => true) scope :reviewers, where(:reviewer => true) scope :judges, where(:judge => true) diff --git a/app/views/attempts/new.html.erb b/app/views/attempts/new.html.erb index 1ea8608..d274513 100644 --- a/app/views/attempts/new.html.erb +++ b/app/views/attempts/new.html.erb @@ -1,6 +1,6 @@

<%= @challenge.title %>

-

<%= @challenge.abstract %>

+

<%= raw RDiscount.new(@challenge.abstract).to_html %>

Submit your entry

diff --git a/app/views/challenges/_disqus.html.erb b/app/views/challenges/_disqus.html.erb new file mode 100644 index 0000000..c9229ed --- /dev/null +++ b/app/views/challenges/_disqus.html.erb @@ -0,0 +1,20 @@ +
+ + +blog comments powered by Disqus \ No newline at end of file diff --git a/app/views/challenges/show.html.erb b/app/views/challenges/show.html.erb index 68e0902..c29e372 100644 --- a/app/views/challenges/show.html.erb +++ b/app/views/challenges/show.html.erb @@ -1,17 +1,37 @@

<%= @challenge.title %>

-

<%= @challenge.abstract %>

+

State: <%= @challenge.state %> | Level: <%= @challenge.level.name %> | Category: <%= @challenge.category.name %> | Ends: <%= @challenge.ends_at.to_date.to_s(:long) %> | Created By: <%= link_to @challenge.user.username, @challenge.user %> | Official?: <%= @challenge.user.admin? %>

+ +

<%= raw RDiscount.new(@challenge.abstract).to_html %>

- <% if @challenge.open? %> + <% if @challenge.open_for_submissions? %> <%= link_to 'Enter your solution', new_challenge_attempt_path(@challenge) %> <% else %> This challenge is not currently accepting solutions <% end %>
-

Challenge attempts

+

Sponsors

-<% @challenge.attempts.each do |attempt| %> - <%= link_to gravatar_for(attempt.user.email), attempt.user %> +

<%= raw RDiscount.new(@challenge.sponsors).to_html if @challenge.sponsors %>

+ +

Prizes

+ +

<%= raw RDiscount.new(@challenge.prizes).to_html if @challenge.prizes %>

+ +<% if @challenge.open_for_comments? %> + +

Challenge attempts

+ + <% @challenge.attempts.each do |attempt| %> + <%= link_to gravatar_for(attempt.user.email), attempt.user %> + <% end %> + +

Comments

+ + <%= render :partial => 'disqus' %> + +<% else %> +

This challenge is not open to view attempts, comments or voting yet

<% end %> \ No newline at end of file diff --git a/app/views/home/index.html.erb b/app/views/home/index.html.erb index c01929f..bc39421 100644 --- a/app/views/home/index.html.erb +++ b/app/views/home/index.html.erb @@ -4,6 +4,14 @@

<%= @featured_challenge.abstract %>

<% end %> -<% @recent_challenges.each do |challenge| %> -
<%= challenge.title %> <%= challenge.ends_at.to_date.to_s(:long) %>
+

Active Challenges

+ +<% @active_challenges.each do |challenge| %> +
<%= link_to challenge.title, challenge %> Ends on <%= challenge.ends_at.to_date.to_s(:long) %>
+<% end %> + +

Past Challenges

+ +<% @past_challenges.each do |challenge| %> +
<%= link_to challenge.title, challenge %> <%= challenge.ends_at.to_date.to_s(:long) %>
<% end %> \ No newline at end of file diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 1e594b7..f11d05e 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -14,7 +14,7 @@

Twitter: <%= link_to @user.profile.twitter, "http://twitter.com/#{@user.profile.twitter.gsub(/^@/, '')}" %>

<% end %> -<% if current_user.profile.github? %> +<% if @user.profile.github? %>

GitHub: <%= link_to current_user.profile.github_username, current_user.profile.github_url %> | <%= current_user.profile.github_public_repo_count %> Public Repositories | @@ -22,7 +22,7 @@

<% end %> -<% if current_user.profile.twitter? %> +<% if @user.profile.twitter? %>

Twitter: <%= link_to "@#{current_user.profile.twitter_username}", "https://twitter.com/#{current_user.profile.twitter_username}" %>

<% end %> diff --git a/db/migrate/20110730114020_create_challenges.rb b/db/migrate/20110730114020_create_challenges.rb index 78b8644..467ed21 100644 --- a/db/migrate/20110730114020_create_challenges.rb +++ b/db/migrate/20110730114020_create_challenges.rb @@ -12,6 +12,8 @@ class CreateChallenges < ActiveRecord::Migration t.string :title, :null => false t.text :abstract, :null => false t.text :resources + t.text :sponsors + t.text :prizes t.datetime :activated_at t.boolean :feature, :default => false, :null => false diff --git a/db/seeds.rb b/db/seeds.rb index 18050a5..4936578 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -48,6 +48,14 @@ durations = [ ] durations.each{|x, y| Duration.create!(:name => x, :duration => y)} +# Admins +10.times do |i| + user = User.new(:email => "admin#{i}@mozdevchallenge.org", :password => 'admin') + user.admin = true + user.save! + Profile.create!(:user => user, :username => "admin#{i}", :name => "Admin #{i}") +end + # Reviewers 10.times do |i| user = User.new(:email => "reviewer#{i}@mozdevchallenge.org", :password => 'reviewer') @@ -62,4 +70,89 @@ end user.judge = true user.save! Profile.create!(:user => user, :username => "judge#{i}", :name => "Judge #{i}") -end \ No newline at end of file +end + +# Users +10.times do |i| + user = User.new(:email => "user#{i}@mozdevchallenge.org", :password => 'user') + user.save! + Profile.create!(:user => user, :username => "user#{i}", :name => "User #{i}") +end + +# Challenges + +challenges = [ + {:title =>'RSpec formatters', :abstract => 'RSpec has a bunch of formatters you can use when running your tests. The default is the "progress" formatter, which prints out a green dot for every spec tat passes and a red "F" for every spec that fails. There are more, like the "documentation" and "html" formatters. + + This week, the challenge is to create your own formatter for RSpec 2. Your solution should solve a problem you\'re facing with the existing formatters (like, I don\'t know how long my specs are going to take or I don\'t notice when my suite is done running) or you can do something completely crazy and funny. With rainbows, or something like that. Oh, and remember: You\'re not limited to terminal output, do whatever you can think of. + + Creating an RSpec formatter is quite straightforward. Be sure to check out the existing formatters, since you\'re probably going to extend one of those. For more information, you can check out the Fuubar source. + + When you\'re done, put your solution in a Gist, including a README.(markdown|textile) file to explain what it does, how it works and why it should win. Of course, you\'re encouraged to put a link to a demo video of your formatter in action in your Gist too. + + You have a week to enter, so that should be enough to think of something great. Good luck!'}, + {:title =>'Pixelizing images with ChunkyPNG', :abstract => 'Ever heard of ChunkyPNG? It\'s an amazing PNG manipulation library that is easy and fun to use. This week\'s challenge is to pixelize the image below, so your resulting image is built up from blocks of 10 by 10 pixels. Remember: you can\'t change the size of the image. + + If you\'ve never used ChunkyPNG before, check out the wiki, you can find some great examples in there. + + Again, put your solution in a Gist, together with your resulting image, like this example (please don\'t include the input image and don\'t fork the example gist). You can\'t add images using Gist\'s web interface, so you\'ll have to clone your Gist and add it using git. + + Like last week, you have a week to get your entry in, so I\'m sure you have enough time to write a great implementation. Good luck!'}, + {:title =>'Terminal admin', :abstract => "Codebrawl doesn't have a proper admin panel, so I tend to do content changes in the database directly using script/rails console. This gives me a lot of freedom, since I can do anything without having to build features for it in my admin panel first. Also, if Codebrawl had an admin panel, I'm absolutely sure I would have to dive into the console to do stuff every once in a while. + + Of course, there are some problems with the console when trying to quickly edit a record. Finding the right one requires you to type a query: + + c = Contest.first(:conditions => {:name => 'Terminal Admin'}) + Also, editing a field requires you to fill in the whole value every time: + + c.update_attribute(:description => 'Codebrawl doesn't have a proper...') + The challenge for this week is to think of something that makes this easier and faster. Tackle one problem (like finding records, for example) the best you can, but don't try to build a complete terminal admin. The idea is to combine good ideas into one project we can keep working on. + + Create a solution you can require into the console. It needs to hook into your ORM of choice (Codebrawl uses Mongoid, but you can build something for another ORM if you want), like in this example Gist. Also, don't forget to add a REAME file explaining how it works. + + No shirt, no shoes, no weapons. You have one week to get your entry in. Good luck!"} +] + +challenges.each do |challenge| + Challenge.create!( + :user => User.admins.all.sample, + :level => Level.all.sample, + :category => Category.all.sample, + :platform => Platform.all.sample, + :duration => Duration.all.sample, + :source => 'admin', + :title => challenge[:title], + :abstract => challenge[:abstract] + ) +end + +attempts = ['Attempt1', 'Attempt2', 'Attempt3'] + +# set one challenge as active +challenge = Challenge.pending.sample +challenge.activate! +attempts.each do |attempt| + challenge.attempts.create!( + :user => (User.ordinary - challenge.attempts.collect{|x| x.user}).sample, + :language => Language.all.sample, + :repository_url => 'http://github.com/', + :description => attempt + ) +end + +# set one challenge as active and open for comments +challenge = Challenge.pending.sample +challenge.activate! + +attempts.each do |attempt| + challenge.attempts.create!( + :user => (User.ordinary - challenge.attempts.collect{|x| x.user}).sample, + :language => Language.all.sample, + :repository_url => 'http://github.com/', + :description => attempt + ) +end + +challenge.update_attributes(:activated_at => Time.now.utc - challenge.duration.duration) + +