implemented challenge view page, added markdown support, added sample data

This commit is contained in:
Richard Taylor 2011-09-29 13:52:11 +01:00
Родитель e15b4cf2c1
Коммит 5714af17c6
13 изменённых файлов: 181 добавлений и 16 удалений

Просмотреть файл

@ -15,6 +15,7 @@ gem 'colored'
gem 'state_machine' gem 'state_machine'
gem 'rest-client' gem 'rest-client'
gem 'oa-oauth' gem 'oa-oauth'
gem 'rdiscount'
# To use debugger # To use debugger
# gem 'ruby-debug19', :require => 'ruby-debug' # gem 'ruby-debug19', :require => 'ruby-debug'

Просмотреть файл

@ -105,6 +105,7 @@ GEM
rdoc (~> 3.4) rdoc (~> 3.4)
thor (~> 0.14.6) thor (~> 0.14.6)
rake (0.9.2) rake (0.9.2)
rdiscount (1.6.8)
rdoc (3.8) rdoc (3.8)
rest-client (1.6.3) rest-client (1.6.3)
mime-types (>= 1.16) mime-types (>= 1.16)
@ -142,6 +143,7 @@ DEPENDENCIES
oa-oauth oa-oauth
pg pg
rails (= 3.1.0.rc5) rails (= 3.1.0.rc5)
rdiscount
rest-client rest-client
sass-rails (~> 3.1.0.rc) sass-rails (~> 3.1.0.rc)
state_machine state_machine

Просмотреть файл

@ -77,3 +77,5 @@ h2 {
margin-top:10px; margin-top:10px;
margin-bottom:10px; margin-bottom:10px;
} }
p {margin-top:10px;}

Просмотреть файл

@ -1,6 +1,6 @@
class HomeController < ApplicationController class HomeController < ApplicationController
def index def index
@featured_challenge = Challenge.featured.first @active_challenges = Challenge.active
@recent_challenges = Challenge.finished.limit(6).all - [@featured_challenge] @past_challenges = Challenge.finished.limit(6).all
end end
end end

Просмотреть файл

@ -12,8 +12,11 @@ class Challenge < ActiveRecord::Base
validates_presence_of :title, :abstract, :level_id, :category_id, :platform_id, :user_id 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 :community, where(:source => 'community')
scope :admin, where(:source => 'admin') scope :admin, where(:source => 'admin')
scope :pending, where(:state => 'pending')
scope :active, where(:state => 'active') scope :active, where(:state => 'active')
scope :finished, where(:state => 'finished') scope :finished, where(:state => 'finished')
scope :featured, where(:feature => true) scope :featured, where(:feature => true)
@ -46,8 +49,20 @@ class Challenge < ActiveRecord::Base
self.state == 'reviewing' self.state == 'reviewing'
end end
def open? def reviewing?
self.active? #and Time.now.utc > self.starts_at and Time.now.utc < self.ends_at 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 end
def days_remaining def days_remaining

Просмотреть файл

@ -16,6 +16,8 @@ class User < ActiveRecord::Base
attr_accessible :email, :password attr_accessible :email, :password
attr_accessible :judge, :admin, :reviewer, :as => :admin 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 :reviewers, where(:reviewer => true)
scope :judges, where(:judge => true) scope :judges, where(:judge => true)

Просмотреть файл

@ -1,6 +1,6 @@
<h1><%= @challenge.title %></h1> <h1><%= @challenge.title %></h1>
<p><%= @challenge.abstract %></p> <p><%= raw RDiscount.new(@challenge.abstract).to_html %></p>
<h1>Submit your entry</h1> <h1>Submit your entry</h1>

Просмотреть файл

@ -0,0 +1,20 @@
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'mozchallenge'; // required: replace example with your forum shortname
<% if Rails.env.development? %>var disqus_developer = 1;<% end %>
var disqus_identifier = 'mozdev_challenge_<%= @challenge.id %>';
var disqus_url = '<%= url_for(@challenge) %>';
var disqus_title = '<%= @challenge.title %>';
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">blog comments powered by <span class="logo-disqus">Disqus</span></a>

Просмотреть файл

@ -1,17 +1,37 @@
<h1><%= @challenge.title %></h1> <h1><%= @challenge.title %></h1>
<p><%= @challenge.abstract %></p> <p>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? %></p>
<p><%= raw RDiscount.new(@challenge.abstract).to_html %></p>
<div> <div>
<% if @challenge.open? %> <% if @challenge.open_for_submissions? %>
<%= link_to 'Enter your solution', new_challenge_attempt_path(@challenge) %> <%= link_to 'Enter your solution', new_challenge_attempt_path(@challenge) %>
<% else %> <% else %>
<i>This challenge is not currently accepting solutions</i> <i>This challenge is not currently accepting solutions</i>
<% end %> <% end %>
</div> </div>
<h2>Sponsors</h2>
<p><%= raw RDiscount.new(@challenge.sponsors).to_html if @challenge.sponsors %></p>
<h2>Prizes</h2>
<p><%= raw RDiscount.new(@challenge.prizes).to_html if @challenge.prizes %></p>
<% if @challenge.open_for_comments? %>
<h2>Challenge attempts</h2> <h2>Challenge attempts</h2>
<% @challenge.attempts.each do |attempt| %> <% @challenge.attempts.each do |attempt| %>
<%= link_to gravatar_for(attempt.user.email), attempt.user %> <%= link_to gravatar_for(attempt.user.email), attempt.user %>
<% end %> <% end %>
<h2>Comments</h2>
<%= render :partial => 'disqus' %>
<% else %>
<p>This challenge is not open to view attempts, comments or voting yet</p>
<% end %>

Просмотреть файл

@ -4,6 +4,14 @@
<p><%= @featured_challenge.abstract %></p> <p><%= @featured_challenge.abstract %></p>
<% end %> <% end %>
<% @recent_challenges.each do |challenge| %> <h2>Active Challenges</h2>
<div><%= challenge.title %> <%= challenge.ends_at.to_date.to_s(:long) %></div>
<% @active_challenges.each do |challenge| %>
<div><%= link_to challenge.title, challenge %> Ends on <%= challenge.ends_at.to_date.to_s(:long) %></div>
<% end %>
<h2>Past Challenges</h2>
<% @past_challenges.each do |challenge| %>
<div><%= link_to challenge.title, challenge %> <%= challenge.ends_at.to_date.to_s(:long) %></div>
<% end %> <% end %>

Просмотреть файл

@ -14,7 +14,7 @@
<p>Twitter: <%= link_to @user.profile.twitter, "http://twitter.com/#{@user.profile.twitter.gsub(/^@/, '')}" %></p> <p>Twitter: <%= link_to @user.profile.twitter, "http://twitter.com/#{@user.profile.twitter.gsub(/^@/, '')}" %></p>
<% end %> <% end %>
<% if current_user.profile.github? %> <% if @user.profile.github? %>
<p> <p>
GitHub: <%= link_to current_user.profile.github_username, current_user.profile.github_url %> | GitHub: <%= link_to current_user.profile.github_username, current_user.profile.github_url %> |
<%= current_user.profile.github_public_repo_count %> Public Repositories | <%= current_user.profile.github_public_repo_count %> Public Repositories |
@ -22,7 +22,7 @@
</p> </p>
<% end %> <% end %>
<% if current_user.profile.twitter? %> <% if @user.profile.twitter? %>
<p>Twitter: <%= link_to "@#{current_user.profile.twitter_username}", "https://twitter.com/#{current_user.profile.twitter_username}" %></p> <p>Twitter: <%= link_to "@#{current_user.profile.twitter_username}", "https://twitter.com/#{current_user.profile.twitter_username}" %></p>
<% end %> <% end %>

Просмотреть файл

@ -12,6 +12,8 @@ class CreateChallenges < ActiveRecord::Migration
t.string :title, :null => false t.string :title, :null => false
t.text :abstract, :null => false t.text :abstract, :null => false
t.text :resources t.text :resources
t.text :sponsors
t.text :prizes
t.datetime :activated_at t.datetime :activated_at
t.boolean :feature, :default => false, :null => false t.boolean :feature, :default => false, :null => false

Просмотреть файл

@ -48,6 +48,14 @@ durations = [
] ]
durations.each{|x, y| Duration.create!(:name => x, :duration => y)} 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 # Reviewers
10.times do |i| 10.times do |i|
user = User.new(:email => "reviewer#{i}@mozdevchallenge.org", :password => 'reviewer') user = User.new(:email => "reviewer#{i}@mozdevchallenge.org", :password => 'reviewer')
@ -63,3 +71,88 @@ end
user.save! user.save!
Profile.create!(:user => user, :username => "judge#{i}", :name => "Judge #{i}") Profile.create!(:user => user, :username => "judge#{i}", :name => "Judge #{i}")
end 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)