implemented challenge view page, added markdown support, added sample data
This commit is contained in:
Родитель
e15b4cf2c1
Коммит
5714af17c6
1
Gemfile
1
Gemfile
|
@ -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
|
||||||
|
|
||||||
|
|
93
db/seeds.rb
93
db/seeds.rb
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче