Skip to content
Browse files

too many changes for one commit

  • Loading branch information...
1 parent 5a9bc5e commit b539e91c64ae342cc61b681eb96b7abe0f72d020 @hajder hajder committed May 10, 2011
Showing with 2,141 additions and 2 deletions.
  1. +4 −1 Gemfile
  2. +84 −0 Gemfile.lock
  3. +1 −0 app/controllers/application_controller.rb
  4. +109 −0 app/controllers/deals_controller.rb
  5. +83 −0 app/controllers/partners_controller.rb
  6. +83 −0 app/controllers/users_controller.rb
  7. +2 −0 app/helpers/deals_helper.rb
  8. +2 −0 app/helpers/partners_helper.rb
  9. +2 −0 app/helpers/users_helper.rb
  10. +51 −0 app/models/deal.rb
  11. +13 −0 app/models/partner.rb
  12. +11 −0 app/models/user.rb
  13. +8 −0 app/models/users_deals.rb
  14. +45 −0 app/views/deals/_form.html.erb
  15. +6 −0 app/views/deals/edit.html.erb
  16. +33 −0 app/views/deals/index.html.erb
  17. +5 −0 app/views/deals/new.html.erb
  18. +17 −0 app/views/deals/none.html.haml
  19. +35 −0 app/views/deals/show.html.erb
  20. +48 −0 app/views/deals/showcase.html.haml
  21. +29 −0 app/views/deals/take.html.haml
  22. 0 app/views/deals/taken.html.haml
  23. +12 −0 app/views/devise/confirmations/new.html.erb
  24. +5 −0 app/views/devise/mailer/confirmation_instructions.html.erb
  25. +8 −0 app/views/devise/mailer/reset_password_instructions.html.erb
  26. +7 −0 app/views/devise/mailer/unlock_instructions.html.erb
  27. +16 −0 app/views/devise/passwords/edit.html.erb
  28. +12 −0 app/views/devise/passwords/new.html.erb
  29. +25 −0 app/views/devise/registrations/edit.html.erb
  30. +18 −0 app/views/devise/registrations/new.html.erb
  31. +23 −0 app/views/devise/sessions/new.html.haml
  32. +25 −0 app/views/devise/shared/_links.erb
  33. +12 −0 app/views/devise/unlocks/new.html.erb
  34. +23 −0 app/views/layouts/application.html.haml
  35. +29 −0 app/views/partners/_form.html.erb
  36. +6 −0 app/views/partners/edit.html.erb
  37. +27 −0 app/views/partners/index.html.erb
  38. +5 −0 app/views/partners/new.html.erb
  39. +20 −0 app/views/partners/show.html.erb
  40. +25 −0 app/views/users/_form.html.erb
  41. +6 −0 app/views/users/edit.html.erb
  42. +25 −0 app/views/users/index.html.erb
  43. +5 −0 app/views/users/new.html.erb
  44. +15 −0 app/views/users/show.html.erb
  45. +1 −0 config/environments/development.rb
  46. +194 −0 config/initializers/devise.rb
  47. +50 −0 config/locales/devise.en.yml
  48. +14 −1 config/routes.rb
  49. +21 −0 db/migrate/20110419161208_create_deals.rb
  50. +15 −0 db/migrate/20110419161241_create_partners.rb
  51. +15 −0 db/migrate/20110419161524_create_users.rb
  52. +16 −0 db/migrate/20110419161840_create_users_deals.rb
  53. +28 −0 db/migrate/20110507163157_devise_create_users.rb
  54. +64 −0 db/schema.rb
  55. +27 −0 groupon.tmproj
  56. +374 −0 public/stylesheets/960.css
  57. +63 −0 public/stylesheets/scaffold.css
  58. +17 −0 test/fixtures/deals.yml
  59. +11 −0 test/fixtures/partners.yml
  60. +9 −0 test/fixtures/users.yml
  61. +11 −0 test/fixtures/users_deals.yml
  62. +49 −0 test/functional/deals_controller_test.rb
  63. +49 −0 test/functional/partners_controller_test.rb
  64. +49 −0 test/functional/users_controller_test.rb
  65. +8 −0 test/unit/deal_test.rb
  66. +4 −0 test/unit/helpers/deals_helper_test.rb
  67. +4 −0 test/unit/helpers/partners_helper_test.rb
  68. +4 −0 test/unit/helpers/users_helper_test.rb
  69. +8 −0 test/unit/partner_test.rb
  70. +8 −0 test/unit/user_test.rb
  71. +8 −0 test/unit/users_deals_test.rb
View
5 Gemfile
@@ -1,11 +1,12 @@
source 'http://rubygems.org'
-gem 'rails', '3.0.6'
+gem 'rails'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'sqlite3'
+gem 'haml'
# Use unicorn as the web server
# gem 'unicorn'
@@ -29,3 +30,5 @@ gem 'sqlite3'
# group :development, :test do
# gem 'webrat'
# end
+
+gem 'devise'
View
84 Gemfile.lock
@@ -0,0 +1,84 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ abstract (1.0.0)
+ actionmailer (3.0.6)
+ actionpack (= 3.0.6)
+ mail (~> 2.2.15)
+ actionpack (3.0.6)
+ activemodel (= 3.0.6)
+ activesupport (= 3.0.6)
+ builder (~> 2.1.2)
+ erubis (~> 2.6.6)
+ i18n (~> 0.5.0)
+ rack (~> 1.2.1)
+ rack-mount (~> 0.6.14)
+ rack-test (~> 0.5.7)
+ tzinfo (~> 0.3.23)
+ activemodel (3.0.6)
+ activesupport (= 3.0.6)
+ builder (~> 2.1.2)
+ i18n (~> 0.5.0)
+ activerecord (3.0.6)
+ activemodel (= 3.0.6)
+ activesupport (= 3.0.6)
+ arel (~> 2.0.2)
+ tzinfo (~> 0.3.23)
+ activeresource (3.0.6)
+ activemodel (= 3.0.6)
+ activesupport (= 3.0.6)
+ activesupport (3.0.6)
+ arel (2.0.9)
+ bcrypt-ruby (2.1.4)
+ builder (2.1.2)
+ devise (1.3.4)
+ bcrypt-ruby (~> 2.1.2)
+ orm_adapter (~> 0.0.3)
+ warden (~> 1.0.3)
+ erubis (2.6.6)
+ abstract (>= 1.0.0)
+ haml (3.1.1)
+ i18n (0.5.0)
+ mail (2.2.15)
+ activesupport (>= 2.3.6)
+ i18n (>= 0.4.0)
+ mime-types (~> 1.16)
+ treetop (~> 1.4.8)
+ mime-types (1.16)
+ orm_adapter (0.0.4)
+ polyglot (0.3.1)
+ rack (1.2.2)
+ rack-mount (0.6.14)
+ rack (>= 1.0.0)
+ rack-test (0.5.7)
+ rack (>= 1.0)
+ rails (3.0.6)
+ actionmailer (= 3.0.6)
+ actionpack (= 3.0.6)
+ activerecord (= 3.0.6)
+ activeresource (= 3.0.6)
+ activesupport (= 3.0.6)
+ bundler (~> 1.0)
+ railties (= 3.0.6)
+ railties (3.0.6)
+ actionpack (= 3.0.6)
+ activesupport (= 3.0.6)
+ rake (>= 0.8.7)
+ thor (~> 0.14.4)
+ rake (0.8.7)
+ sqlite3 (1.3.3)
+ thor (0.14.6)
+ treetop (1.4.9)
+ polyglot (>= 0.3.1)
+ tzinfo (0.3.26)
+ warden (1.0.4)
+ rack (>= 1.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ devise
+ haml
+ rails
+ sqlite3
View
1 app/controllers/application_controller.rb
@@ -1,3 +1,4 @@
class ApplicationController < ActionController::Base
protect_from_forgery
+
end
View
109 app/controllers/deals_controller.rb
@@ -0,0 +1,109 @@
+class DealsController < ApplicationController
+ # GET /deals
+ # GET /deals.xml
+
+ before_filter :authenticate_user!, :only => [:take, :taken]
+
+ def index
+ @deals = Deal.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @deals }
+ end
+ end
+
+ def showcase
+ @featured = Deal.where("featured = ? and start < ? and finish > ?", true, Time.now, Time.now)[0]
+ @additional = Deal.where("featured = ? and start < ? and finish > ?", false, Time.now, Time.now)
+ render :action => "none" if @featured.nil? and @additional.empty?
+ @featured = @additional.shift if @featured.nil?
+ end
+
+ def none
+
+ end
+
+ def take
+ @deal = Deal.find(params[:id])
+ end
+
+ def taken
+ UsersDeals.new(:user_id => current_user.id, :deal_id => params[:id], :promocode => current_user.email).save
+ end
+
+ # GET /deals/1
+ # GET /deals/1.xml
+ def show
+ @deal = Deal.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.xml { render :xml => @deal }
+ end
+ end
+
+ # GET /deals/new
+ # GET /deals/new.xml
+ def new
+ @deal = Deal.new
+ @partners = Partner.all
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @deal }
+ end
+ end
+
+ # GET /deals/1/edit
+ def edit
+ @deal = Deal.find(params[:id])
+ @partners = Partner.all
+ end
+
+ # POST /deals
+ # POST /deals.xml
+ def create
+ @deal = Deal.new(params[:deal])
+ @partners = Partner.all
+
+ respond_to do |format|
+ if @deal.save
+ format.html { redirect_to(@deal, :notice => 'Deal was successfully created.') }
+ format.xml { render :xml => @deal, :status => :created, :location => @deal }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @deal.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /deals/1
+ # PUT /deals/1.xml
+ def update
+ @deal = Deal.find(params[:id])
+ @partners = Partner.all
+
+ respond_to do |format|
+ if @deal.update_attributes(params[:deal])
+ format.html { redirect_to(@deal, :notice => 'Deal was successfully updated.') }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @deal.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /deals/1
+ # DELETE /deals/1.xml
+ def destroy
+ @deal = Deal.find(params[:id])
+ @deal.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(deals_url) }
+ format.xml { head :ok }
+ end
+ end
+end
View
83 app/controllers/partners_controller.rb
@@ -0,0 +1,83 @@
+class PartnersController < ApplicationController
+ # GET /partners
+ # GET /partners.xml
+ def index
+ @partners = Partner.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @partners }
+ end
+ end
+
+ # GET /partners/1
+ # GET /partners/1.xml
+ def show
+ @partner = Partner.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.xml { render :xml => @partner }
+ end
+ end
+
+ # GET /partners/new
+ # GET /partners/new.xml
+ def new
+ @partner = Partner.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @partner }
+ end
+ end
+
+ # GET /partners/1/edit
+ def edit
+ @partner = Partner.find(params[:id])
+ end
+
+ # POST /partners
+ # POST /partners.xml
+ def create
+ @partner = Partner.new(params[:partner])
+
+ respond_to do |format|
+ if @partner.save
+ format.html { redirect_to(@partner, :notice => 'Partner was successfully created.') }
+ format.xml { render :xml => @partner, :status => :created, :location => @partner }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @partner.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /partners/1
+ # PUT /partners/1.xml
+ def update
+ @partner = Partner.find(params[:id])
+
+ respond_to do |format|
+ if @partner.update_attributes(params[:partner])
+ format.html { redirect_to(@partner, :notice => 'Partner was successfully updated.') }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @partner.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /partners/1
+ # DELETE /partners/1.xml
+ def destroy
+ @partner = Partner.find(params[:id])
+ @partner.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(partners_url) }
+ format.xml { head :ok }
+ end
+ end
+end
View
83 app/controllers/users_controller.rb
@@ -0,0 +1,83 @@
+class UsersController < ApplicationController
+ # GET /users
+ # GET /users.xml
+ def index
+ @users = User.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @users }
+ end
+ end
+
+ # GET /users/1
+ # GET /users/1.xml
+ def show
+ @user = User.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.xml { render :xml => @user }
+ end
+ end
+
+ # GET /users/new
+ # GET /users/new.xml
+ def new
+ @user = User.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @user }
+ end
+ end
+
+ # GET /users/1/edit
+ def edit
+ @user = User.find(params[:id])
+ end
+
+ # POST /users
+ # POST /users.xml
+ def create
+ @user = User.new(params[:user])
+
+ respond_to do |format|
+ if @user.save
+ format.html { redirect_to(@user, :notice => 'User was successfully created.') }
+ format.xml { render :xml => @user, :status => :created, :location => @user }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /users/1
+ # PUT /users/1.xml
+ def update
+ @user = User.find(params[:id])
+
+ respond_to do |format|
+ if @user.update_attributes(params[:user])
+ format.html { redirect_to(@user, :notice => 'User was successfully updated.') }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /users/1
+ # DELETE /users/1.xml
+ def destroy
+ @user = User.find(params[:id])
+ @user.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(users_url) }
+ format.xml { head :ok }
+ end
+ end
+end
View
2 app/helpers/deals_helper.rb
@@ -0,0 +1,2 @@
+module DealsHelper
+end
View
2 app/helpers/partners_helper.rb
@@ -0,0 +1,2 @@
+module PartnersHelper
+end
View
2 app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
View
51 app/models/deal.rb
@@ -0,0 +1,51 @@
+class Deal < ActiveRecord::Base
+ has_many :users_deals
+ has_many :users, :through => :users_deals
+ belongs_to :partner
+
+ validates_presence_of :name, :description, :partner_id
+ validates_numericality_of :price, :greater_than => 0
+ validate :only_featured_for_given_period
+ validate :start_in_future
+ validate :finish_after_start
+ validate :min_lenght_24_hours
+ validate :partner_exists
+
+ def before_validation
+ if self.persisted? and self.start <= Time.now
+ errors.add(:deal, "changes not allowed after deal start")
+ return false
+ end
+ end
+
+ private
+ def only_featured_for_given_period
+ errors.add(:start, "there's already another featured deal for given period of time") if
+ featured and
+ ( Deal.where("featured = ? and start <= ? and finish > ? and id != ?", true, start, start, id).count > 0 or
+ Deal.where("featured = ? and start < ? and finish >= ? and id != ?", true, finish, finish, id).count > 0 )
+ end
+
+ def start_in_future
+ errors.add(:start, "deal have to start minumum two hours from how") if
+ start < Time.now + 2.hours
+ end
+
+ def finish_after_start
+ errors.add(:finish, "deal end must be after start, and the deal must last for minimum of 24 hours") if
+ (finish-start) < 0
+ end
+
+ def min_lenght_24_hours
+ errors.add(:finish, "deal must last for at least 24 hours") unless
+ (finish-start) > 24*60*60
+ end
+
+ def partner_exists
+ begin
+ Partner.find(partner_id) unless partner_id.nil?
+ rescue
+ errors.add(:partner_id, "doesn't exist")
+ end
+ end
+end
View
13 app/models/partner.rb
@@ -0,0 +1,13 @@
+class Partner < ActiveRecord::Base
+ has_many :deals
+
+ def before_validation
+ begin
+ uri = URI.parse(url)
+ p uri.normalize
+ rescue => e
+ p e
+ errors.add(:url, 'Invalid url')
+ end
+ end
+end
View
11 app/models/user.rb
@@ -0,0 +1,11 @@
+class User < ActiveRecord::Base
+ # Include default devise modules. Others available are:
+ # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
+ devise :database_authenticatable, :registerable,
+ :recoverable, :rememberable, :trackable, :validatable
+
+ # Setup accessible (or protected) attributes for your model
+ attr_accessible :email, :password, :password_confirmation, :remember_me
+ has_many :users_deals
+ has_many :deals, :through => :users_deals
+end
View
8 app/models/users_deals.rb
@@ -0,0 +1,8 @@
+class UsersDeals < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :deal
+
+ def before_create
+ self.promocode = Digest::SHA1.hexdigest(Time.now.to_s + promocode).slice(0..10)
+ end
+end
View
45 app/views/deals/_form.html.erb
@@ -0,0 +1,45 @@
+<%= form_for(@deal) do |f| %>
+ <% if @deal.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(@deal.errors.count, "error") %> prohibited this deal from being saved:</h2>
+
+ <ul>
+ <% @deal.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="field">
+ <%= f.label :name %><br />
+ <%= f.text_field :name %>
+ </div>
+ <div class="field">
+ <%= f.label :start %><br />
+ <%= f.datetime_select :start %>
+ </div>
+ <div class="field">
+ <%= f.label :finish %><br />
+ <%= f.datetime_select :finish %>
+ </div>
+ <div class="field">
+ <%= f.label :price %><br />
+ <%= f.text_field :price %>
+ </div>
+ <div class="field">
+ <%= f.label :description %><br />
+ <%= f.text_field :description %>
+ </div>
+ <div class="field">
+ <%= f.label :partner_id %><br />
+ <%= f.select :partner_id, @partners.collect { |p| [p.name, p.id] }, { :include_blank => true } %>
+ </div>
+ <div class="field">
+ <%= f.label :featured %><br />
+ <%= f.check_box :featured %>
+ </div>
+ <div class="actions">
+ <%= f.submit %>
+ </div>
+<% end %>
View
6 app/views/deals/edit.html.erb
@@ -0,0 +1,6 @@
+<h1>Editing deal</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', @deal %> |
+<%= link_to 'Back', deals_path %>
View
33 app/views/deals/index.html.erb
@@ -0,0 +1,33 @@
+<h1>Listing deals</h1>
+
+<table>
+ <tr>
+ <th>Name</th>
+ <th>Start</th>
+ <th>End</th>
+ <th>Price</th>
+ <th>Description</th>
+ <th>Partner</th>
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+<% @deals.each do |deal| %>
+ <tr>
+ <td><%= deal.name %></td>
+ <td><%= deal.start %></td>
+ <td><%= deal.finish %></td>
+ <td><%= deal.price %></td>
+ <td><%= deal.description %></td>
+ <td><%= deal.partner_id %></td>
+ <td><%= link_to 'Show', deal %></td>
+ <td><%= link_to 'Edit', edit_deal_path(deal) %></td>
+ <td><%= link_to 'Destroy', deal, :confirm => 'Are you sure?', :method => :delete %></td>
+ </tr>
+<% end %>
+</table>
+
+<br />
+
+<%= link_to 'New Deal', new_deal_path %>
View
5 app/views/deals/new.html.erb
@@ -0,0 +1,5 @@
+<h1>New deal</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Back', deals_path %>
View
17 app/views/deals/none.html.haml
@@ -0,0 +1,17 @@
+%div.container.container_12
+ %div.grid_12.header
+ &nbsp;
+ %h2.grid_12
+ Yet another groupon clone
+ %div.grid_1
+ &nbsp;
+ %div.grid_10
+ %div
+ No deals for now, sorry!
+ %div.grid_1
+ &nbsp;
+ %div.clear
+ %div.grid_12.footer
+ &nbsp;
+ %div.clear
+
View
35 app/views/deals/show.html.erb
@@ -0,0 +1,35 @@
+<p id="notice"><%= notice %></p>
+
+<p>
+ <b>Name:</b>
+ <%= @deal.name %>
+</p>
+
+<p>
+ <b>Start:</b>
+ <%= @deal.start %>
+</p>
+
+<p>
+ <b>End:</b>
+ <%= @deal.finish %>
+</p>
+
+<p>
+ <b>Price:</b>
+ <%= @deal.price %>
+</p>
+
+<p>
+ <b>Description:</b>
+ <%= @deal.description %>
+</p>
+
+<p>
+ <b>Partner:</b>
+ <%= @deal.partner_id %>
+</p>
+
+
+<%= link_to 'Edit', edit_deal_path(@deal) %> |
+<%= link_to 'Back', deals_path %>
View
48 app/views/deals/showcase.html.haml
@@ -0,0 +1,48 @@
+%div.grid_8
+ %div.featured
+ %h3
+ Featured deal
+ %p
+ %b Name:
+ = @featured.name
+ %p
+ %b Ends in:
+ - secs = @featured.finish - Time.now
+ = (secs / (3600*24)).floor.to_s + " days "
+ = (secs % (3600*24) / 3600).floor.to_s + "h"
+ = (secs % 3600 / 60).floor.to_s + "\'"
+ = (secs % 60).floor.to_s + "\""
+ %p
+ %b Price:
+ = @featured.price
+ %p
+ %b More about this deal:
+ = @featured.description
+ %p
+ %b Deal by:
+ %a{:href => @featured.partner.url, :target => '_blank'}
+ = @featured.partner.name
+ %p
+ %a{:href => take_deal_path(@featured.id)} Take it!
+- @additional.each do |deal|
+ %div.grid_4
+ %div.additional
+ %h3
+ Other deals
+ %p
+ %b Name:
+ = deal.name
+ %p
+ %b End:
+ = deal.finish
+ %p
+ %b Price:
+ = deal.price
+ %p
+ %b Description:
+ = deal.description
+ %p
+ %b Partner:
+ %a{:href => deal.partner.url, :target => '_blank'}
+ = deal.partner.name
+%div.clear
View
29 app/views/deals/take.html.haml
@@ -0,0 +1,29 @@
+%div.grid_2
+ &nbsp;
+%div.grid_8
+ %h3 You're about to make a great deal!
+ %p
+ %b Name:
+ = @deal.name
+ %p
+ %b Ends in:
+ - secs = @deal.finish - Time.now
+ = (secs / (3600*24)).floor.to_s + " days "
+ = (secs % (3600*24) / 3600).floor.to_s + "h"
+ = (secs % 3600 / 60).floor.to_s + "\'"
+ = (secs % 60).floor.to_s + "\""
+ %p
+ %b Price:
+ = @deal.price
+ %p
+ %b More about this deal:
+ = @deal.description
+ %p
+ %b Deal from:
+ %a{:href => @deal.partner.url, :target => '_blank'}
+ = @deal.partner.name
+ %p
+ %a{:href => taken_deal_path(@deal.id)} Sure, give it to me!
+%div.grid_2
+ &nbsp;
+%div.clear
View
0 app/views/deals/taken.html.haml
No changes.
View
12 app/views/devise/confirmations/new.html.erb
@@ -0,0 +1,12 @@
+<h2>Resend confirmation instructions</h2>
+
+<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
+ <%= devise_error_messages! %>
+
+ <p><%= f.label :email %><br />
+ <%= f.email_field :email %></p>
+
+ <p><%= f.submit "Resend confirmation instructions" %></p>
+<% end %>
+
+<%= render :partial => "devise/shared/links" %>
View
5 app/views/devise/mailer/confirmation_instructions.html.erb
@@ -0,0 +1,5 @@
+<p>Welcome <%= @resource.email %>!</p>
+
+<p>You can confirm your account through the link below:</p>
+
+<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %></p>
View
8 app/views/devise/mailer/reset_password_instructions.html.erb
@@ -0,0 +1,8 @@
+<p>Hello <%= @resource.email %>!</p>
+
+<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
+
+<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %></p>
+
+<p>If you didn't request this, please ignore this email.</p>
+<p>Your password won't change until you access the link above and create a new one.</p>
View
7 app/views/devise/mailer/unlock_instructions.html.erb
@@ -0,0 +1,7 @@
+<p>Hello <%= @resource.email %>!</p>
+
+<p>Your account has been locked due to an excessive amount of unsuccessful sign in attempts.</p>
+
+<p>Click the link below to unlock your account:</p>
+
+<p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %></p>
View
16 app/views/devise/passwords/edit.html.erb
@@ -0,0 +1,16 @@
+<h2>Change your password</h2>
+
+<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
+ <%= devise_error_messages! %>
+ <%= f.hidden_field :reset_password_token %>
+
+ <p><%= f.label :password, "New password" %><br />
+ <%= f.password_field :password %></p>
+
+ <p><%= f.label :password_confirmation, "Confirm new password" %><br />
+ <%= f.password_field :password_confirmation %></p>
+
+ <p><%= f.submit "Change my password" %></p>
+<% end %>
+
+<%= render :partial => "devise/shared/links" %>
View
12 app/views/devise/passwords/new.html.erb
@@ -0,0 +1,12 @@
+<h2>Forgot your password?</h2>
+
+<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %>
+ <%= devise_error_messages! %>
+
+ <p><%= f.label :email %><br />
+ <%= f.email_field :email %></p>
+
+ <p><%= f.submit "Send me reset password instructions" %></p>
+<% end %>
+
+<%= render :partial => "devise/shared/links" %>
View
25 app/views/devise/registrations/edit.html.erb
@@ -0,0 +1,25 @@
+<h2>Edit <%= resource_name.to_s.humanize %></h2>
+
+<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
+ <%= devise_error_messages! %>
+
+ <p><%= f.label :email %><br />
+ <%= f.email_field :email %></p>
+
+ <p><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
+ <%= f.password_field :password %></p>
+
+ <p><%= f.label :password_confirmation %><br />
+ <%= f.password_field :password_confirmation %></p>
+
+ <p><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
+ <%= f.password_field :current_password %></p>
+
+ <p><%= f.submit "Update" %></p>
+<% end %>
+
+<h3>Cancel my account</h3>
+
+<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.</p>
+
+<%= link_to "Back", :back %>
View
18 app/views/devise/registrations/new.html.erb
@@ -0,0 +1,18 @@
+<h2>Sign up</h2>
+
+<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
+ <%= devise_error_messages! %>
+
+ <p><%= f.label :email %><br />
+ <%= f.email_field :email %></p>
+
+ <p><%= f.label :password %><br />
+ <%= f.password_field :password %></p>
+
+ <p><%= f.label :password_confirmation %><br />
+ <%= f.password_field :password_confirmation %></p>
+
+ <p><%= f.submit "Sign up" %></p>
+<% end %>
+
+<%= render :partial => "devise/shared/links" %>
View
23 app/views/devise/sessions/new.html.haml
@@ -0,0 +1,23 @@
+%div.grid_3
+ &nbsp;
+%div.grid_4
+ %div.auth
+ %h3 Sign in
+ = form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f|
+ %p
+ = f.label :email
+ %br/
+ = f.email_field :email
+ %p
+ = f.label :password
+ %br/
+ = f.password_field :password
+ - if devise_mapping.rememberable?
+ %p
+ = f.check_box :remember_me
+ = f.label :remember_me
+ %p= f.submit "Sign in"
+ = render :partial => "devise/shared/links"
+%div.grid_5
+ &nbsp;
+%div.clear
View
25 app/views/devise/shared/_links.erb
@@ -0,0 +1,25 @@
+<%- if controller_name != 'sessions' %>
+ <%= link_to "Sign in", new_session_path(resource_name) %><br />
+<% end -%>
+
+<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
+ <%= link_to "Sign up", new_registration_path(resource_name) %><br />
+<% end -%>
+
+<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
+ <%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
+<% end -%>
+
+<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
+ <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
+<% end -%>
+
+<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
+ <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
+<% end -%>
+
+<%- if devise_mapping.omniauthable? %>
+ <%- resource_class.omniauth_providers.each do |provider| %>
+ <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
+ <% end -%>
+<% end -%>
View
12 app/views/devise/unlocks/new.html.erb
@@ -0,0 +1,12 @@
+<h2>Resend unlock instructions</h2>
+
+<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
+ <%= devise_error_messages! %>
+
+ <p><%= f.label :email %><br />
+ <%= f.email_field :email %></p>
+
+ <p><%= f.submit "Resend unlock instructions" %></p>
+<% end %>
+
+<%= render :partial => "devise/shared/links" %>
View
23 app/views/layouts/application.html.haml
@@ -0,0 +1,23 @@
+!!!
+%html
+ %head
+ %title Groupon
+ = stylesheet_link_tag :all
+ = javascript_include_tag :defaults
+ = csrf_meta_tag
+ %body
+ %div.container.container_12
+ %div.container_12.header
+ - if user_signed_in?
+ = link_to "My account", user_path(current_user)
+ |
+ = link_to "Sign out", destroy_user_session_path
+ - else
+ = link_to "Sign in", new_user_session_path
+ %h2.grid_12
+ Yet another groupon clone
+ %div.clear
+ = yield
+ %div.grid_12.footer
+ &nbsp;
+ %div.clear
View
29 app/views/partners/_form.html.erb
@@ -0,0 +1,29 @@
+<%= form_for(@partner) do |f| %>
+ <% if @partner.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(@partner.errors.count, "error") %> prohibited this partner from being saved:</h2>
+
+ <ul>
+ <% @partner.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="field">
+ <%= f.label :name %><br />
+ <%= f.text_field :name %>
+ </div>
+ <div class="field">
+ <%= f.label :url %><br />
+ <%= f.text_field :url %>
+ </div>
+ <div class="field">
+ <%= f.label :description %><br />
+ <%= f.text_field :description %>
+ </div>
+ <div class="actions">
+ <%= f.submit %>
+ </div>
+<% end %>
View
6 app/views/partners/edit.html.erb
@@ -0,0 +1,6 @@
+<h1>Editing partner</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', @partner %> |
+<%= link_to 'Back', partners_path %>
View
27 app/views/partners/index.html.erb
@@ -0,0 +1,27 @@
+<h1>Listing partners</h1>
+
+<table>
+ <tr>
+ <th>Name</th>
+ <th>Url</th>
+ <th>Description</th>
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+<% @partners.each do |partner| %>
+ <tr>
+ <td><%= partner.name %></td>
+ <td><%= partner.url %></td>
+ <td><%= partner.description %></td>
+ <td><%= link_to 'Show', partner %></td>
+ <td><%= link_to 'Edit', edit_partner_path(partner) %></td>
+ <td><%= link_to 'Destroy', partner, :confirm => 'Are you sure?', :method => :delete %></td>
+ </tr>
+<% end %>
+</table>
+
+<br />
+
+<%= link_to 'New Partner', new_partner_path %>
View
5 app/views/partners/new.html.erb
@@ -0,0 +1,5 @@
+<h1>New partner</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Back', partners_path %>
View
20 app/views/partners/show.html.erb
@@ -0,0 +1,20 @@
+<p id="notice"><%= notice %></p>
+
+<p>
+ <b>Name:</b>
+ <%= @partner.name %>
+</p>
+
+<p>
+ <b>Url:</b>
+ <%= @partner.url %>
+</p>
+
+<p>
+ <b>Description:</b>
+ <%= @partner.description %>
+</p>
+
+
+<%= link_to 'Edit', edit_partner_path(@partner) %> |
+<%= link_to 'Back', partners_path %>
View
25 app/views/users/_form.html.erb
@@ -0,0 +1,25 @@
+<%= form_for(@user) do |f| %>
+ <% if @user.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
+
+ <ul>
+ <% @user.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="field">
+ <%= f.label :email %><br />
+ <%= f.text_field :email %>
+ </div>
+ <div class="field">
+ <%= f.label :password %><br />
+ <%= f.text_field :password %>
+ </div>
+ <div class="actions">
+ <%= f.submit %>
+ </div>
+<% end %>
View
6 app/views/users/edit.html.erb
@@ -0,0 +1,6 @@
+<h1>Editing user</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', @user %> |
+<%= link_to 'Back', users_path %>
View
25 app/views/users/index.html.erb
@@ -0,0 +1,25 @@
+<h1>Listing users</h1>
+
+<table>
+ <tr>
+ <th>Email</th>
+ <th>Password</th>
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+<% @users.each do |user| %>
+ <tr>
+ <td><%= user.email %></td>
+ <td><%= user.password %></td>
+ <td><%= link_to 'Show', user %></td>
+ <td><%= link_to 'Edit', edit_user_path(user) %></td>
+ <td><%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %></td>
+ </tr>
+<% end %>
+</table>
+
+<br />
+
+<%= link_to 'New User', new_user_path %>
View
5 app/views/users/new.html.erb
@@ -0,0 +1,5 @@
+<h1>New user</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Back', users_path %>
View
15 app/views/users/show.html.erb
@@ -0,0 +1,15 @@
+<p id="notice"><%= notice %></p>
+
+<p>
+ <b>Email:</b>
+ <%= @user.email %>
+</p>
+
+<p>
+ <b>Password:</b>
+ <%= @user.password %>
+</p>
+
+
+<%= link_to 'Edit', edit_user_path(@user) %> |
+<%= link_to 'Back', users_path %>
View
1 config/environments/development.rb
@@ -22,5 +22,6 @@
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
+ config.action_mailer.default_url_options = { :host => 'localhost:3000' }
end
View
194 config/initializers/devise.rb
@@ -0,0 +1,194 @@
+# Use this hook to configure devise mailer, warden hooks and so forth. The first
+# four configuration values can also be set straight in your models.
+Devise.setup do |config|
+ # ==> Mailer Configuration
+ # Configure the e-mail address which will be shown in DeviseMailer.
+ config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com"
+
+ # Configure the class responsible to send e-mails.
+ # config.mailer = "Devise::Mailer"
+
+ # ==> ORM configuration
+ # Load and configure the ORM. Supports :active_record (default) and
+ # :mongoid (bson_ext recommended) by default. Other ORMs may be
+ # available as additional gems.
+ require 'devise/orm/active_record'
+
+ # ==> Configuration for any authentication mechanism
+ # Configure which keys are used when authenticating a user. The default is
+ # just :email. You can configure it to use [:username, :subdomain], so for
+ # authenticating a user, both parameters are required. Remember that those
+ # parameters are used only when authenticating and not when retrieving from
+ # session. If you need permissions, you should implement that in a before filter.
+ # You can also supply a hash where the value is a boolean determining whether
+ # or not authentication should be aborted when the value is not present.
+ # config.authentication_keys = [ :email ]
+
+ # Configure parameters from the request object used for authentication. Each entry
+ # given should be a request method and it will automatically be passed to the
+ # find_for_authentication method and considered in your model lookup. For instance,
+ # if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
+ # The same considerations mentioned for authentication_keys also apply to request_keys.
+ # config.request_keys = []
+
+ # Configure which authentication keys should be case-insensitive.
+ # These keys will be downcased upon creating or modifying a user and when used
+ # to authenticate or find a user. Default is :email.
+ config.case_insensitive_keys = [ :email ]
+
+ # Tell if authentication through request.params is enabled. True by default.
+ # config.params_authenticatable = true
+
+ # Tell if authentication through HTTP Basic Auth is enabled. False by default.
+ # config.http_authenticatable = false
+
+ # If http headers should be returned for AJAX requests. True by default.
+ # config.http_authenticatable_on_xhr = true
+
+ # The realm used in Http Basic Authentication. "Application" by default.
+ # config.http_authentication_realm = "Application"
+
+ # ==> Configuration for :database_authenticatable
+ # For bcrypt, this is the cost for hashing the password and defaults to 10. If
+ # using other encryptors, it sets how many times you want the password re-encrypted.
+ config.stretches = 10
+
+ # Setup a pepper to generate the encrypted password.
+ # config.pepper = "ec28f816cf74bcc21e7ef39ced26ab60eccc67dea6d2e360530fcf3e13032c7b4fc674cb3e6ade1938aa03296f175ce4ec4ae1f4882bda3ad4ea519f7b3d06ed"
+
+ # ==> Configuration for :confirmable
+ # The time you want to give your user to confirm his account. During this time
+ # he will be able to access your application without confirming. Default is 0.days
+ # When confirm_within is zero, the user won't be able to sign in without confirming.
+ # You can use this to let your user access some features of your application
+ # without confirming the account, but blocking it after a certain period
+ # (ie 2 days).
+ # config.confirm_within = 2.days
+
+ # Defines which key will be used when confirming an account
+ # config.confirmation_keys = [ :email ]
+
+ # ==> Configuration for :rememberable
+ # The time the user will be remembered without asking for credentials again.
+ # config.remember_for = 2.weeks
+
+ # If true, a valid remember token can be re-used between multiple browsers.
+ # config.remember_across_browsers = true
+
+ # If true, extends the user's remember period when remembered via cookie.
+ # config.extend_remember_period = false
+
+ # If true, uses the password salt as remember token. This should be turned
+ # to false if you are not using database authenticatable.
+ config.use_salt_as_remember_token = true
+
+ # Options to be passed to the created cookie. For instance, you can set
+ # :secure => true in order to force SSL only cookies.
+ # config.cookie_options = {}
+
+ # ==> Configuration for :validatable
+ # Range for password length. Default is 6..128.
+ # config.password_length = 6..128
+
+ # Regex to use to validate the email address
+ # config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
+
+ # ==> Configuration for :timeoutable
+ # The time you want to timeout the user session without activity. After this
+ # time the user will be asked for credentials again. Default is 30 minutes.
+ # config.timeout_in = 30.minutes
+
+ # ==> Configuration for :lockable
+ # Defines which strategy will be used to lock an account.
+ # :failed_attempts = Locks an account after a number of failed attempts to sign in.
+ # :none = No lock strategy. You should handle locking by yourself.
+ # config.lock_strategy = :failed_attempts
+
+ # Defines which key will be used when locking and unlocking an account
+ # config.unlock_keys = [ :email ]
+
+ # Defines which strategy will be used to unlock an account.
+ # :email = Sends an unlock link to the user email
+ # :time = Re-enables login after a certain amount of time (see :unlock_in below)
+ # :both = Enables both strategies
+ # :none = No unlock strategy. You should handle unlocking by yourself.
+ # config.unlock_strategy = :both
+
+ # Number of authentication tries before locking an account if lock_strategy
+ # is failed attempts.
+ # config.maximum_attempts = 20
+
+ # Time interval to unlock the account if :time is enabled as unlock_strategy.
+ # config.unlock_in = 1.hour
+
+ # ==> Configuration for :recoverable
+ #
+ # Defines which key will be used when recovering the password for an account
+ # config.reset_password_keys = [ :email ]
+
+ # Time interval you can reset your password with a reset password key.
+ # Don't put a too small interval or your users won't have the time to
+ # change their passwords.
+ config.reset_password_within = 2.hours
+
+ # ==> Configuration for :encryptable
+ # Allow you to use another encryption algorithm besides bcrypt (default). You can use
+ # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
+ # :authlogic_sha512 (then you should set stretches above to 20 for default behavior)
+ # and :restful_authentication_sha1 (then you should set stretches to 10, and copy
+ # REST_AUTH_SITE_KEY to pepper)
+ # config.encryptor = :sha512
+
+ # ==> Configuration for :token_authenticatable
+ # Defines name of the authentication token params key
+ # config.token_authentication_key = :auth_token
+
+ # If true, authentication through token does not store user in session and needs
+ # to be supplied on each request. Useful if you are using the token as API token.
+ # config.stateless_token = false
+
+ # ==> Scopes configuration
+ # Turn scoped views on. Before rendering "sessions/new", it will first check for
+ # "users/sessions/new". It's turned off by default because it's slower if you
+ # are using only default views.
+ # config.scoped_views = false
+
+ # Configure the default scope given to Warden. By default it's the first
+ # devise role declared in your routes (usually :user).
+ # config.default_scope = :user
+
+ # Configure sign_out behavior.
+ # Sign_out action can be scoped (i.e. /users/sign_out affects only :user scope).
+ # The default is true, which means any logout action will sign out all active scopes.
+ # config.sign_out_all_scopes = true
+
+ # ==> Navigation configuration
+ # Lists the formats that should be treated as navigational. Formats like
+ # :html, should redirect to the sign in page when the user does not have
+ # access, but formats like :xml or :json, should return 401.
+ #
+ # If you have any extra navigational formats, like :iphone or :mobile, you
+ # should add them to the navigational formats lists.
+ #
+ # The :"*/*" and "*/*" formats below is required to match Internet
+ # Explorer requests.
+ # config.navigational_formats = [:"*/*", "*/*", :html]
+
+ # The default HTTP method used to sign out a resource. Default is :get.
+ # config.sign_out_via = :get
+
+ # ==> OmniAuth
+ # Add a new OmniAuth provider. Check the wiki for more information on setting
+ # up on your models and hooks.
+ # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
+
+ # ==> Warden configuration
+ # If you want to use other strategies, that are not supported by Devise, or
+ # change the failure app, you can configure them inside the config.warden block.
+ #
+ # config.warden do |manager|
+ # manager.failure_app = AnotherApp
+ # manager.intercept_401 = false
+ # manager.default_strategies(:scope => :user).unshift :some_external_strategy
+ # end
+end
View
50 config/locales/devise.en.yml
@@ -0,0 +1,50 @@
+# Additional translations at http://github.com/plataformatec/devise/wiki/I18n
+
+en:
+ errors:
+ messages:
+ expired: "has expired, please request a new one"
+ not_found: "not found"
+ already_confirmed: "was already confirmed, please try signing in"
+ not_locked: "was not locked"
+ not_saved:
+ one: "1 error prohibited this %{resource} from being saved:"
+ other: "%{count} errors prohibited this %{resource} from being saved:"
+
+ devise:
+ failure:
+ already_authenticated: 'You are already signed in.'
+ unauthenticated: 'You need to sign in or sign up before continuing.'
+ unconfirmed: 'You have to confirm your account before continuing.'
+ locked: 'Your account is locked.'
+ invalid: 'Invalid email or password.'
+ invalid_token: 'Invalid authentication token.'
+ timeout: 'Your session expired, please sign in again to continue.'
+ inactive: 'Your account was not activated yet.'
+ sessions:
+ signed_in: 'Signed in successfully.'
+ signed_out: 'Signed out successfully.'
+ passwords:
+ send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
+ updated: 'Your password was changed successfully. You are now signed in.'
+ confirmations:
+ send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
+ confirmed: 'Your account was successfully confirmed. You are now signed in.'
+ registrations:
+ signed_up: 'Welcome! You have signed up successfully.'
+ inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.'
+ updated: 'You updated your account successfully.'
+ destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
+ unlocks:
+ send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
+ unlocked: 'Your account was successfully unlocked. You are now signed in.'
+ omniauth_callbacks:
+ success: 'Successfully authorized from %{kind} account.'
+ failure: 'Could not authorize you from %{kind} because "%{reason}".'
+ mailer:
+ confirmation_instructions:
+ subject: 'Confirmation instructions'
+ reset_password_instructions:
+ subject: 'Reset password instructions'
+ unlock_instructions:
+ subject: 'Unlock Instructions'
View
15 config/routes.rb
@@ -1,4 +1,17 @@
Groupon::Application.routes.draw do
+ devise_for :users
+
+ resources :users
+
+ resources :partners
+
+ resources :deals do
+ get 'showcase', :on => :collection
+ get 'none', :on => :collection
+ get 'take', :on => :member
+ get 'taken', :on => :member
+ end
+
# The priority is based upon order of creation:
# first created -> highest priority.
@@ -48,7 +61,7 @@
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
- # root :to => "welcome#index"
+ root :to => "deals#showcase"
# See how all your routes lay out with "rake routes"
View
21 db/migrate/20110419161208_create_deals.rb
@@ -0,0 +1,21 @@
+class CreateDeals < ActiveRecord::Migration
+ def self.up
+ create_table :deals do |t|
+ t.string :name
+ t.timestamp :start
+ t.timestamp :finish
+ t.decimal :price
+ t.string :description
+ t.integer :partner_id
+ t.timestamp :valid_from
+ t.timestamp :valid_to
+ t.boolean :featured
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :deals
+ end
+end
View
15 db/migrate/20110419161241_create_partners.rb
@@ -0,0 +1,15 @@
+class CreatePartners < ActiveRecord::Migration
+ def self.up
+ create_table :partners do |t|
+ t.string :name
+ t.string :url
+ t.string :description
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :partners
+ end
+end
View
15 db/migrate/20110419161524_create_users.rb
@@ -0,0 +1,15 @@
+class CreateUsers < ActiveRecord::Migration
+ def self.up
+ create_table :users do |t|
+ t.string :email
+ t.string :password
+ t.string :name
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :users
+ end
+end
View
16 db/migrate/20110419161840_create_users_deals.rb
@@ -0,0 +1,16 @@
+class CreateUsersDeals < ActiveRecord::Migration
+ def self.up
+ create_table :users_deals do |t|
+ t.integer :user_id
+ t.integer :deal_id
+ t.string :promocode
+ t.timestamp :used_at
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :users_deals
+ end
+end
View
28 db/migrate/20110507163157_devise_create_users.rb
@@ -0,0 +1,28 @@
+class DeviseCreateUsers < ActiveRecord::Migration
+ def self.up
+ create_table(:users) do |t|
+ t.database_authenticatable :null => false
+ t.recoverable
+ t.rememberable
+ t.trackable
+
+ # t.encryptable
+ # t.confirmable
+ # t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
+ # t.token_authenticatable
+
+
+ t.timestamps
+ end
+
+ add_index :users, :email, :unique => true
+ add_index :users, :reset_password_token, :unique => true
+ # add_index :users, :confirmation_token, :unique => true
+ # add_index :users, :unlock_token, :unique => true
+ # add_index :users, :authentication_token, :unique => true
+ end
+
+ def self.down
+ drop_table :users
+ end
+end
View
64 db/schema.rb
@@ -0,0 +1,64 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your
+# database schema. If you need to create the application database on another
+# system, you should be using db:schema:load, not running all the migrations
+# from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended to check this file into your version control system.
+
+ActiveRecord::Schema.define(:version => 20110507163157) do
+
+ create_table "deals", :force => true do |t|
+ t.string "name"
+ t.datetime "start"
+ t.datetime "finish"
+ t.decimal "price"
+ t.string "description"
+ t.integer "partner_id"
+ t.datetime "valid_from"
+ t.datetime "valid_to"
+ t.boolean "featured"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "partners", :force => true do |t|
+ t.string "name"
+ t.string "url"
+ t.string "description"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "users", :force => true do |t|
+ t.string "email", :default => "", :null => false
+ t.string "encrypted_password", :limit => 128, :default => "", :null => false
+ t.string "reset_password_token"
+ t.datetime "reset_password_sent_at"
+ t.datetime "remember_created_at"
+ t.integer "sign_in_count", :default => 0
+ t.datetime "current_sign_in_at"
+ t.datetime "last_sign_in_at"
+ t.string "current_sign_in_ip"
+ t.string "last_sign_in_ip"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "users", ["email"], :name => "index_users_on_email", :unique => true
+ add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
+
+ create_table "users_deals", :force => true do |t|
+ t.integer "user_id"
+ t.integer "deal_id"
+ t.string "promocode"
+ t.datetime "used_at"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+end
View
27 groupon.tmproj
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>documents</key>
+ <array>
+ <dict>
+ <key>expanded</key>
+ <true/>
+ <key>name</key>
+ <string>groupon</string>
+ <key>regexFolderFilter</key>
+ <string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
+ <key>sourceDirectory</key>
+ <string></string>
+ </dict>
+ </array>
+ <key>fileHierarchyDrawerWidth</key>
+ <integer>200</integer>
+ <key>metaData</key>
+ <dict/>
+ <key>showFileHierarchyDrawer</key>
+ <true/>
+ <key>windowFrame</key>
+ <string>{{10, 67}, {1043, 711}}</string>
+</dict>
+</plist>
View
374 public/stylesheets/960.css
@@ -0,0 +1,374 @@
+/*
+ Variable Grid System.
+ Learn more ~ http://www.spry-soft.com/grids/
+ Based on 960 Grid System - http://960.gs/
+
+ Licensed under GPL and MIT.
+*/
+
+/*
+ Forces backgrounds to span full width,
+ even if there is horizontal scrolling.
+ Increase this if your layout is wider.
+
+ Note: IE6 works fine without this fix.
+*/
+
+body {
+ min-width: 960px;
+}
+
+/* Containers
+----------------------------------------------------------------------------------------------------*/
+.container_12 {
+ margin-left: auto;
+ margin-right: auto;
+ width: 960px;
+}
+
+/* Grid >> Global
+----------------------------------------------------------------------------------------------------*/
+
+
+.grid_1,
+.grid_2,
+.grid_3,
+.grid_4,
+.grid_5,
+.grid_6,
+.grid_7,
+.grid_8,
+.grid_9,
+.grid_10,
+.grid_11,
+.grid_12 {
+ display:inline;
+ float: left;
+ position: relative;
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+
+
+.push_1, .pull_1,
+.push_2, .pull_2,
+.push_3, .pull_3,
+.push_4, .pull_4,
+.push_5, .pull_5,
+.push_6, .pull_6,
+.push_7, .pull_7,
+.push_8, .pull_8,
+.push_9, .pull_9,
+.push_10, .pull_10,
+.push_11, .pull_11,
+.push_12, .pull_12 {
+ position:relative;
+}
+
+
+/* Grid >> Children (Alpha ~ First, Omega ~ Last)
+----------------------------------------------------------------------------------------------------*/
+
+.alpha {
+ margin-left: 0;
+}
+
+.omega {
+ margin-right: 0;
+}
+
+/* Grid >> 12 Columns
+----------------------------------------------------------------------------------------------------*/
+
+
+.container_12 .grid_1 {
+ width:60px;
+}
+
+.container_12 .grid_2 {
+ width:140px;
+}
+
+.container_12 .grid_3 {
+ width:220px;
+}
+
+.container_12 .grid_4 {
+ width:300px;
+}
+
+.container_12 .grid_5 {
+ width:380px;
+}
+
+.container_12 .grid_6 {
+ width:460px;
+}
+
+.container_12 .grid_7 {
+ width:540px;
+}
+
+.container_12 .grid_8 {
+ width:620px;
+}
+
+.container_12 .grid_9 {
+ width:700px;
+}
+
+.container_12 .grid_10 {
+ width:780px;
+}
+
+.container_12 .grid_11 {
+ width:860px;
+}
+
+.container_12 .grid_12 {
+ width:940px;
+}
+
+
+
+
+/* Prefix Extra Space >> 12 Columns
+----------------------------------------------------------------------------------------------------*/
+
+
+.container_12 .prefix_1 {
+ padding-left:80px;
+}
+
+.container_12 .prefix_2 {
+ padding-left:160px;
+}
+
+.container_12 .prefix_3 {
+ padding-left:240px;
+}
+
+.container_12 .prefix_4 {
+ padding-left:320px;
+}
+
+.container_12 .prefix_5 {
+ padding-left:400px;
+}
+
+.container_12 .prefix_6 {
+ padding-left:480px;
+}
+
+.container_12 .prefix_7 {
+ padding-left:560px;
+}
+
+.container_12 .prefix_8 {
+ padding-left:640px;
+}
+
+.container_12 .prefix_9 {
+ padding-left:720px;
+}
+
+.container_12 .prefix_10 {
+ padding-left:800px;
+}
+
+.container_12 .prefix_11 {
+ padding-left:880px;
+}
+
+
+
+/* Suffix Extra Space >> 12 Columns
+----------------------------------------------------------------------------------------------------*/
+
+
+.container_12 .suffix_1 {
+ padding-right:80px;
+}
+
+.container_12 .suffix_2 {
+ padding-right:160px;
+}
+
+.container_12 .suffix_3 {
+ padding-right:240px;
+}
+
+.container_12 .suffix_4 {
+ padding-right:320px;
+}
+
+.container_12 .suffix_5 {
+ padding-right:400px;
+}
+
+.container_12 .suffix_6 {
+ padding-right:480px;
+}
+
+.container_12 .suffix_7 {
+ padding-right:560px;
+}
+
+.container_12 .suffix_8 {
+ padding-right:640px;
+}
+
+.container_12 .suffix_9 {
+ padding-right:720px;
+}
+
+.container_12 .suffix_10 {
+ padding-right:800px;
+}
+
+.container_12 .suffix_11 {
+ padding-right:880px;
+}
+
+
+
+/* Push Space >> 12 Columns
+----------------------------------------------------------------------------------------------------*/
+
+
+.container_12 .push_1 {
+ left:80px;
+}
+
+.container_12 .push_2 {
+ left:160px;
+}
+
+.container_12 .push_3 {
+ left:240px;
+}
+
+.container_12 .push_4 {
+ left:320px;
+}
+
+.container_12 .push_5 {
+ left:400px;
+}
+
+.container_12 .push_6 {
+ left:480px;
+}
+
+.container_12 .push_7 {
+ left:560px;
+}
+
+.container_12 .push_8 {
+ left:640px;
+}
+
+.container_12 .push_9 {
+ left:720px;
+}
+
+.container_12 .push_10 {
+ left:800px;
+}
+
+.container_12 .push_11 {
+ left:880px;
+}
+
+
+
+/* Pull Space >> 12 Columns
+----------------------------------------------------------------------------------------------------*/
+
+
+.container_12 .pull_1 {
+ left:-80px;
+}
+
+.container_12 .pull_2 {
+ left:-160px;
+}
+
+.container_12 .pull_3 {
+ left:-240px;
+}
+
+.container_12 .pull_4 {
+ left:-320px;
+}
+
+.container_12 .pull_5 {
+ left:-400px;
+}
+
+.container_12 .pull_6 {
+ left:-480px;
+}
+
+.container_12 .pull_7 {
+ left:-560px;
+}
+
+.container_12 .pull_8 {
+ left:-640px;
+}
+
+.container_12 .pull_9 {
+ left:-720px;
+}
+
+.container_12 .pull_10 {
+ left:-800px;
+}
+
+.container_12 .pull_11 {
+ left:-880px;
+}
+
+
+
+
+/* `Clear Floated Elements
+----------------------------------------------------------------------------------------------------*/
+
+/* http://sonspring.com/journal/clearing-floats */
+
+.clear {
+ clear: both;
+ display: block;
+ overflow: hidden;
+ visibility: hidden;
+ width: 0;
+ height: 0;
+}
+
+/* http://www.yuiblog.com/blog/2010/09/27/clearfix-reloaded-overflowhidden-demystified */
+
+.clearfix:before,
+.clearfix:after {
+ content: '\0020';
+ display: block;
+ overflow: hidden;
+ visibility: hidden;
+ width: 0;
+ height: 0;
+}
+
+.clearfix:after {
+ clear: both;
+}
+
+/*
+ The following zoom:1 rule is specifically for IE6 + IE7.
+ Move to separate stylesheet if invalid CSS is a problem.
+*/
+
+.clearfix {
+ zoom: 1;
+}
View
63 public/stylesheets/scaffold.css
@@ -0,0 +1,63 @@
+.container > div { background-color:#fff }
+.container, div.header, div.footer { background-color:#333; }
+h2 { color:#fff; }
+
+.header, .footer { height: 20px; }
+.featured, .additional, .auth { padding: 10px 20px; }
+
+body { background-color: #fff; }
+
+body, p, ol, ul, td {
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+}
+
+pre {
+ background-color: #eee;
+ padding: 10px;
+ font-size: 11px;
+}
+
+a { color: #000; }
+a:visited { color: #666; }
+a:hover { color: #fff; background-color:#000; }
+
+div.field, div.actions {
+ margin-bottom: 10px;
+}
+
+#notice {
+ color: green;
+}
+
+.field_with_errors {
+ padding: 2px;
+ background-color: red;
+ display: table;
+}
+
+#error_explanation {
+ width: 450px;
+ border: 2px solid red;
+ padding: 7px;
+ padding-bottom: 0;
+ margin-bottom: 20px;
+ background-color: #f0f0f0;
+}
+
+#error_explanation h2 {
+ text-align: left;
+ font-weight: bold;
+ padding: 5px 5px 5px 15px;
+ font-size: 12px;
+ margin: -7px;
+ margin-bottom: 0px;
+ background-color: #c00;
+ color: #fff;
+}
+
+#error_explanation ul li {
+ font-size: 12px;
+ list-style: square;
+}
View
17 test/fixtures/deals.yml
@@ -0,0 +1,17 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+
+one:
+ name: MyString
+ start: 2011-04-19 18:12:08
+ end: 2011-04-19 18:12:08
+ price: 9.99
+ description: MyString
+ partner_id: 1
+
+two:
+ name: MyString
+ start: 2011-04-19 18:12:08
+ end: 2011-04-19 18:12:08
+ price: 9.99
+ description: MyString
+ partner_id: 1
View
11 test/fixtures/partners.yml
@@ -0,0 +1,11 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+
+one:
+ name: MyString
+ url: MyString
+ description: MyString
+
+two:
+ name: MyString
+ url: MyString
+ description: MyString
View
9 test/fixtures/users.yml
@@ -0,0 +1,9 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+
+one:
+ email: MyString
+ password: MyString
+
+two:
+ email: MyString
+ password: MyString
View
11 test/fixtures/users_deals.yml
@@ -0,0 +1,11 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+
+one:
+ user_id: 1
+ deal_id: 1
+ promocode: MyString
+
+two:
+ user_id: 1
+ deal_id: 1
+ promocode: MyString
View
49 test/functional/deals_controller_test.rb
@@ -0,0 +1,49 @@
+require 'test_helper'
+
+class DealsControllerTest < ActionController::TestCase
+ setup do
+ @deal = deals(:one)
+ end
+
+ test "should get index" do
+ get :index
+ assert_response :success
+ assert_not_nil assigns(:deals)
+ end
+
+ test "should get new" do
+ get :new
+ assert_response :success
+ end
+
+ test "should create deal" do
+ assert_difference('Deal.count') do
+ post :create, :deal => @deal.attributes
+ end
+
+ assert_redirected_to deal_path(assigns(:deal))
+ end
+
+ test "should show deal" do
+ get :show, :id => @deal.to_param
+ assert_response :success