├── log └── .gitkeep ├── lib ├── tasks │ └── .gitkeep ├── assets │ └── .gitkeep ├── maintenance.rb └── shorten.rb ├── public ├── favicon.ico ├── robots.txt ├── 422.html ├── 404.html └── 500.html ├── app ├── mailers │ ├── .gitkeep │ ├── user_mailer.rb │ └── delivery_mailer.rb ├── models │ ├── .gitkeep │ ├── comment.rb │ ├── sighting.rb │ ├── journal.rb │ ├── schedule.rb │ ├── fee.rb │ ├── location.rb │ ├── package.rb │ ├── user.rb │ └── delivery.rb ├── assets │ ├── javascripts │ │ ├── util.js │ │ ├── schedule_add.js │ │ ├── application.js │ │ ├── delivery_edit.js │ │ └── gmaps.js.erb │ ├── images │ │ ├── logo.png │ │ ├── wheel.png │ │ ├── favicon.png │ │ ├── wheel-e.png │ │ ├── don-hottub-deck.jpg │ │ ├── aol_button_150_47.png │ │ ├── openid_small_logo.png │ │ ├── google_button_150_47.png │ │ ├── yahoo_button_150_47.png │ │ ├── wheel.svg │ │ ├── wheel-e.svg │ │ └── seal.svg │ └── stylesheets │ │ ├── application.css │ │ └── main.scss ├── views │ ├── dashboard │ │ ├── gaignore.html.erb │ │ ├── start_delivery.html │ │ ├── ready_delivery.html.erb │ │ ├── biglogin.html │ │ ├── index.html.erb │ │ └── contact.html.erb │ ├── users │ │ ├── _location.html.erb │ │ ├── _deliveries.html.erb │ │ ├── show.html.erb │ │ ├── _billing.html.erb │ │ ├── _menu.html.erb │ │ ├── _profile.html.erb │ │ ├── edit.html.erb │ │ └── schedule.html.erb │ ├── delivery_mailer │ │ ├── updated.text.erb │ │ ├── accepted.text.erb │ │ └── comment.text.erb │ ├── deliveries │ │ ├── _list.html.erb │ │ ├── _single_due.html.erb │ │ ├── _single_address_map.html.erb │ │ ├── index.html.erb │ │ ├── _single.html.erb │ │ ├── confirm.html.erb │ │ ├── show.html.erb │ │ └── edit.html.erb │ ├── user_mailer │ │ └── login_token_email.text.erb │ ├── layouts │ │ ├── _footer.html.erb │ │ ├── _google_maps.html.erb │ │ ├── _menubar.html.erb │ │ ├── _flashmsg.html.erb │ │ ├── _google_analytics.html.erb │ │ ├── _getsatisfaction.html.erb │ │ ├── application.html.erb │ │ ├── _header.html.erb │ │ └── _geode.html.erb │ └── journal │ │ └── index.html.erb ├── controllers │ ├── payments_controller.rb │ ├── dashboard_controller.rb │ ├── application_controller.rb │ ├── journal_controller.rb │ ├── session_controller.rb │ ├── git_hub_controller.rb │ ├── users_controller.rb │ └── deliveries_controller.rb ├── jobs │ └── twitter_job.rb └── helpers │ └── application_helper.rb ├── vendor ├── plugins │ └── .gitkeep └── assets │ └── stylesheets │ └── .gitkeep ├── spec ├── rcov.opts ├── spec.opts ├── models │ ├── schedule_spec.rb │ ├── journal_spec.rb │ ├── location_spec.rb │ ├── fee_spec.rb │ ├── package_spec.rb │ ├── user_spec.rb │ └── delivery_spec.rb ├── mailers │ ├── user_mailer_spec.rb │ └── delivery_mailer_spec.rb ├── fixtures │ ├── fees.yml │ ├── users.yml │ ├── journal.yml │ ├── locations.yml │ ├── packages.yml │ ├── openidentities.yml │ └── deliveries.yml ├── controllers │ ├── journal_controller_spec.rb │ ├── dashboard_controller_spec.rb │ ├── git_hub_controller_spec.rb │ ├── session_controller_spec.rb │ ├── users_controller_spec.rb │ └── deliveries_controller_spec.rb ├── views │ ├── users │ │ └── show.html.erb_spec.rb │ ├── git_hub │ │ └── commit.html.erb_spec.rb │ ├── layouts │ │ └── application.html.erb_spec.rb │ ├── dashboard │ │ └── index.html.erb_spec.rb │ └── deliveries │ │ ├── edit.html.erb_spec.rb │ │ ├── index.html.erb_spec.rb │ │ └── show.html.erb_spec.rb └── spec_helper.rb ├── config ├── initializers │ ├── _settings.rb │ ├── mime_types.rb │ ├── exception_notifier.rb │ ├── twitter.rb │ ├── inflections.rb │ ├── backtrace_silencers.rb │ ├── session_store.rb │ ├── secret_token.rb │ ├── wrap_parameters.rb │ └── devise.rb ├── environment.rb ├── boot.rb ├── locales │ ├── en.yml │ └── devise.en.yml ├── settings.yml.example ├── routes.rb ├── environments │ ├── development.rb │ ├── test.rb │ └── production.rb └── application.rb ├── script ├── hourly.rb ├── delayed_job └── rails ├── db ├── migrate │ ├── 20111003183742_location_name.rb │ ├── 20090421175806_add_user.rb │ ├── 20090807223209_add_email_to_user.rb │ ├── 20110115184624_add_fee_method.rb │ ├── 20090828195035_add_users_clocked_in.rb │ ├── 20101123223921_add_featured_flag.rb │ ├── 20130929215541_add_queue_to_delayed_jobs.rb │ ├── 20090727203928_add_price_to_package.rb │ ├── 20090424180923_create_fees.rb │ ├── 20090916183925_add_accepted_at_to_delivery.rb │ ├── 20091028235007_user_email_on_new_listing.rb │ ├── 20110920184328_devise_user.rb │ ├── 20111004010538_create_comments.rb │ ├── 20090824161024_add_delivery_start_end_distance.rb │ ├── 20090421182229_create_locations.rb │ ├── 20090424003438_create_openids.rb │ ├── 20090812000239_create_sightings.rb │ ├── 20090908222348_clockedin_boolean_to_time.rb │ ├── 20090506004017_user_add_timezone_displaymeasurement.rb │ ├── 20111012174153_create_schedules.rb │ ├── 20090421182220_create_packages.rb │ ├── 20090428170519_create_journal.rb │ ├── 20090811235813_add_lat_long_to_location.rb │ ├── 20090421181738_create_deliveries.rb │ ├── 20090803214257_add_time_to_fee.rb │ ├── 20101228194334_add_workflow_state.rb │ ├── 20101207021937_create_slugs.rb │ ├── 20090424003439_add_open_id_store_to_db.rb │ └── 20111006165028_create_delayed_jobs.rb ├── seeds.rb └── schema.rb ├── .gitignore ├── doc └── README_FOR_APP ├── Rakefile ├── config.ru ├── Gemfile ├── Gemfile.lock └── README /log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/plugins/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/javascripts/util.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/dashboard/gaignore.html.erb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/rcov.opts: -------------------------------------------------------------------------------- 1 | --exclude "spec/*,gems/*" 2 | --rails -------------------------------------------------------------------------------- /spec/spec.opts: -------------------------------------------------------------------------------- 1 | --colour 2 | --format specdoc 3 | --loadby mtime 4 | --reverse 5 | -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donpdonp/everyonedelivers/master/app/assets/images/logo.png -------------------------------------------------------------------------------- /app/assets/images/wheel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donpdonp/everyonedelivers/master/app/assets/images/wheel.png -------------------------------------------------------------------------------- /app/models/comment.rb: -------------------------------------------------------------------------------- 1 | class Comment < ActiveRecord::Base 2 | belongs_to :delivery 3 | belongs_to :user 4 | end 5 | -------------------------------------------------------------------------------- /app/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donpdonp/everyonedelivers/master/app/assets/images/favicon.png -------------------------------------------------------------------------------- /app/assets/images/wheel-e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donpdonp/everyonedelivers/master/app/assets/images/wheel-e.png -------------------------------------------------------------------------------- /app/models/sighting.rb: -------------------------------------------------------------------------------- 1 | class Sighting < ActiveRecord::Base 2 | belongs_to :user 3 | belongs_to :location 4 | end 5 | -------------------------------------------------------------------------------- /app/controllers/payments_controller.rb: -------------------------------------------------------------------------------- 1 | class PaymentsController < ApplicationController 2 | def paypal 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/jobs/twitter_job.rb: -------------------------------------------------------------------------------- 1 | class TwitterJob < Struct.new(:update) 2 | def perform 3 | Twitter.update(update) 4 | end 5 | end -------------------------------------------------------------------------------- /config/initializers/_settings.rb: -------------------------------------------------------------------------------- 1 | SETTINGS = YAML.load(File.open(Rails.root+"config/settings.yml")) unless defined? SETTINGS 2 | 3 | -------------------------------------------------------------------------------- /app/assets/images/don-hottub-deck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donpdonp/everyonedelivers/master/app/assets/images/don-hottub-deck.jpg -------------------------------------------------------------------------------- /app/assets/images/aol_button_150_47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donpdonp/everyonedelivers/master/app/assets/images/aol_button_150_47.png -------------------------------------------------------------------------------- /app/assets/images/openid_small_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donpdonp/everyonedelivers/master/app/assets/images/openid_small_logo.png -------------------------------------------------------------------------------- /app/assets/images/google_button_150_47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donpdonp/everyonedelivers/master/app/assets/images/google_button_150_47.png -------------------------------------------------------------------------------- /app/assets/images/yahoo_button_150_47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donpdonp/everyonedelivers/master/app/assets/images/yahoo_button_150_47.png -------------------------------------------------------------------------------- /script/hourly.rb: -------------------------------------------------------------------------------- 1 | # Run hourly 2 | require 'maintenance' 3 | 4 | # Clean out the clocked_in users older than an hour 5 | Maintenance.clock_clean 6 | -------------------------------------------------------------------------------- /app/views/users/_location.html.erb: -------------------------------------------------------------------------------- 1 |

2 | Recorded <%= @user.sightings.size %> sightings at <%= @user.locations.size %> locations.
3 |

4 | -------------------------------------------------------------------------------- /spec/models/schedule_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Schedule do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/mailers/user_mailer_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe UserMailer do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/mailers/delivery_mailer_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe DeliveryMailer do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /app/models/journal.rb: -------------------------------------------------------------------------------- 1 | class Journal < ActiveRecord::Base 2 | belongs_to :delivery 3 | belongs_to :user 4 | belongs_to :package 5 | belongs_to :location 6 | end 7 | -------------------------------------------------------------------------------- /app/views/dashboard/start_delivery.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | To complete the delivery request, please use the email login form above. 4 |

5 | 6 |
7 | -------------------------------------------------------------------------------- /db/migrate/20111003183742_location_name.rb: -------------------------------------------------------------------------------- 1 | class LocationName < ActiveRecord::Migration 2 | def change 3 | add_column :locations, :name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/fixtures/fees.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | # one: 4 | # column: value 5 | # 6 | # two: 7 | # column: value 8 | -------------------------------------------------------------------------------- /spec/fixtures/users.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | # one: 4 | # column: value 5 | # 6 | # two: 7 | # column: value 8 | -------------------------------------------------------------------------------- /spec/fixtures/journal.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | # one: 4 | # column: value 5 | # 6 | # two: 7 | # column: value 8 | -------------------------------------------------------------------------------- /spec/fixtures/locations.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | # one: 4 | # column: value 5 | # 6 | # two: 7 | # column: value 8 | -------------------------------------------------------------------------------- /spec/fixtures/packages.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | # one: 4 | # column: value 5 | # 6 | # two: 7 | # column: value 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | db/*.sqlite3 3 | log/*.log 4 | tmp/ 5 | .sass-cache/ 6 | gems/ 7 | config/database.yml 8 | config/settings.yml 9 | .rspec 10 | bin/ 11 | public/assets/ 12 | -------------------------------------------------------------------------------- /spec/fixtures/openidentities.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | # one: 4 | # column: value 5 | # 6 | # two: 7 | # column: value 8 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | EveryoneDelivers::Application.initialize! 6 | -------------------------------------------------------------------------------- /script/delayed_job: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) 4 | require 'delayed/command' 5 | Delayed::Command.new(ARGV).daemonize 6 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def link_to_user(user) 3 | if user 4 | link_to user.username, user_path(user) 5 | else 6 | "(none)" 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/views/delivery_mailer/updated.text.erb: -------------------------------------------------------------------------------- 1 | Delivery #<%=@delivery.id%> has been updated. 2 | 3 | <%= url_for(:host => SETTINGS["email"]["domain"], :controller => :deliveries, :action => :show, :id => @delivery.id )%> 4 | 5 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-Agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /app/views/deliveries/_list.html.erb: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /app/views/user_mailer/login_token_email.text.erb: -------------------------------------------------------------------------------- 1 | Welcome to <%= SETTINGS["email"]["domain"]%>, <%= @user.username %> 2 | =============================================== 3 | 4 | Follow this link to login: 5 | 6 | <%= @url %> 7 | 8 | -- Email Robot -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /db/migrate/20090421175806_add_user.rb: -------------------------------------------------------------------------------- 1 | class AddUser < ActiveRecord::Migration 2 | def self.up 3 | create_table :users do |t| 4 | t.string :username 5 | t.timestamps 6 | end 7 | end 8 | 9 | def self.down 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20090807223209_add_email_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddEmailToUser < ActiveRecord::Migration 2 | def self.up 3 | add_column :users, :email, :string 4 | end 5 | 6 | def self.down 7 | remove_column :users, :email, :string 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110115184624_add_fee_method.rb: -------------------------------------------------------------------------------- 1 | class AddFeeMethod < ActiveRecord::Migration 2 | def self.up 3 | add_column :fees, :payment_method, :string 4 | end 5 | 6 | def self.down 7 | add_column :fees, :payment_method 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20090828195035_add_users_clocked_in.rb: -------------------------------------------------------------------------------- 1 | class AddUsersClockedIn < ActiveRecord::Migration 2 | def self.up 3 | add_column :users, :clocked_in, :boolean 4 | end 5 | 6 | def self.down 7 | remove_column :users, :clocked_in 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20101123223921_add_featured_flag.rb: -------------------------------------------------------------------------------- 1 | class AddFeaturedFlag < ActiveRecord::Migration 2 | def self.up 3 | add_column :deliveries, :featured, :boolean 4 | end 5 | 6 | def self.down 7 | remove_column :deliveries, :featured 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/views/delivery_mailer/accepted.text.erb: -------------------------------------------------------------------------------- 1 | Delivery #<%=@delivery.id%> has been accepted for delivery by <%= @delivery.delivering_user.username%>. 2 | 3 | <%= url_for(:host => SETTINGS["email"]["domain"], :controller => :deliveries, :action => :show, :id => @delivery.id )%> 4 | -------------------------------------------------------------------------------- /config/initializers/exception_notifier.rb: -------------------------------------------------------------------------------- 1 | EveryoneDelivers::Application.config.middleware.use(ExceptionNotifier, 2 | :sender_address => SETTINGS["email"]["from"], 3 | :exception_recipients => SETTINGS["exception_notifier"]["email"]) 4 | -------------------------------------------------------------------------------- /db/migrate/20130929215541_add_queue_to_delayed_jobs.rb: -------------------------------------------------------------------------------- 1 | class AddQueueToDelayedJobs < ActiveRecord::Migration 2 | def self.up 3 | add_column :delayed_jobs, :queue, :string 4 | end 5 | 6 | def self.down 7 | remove_column :delayed_jobs, :queue 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/views/delivery_mailer/comment.text.erb: -------------------------------------------------------------------------------- 1 | Delivery #<%=@delivery.id%> has a new comment from <%= @comment.user.username %>. 2 | 3 | "<%= @comment.text %>" 4 | 5 | <%= url_for(:host => SETTINGS["email"]["domain"], :controller => :deliveries, :action => :show, :id => @delivery.id )%> 6 | -------------------------------------------------------------------------------- /db/migrate/20090727203928_add_price_to_package.rb: -------------------------------------------------------------------------------- 1 | class AddPriceToPackage < ActiveRecord::Migration 2 | def self.up 3 | add_column :packages, :price_in_cents, :integer 4 | end 5 | 6 | def self.down 7 | remove_column :packages, :price_in_cents 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20090424180923_create_fees.rb: -------------------------------------------------------------------------------- 1 | class CreateFees < ActiveRecord::Migration 2 | def self.up 3 | create_table :fees do |t| 4 | t.integer :price_in_cents 5 | t.timestamps 6 | end 7 | end 8 | 9 | def self.down 10 | drop_table :fees 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20090916183925_add_accepted_at_to_delivery.rb: -------------------------------------------------------------------------------- 1 | class AddAcceptedAtToDelivery < ActiveRecord::Migration 2 | def self.up 3 | add_column :deliveries, :accepted_at, :datetime 4 | end 5 | 6 | def self.down 7 | remove_column :deliveries, :accepted_at 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20091028235007_user_email_on_new_listing.rb: -------------------------------------------------------------------------------- 1 | class UserEmailOnNewListing < ActiveRecord::Migration 2 | def self.up 3 | add_column :users, :email_on_new_listing, :boolean 4 | end 5 | 6 | def self.down 7 | remove_column :users, :email_on_new_listing 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110920184328_devise_user.rb: -------------------------------------------------------------------------------- 1 | require 'uuidtools' 2 | class DeviseUser < ActiveRecord::Migration 3 | def change 4 | add_column :users, :authentication_token, :string 5 | User.all.each{|u| u.update_attribute :authentication_token, UUIDTools::UUID.random_create.to_s} 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20111004010538_create_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateComments < ActiveRecord::Migration 2 | def change 3 | create_table :comments do |t| 4 | t.integer :delivery_id 5 | t.integer :user_id 6 | t.string :text 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | EveryoneDelivers::Application.load_tasks 8 | -------------------------------------------------------------------------------- /db/migrate/20090824161024_add_delivery_start_end_distance.rb: -------------------------------------------------------------------------------- 1 | class AddDeliveryStartEndDistance < ActiveRecord::Migration 2 | def self.up 3 | add_column :deliveries, :start_end_distance, :integer 4 | end 5 | 6 | def self.down 7 | remove_column :deliveries, :start_end_distance 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /spec/controllers/journal_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe JournalController do 4 | 5 | before(:each) do 6 | controller.stub!(:set_timezone) 7 | end 8 | 9 | it "should show the journal" do 10 | get :index 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /config/initializers/twitter.rb: -------------------------------------------------------------------------------- 1 | Twitter.configure do |config| 2 | config.consumer_key = SETTINGS["twitter"]["consumer_key"] 3 | config.consumer_secret = SETTINGS["twitter"]["consumer_secret"] 4 | config.oauth_token = SETTINGS["twitter"]["oauth_token"] 5 | config.oauth_token_secret = SETTINGS["twitter"]["oauth_secret"] 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20090421182229_create_locations.rb: -------------------------------------------------------------------------------- 1 | class CreateLocations < ActiveRecord::Migration 2 | def self.up 3 | create_table :locations do |t| 4 | t.string :street 5 | t.string :zipcode 6 | t.timestamps 7 | end 8 | end 9 | 10 | def self.down 11 | drop_table :locations 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | header: 6 | login: "Login" 7 | logout: "logout" 8 | email_login_placeholder: "Login with email address" -------------------------------------------------------------------------------- /db/migrate/20090424003438_create_openids.rb: -------------------------------------------------------------------------------- 1 | class CreateOpenids < ActiveRecord::Migration 2 | def self.up 3 | create_table :openidentities do |t| 4 | t.string :url 5 | t.integer :user_id 6 | t.timestamps 7 | end 8 | end 9 | 10 | def self.down 11 | drop_table :openidentites 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/models/journal_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe Journal do 4 | before(:each) do 5 | @valid_attributes = { 6 | } 7 | end 8 | 9 | it "should create a new instance given valid attributes" do 10 | Journal.create!(@valid_attributes) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/models/location_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe Location do 4 | before(:each) do 5 | @valid_attributes = { 6 | } 7 | end 8 | 9 | it "should create a new instance given valid attributes" do 10 | Location.create!(@valid_attributes) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.erb: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /lib/maintenance.rb: -------------------------------------------------------------------------------- 1 | class Maintenance 2 | def self.clock_clean 3 | User.clocked_ins.each do |user| 4 | if user.clocked_in < Time.now - 1.hour 5 | user.clock_out! 6 | Journal.create({:delivery => nil, :user => user, :note => "Clocked out #{user.username} after an hour"}) 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/views/users/_deliveries.html.erb: -------------------------------------------------------------------------------- 1 |

Listed deliveries

2 | 3 | <%= render :partial => 'deliveries/list', :locals => {:timedesc => "", :deliveries => user.listed_deliveries} %> 4 | 5 |

Accepted deliveries

6 | 7 | <%= render :partial => 'deliveries/list', :locals => {:timedesc => "", :deliveries => user.accepted_deliveries} %> 8 | -------------------------------------------------------------------------------- /db/migrate/20090812000239_create_sightings.rb: -------------------------------------------------------------------------------- 1 | class CreateSightings < ActiveRecord::Migration 2 | def self.up 3 | create_table :sightings do |t| 4 | t.column :user_id, :integer 5 | t.column :location_id, :integer 6 | t.timestamps 7 | end 8 | end 9 | 10 | def self.down 11 | drop_table :sightings 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/controllers/dashboard_controller.rb: -------------------------------------------------------------------------------- 1 | class DashboardController < ApplicationController 2 | 3 | def index 4 | @featured_delivery = Delivery.first(:conditions => {:featured => true}) 5 | end 6 | 7 | def start_delivery 8 | end 9 | 10 | def ready_delivery 11 | redirect_to :action => :start_delivery unless user_signed_in? 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20090908222348_clockedin_boolean_to_time.rb: -------------------------------------------------------------------------------- 1 | class ClockedinBooleanToTime < ActiveRecord::Migration 2 | def self.up 3 | remove_column :users, :clocked_in 4 | add_column :users, :clocked_in, :datetime 5 | end 6 | 7 | def self.down 8 | remove_column :users, :clocked_in 9 | add_column :users, :clocked_in, :boolean 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/mailers/user_mailer.rb: -------------------------------------------------------------------------------- 1 | class UserMailer < ActionMailer::Base 2 | default from: SETTINGS["email"]["from"] 3 | 4 | def login_token_email(user) 5 | @user = user 6 | @url = "http://#{SETTINGS["email"]["domain"]}/session/login_token?token=#{user.authentication_token}" 7 | mail(:to => user.email, :subject => "EveryoneDelivers Login Button") 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/views/layouts/_google_maps.html.erb: -------------------------------------------------------------------------------- 1 | 3 | 10 | -------------------------------------------------------------------------------- /spec/controllers/dashboard_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe DashboardController do 4 | 5 | before(:each) do 6 | controller.stub!(:set_timezone) 7 | end 8 | 9 | it "should display the splash" do 10 | get :index 11 | response.should render_template("dashboard/index") 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /app/views/dashboard/ready_delivery.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

3 | You did it! 4 |

5 |

6 | Press the link below to 7 | start filling in details about your delivery requset. 8 |

9 | <%= form_for Delivery.new do |f| %> 10 | <%= submit_tag "Create a delivery"%> 11 | <% end %> 12 |

13 | 14 |
15 | 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll automatically include all the stylesheets available in this directory 3 | * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at 4 | * the top of the compiled file, but it's generally better to create a new file per style scope. 5 | *= require_self 6 | *= require_tree . 7 | */ -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery # See ActionController::RequestForgeryProtection for details 3 | before_filter :set_timezone 4 | 5 | def set_timezone 6 | # current_user.time_zone #=> 'London' 7 | Time.zone = current_user.time_zone if current_user && !current_user.time_zone.blank? 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20090506004017_user_add_timezone_displaymeasurement.rb: -------------------------------------------------------------------------------- 1 | class UserAddTimezoneDisplaymeasurement < ActiveRecord::Migration 2 | def self.up 3 | add_column :users, :time_zone, :string 4 | add_column :users, :display_measurement, :string 5 | end 6 | 7 | def self.down 8 | remove_column :users, :time_zone 9 | remove_column :users, :display_measurement 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/assets/javascripts/schedule_add.js: -------------------------------------------------------------------------------- 1 | function schedule_submit(event) { 2 | console.log("submit!"); 3 | if($('#gmaplat').val().length > 0 && 4 | $('#gmaplng').val().length > 0 && 5 | $('#street1_field').val().length > 0 && 6 | $('#street2_field').val().length > 0 ) { 7 | return true; 8 | } else { 9 | alert('Please position the map marker'); 10 | return false; 11 | } 12 | } -------------------------------------------------------------------------------- /app/views/deliveries/_single_due.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <% if fee.delivery_due %> 3 | <% if fee.delivery_due >= Time.now %> 4 | Due in 5 | <% else %> 6 | Overdue by 7 | <% end %> 8 | <%= distance_of_time_in_words_to_now(fee.delivery_due) %>
9 | <% else %> 10 | Due date missing. 11 | <% end %> 12 | 13 | -------------------------------------------------------------------------------- /spec/views/users/show.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/users/show.html.erb" do 4 | before(:each) do 5 | view.stub!(:user_signed_in?).and_return(true) 6 | @user = mock_model(User, :username => "bob") 7 | end 8 | 9 | it "should render" do 10 | assign(:user, @user) 11 | render 12 | rendered.should have_selector('div#sampledelivery') 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20111012174153_create_schedules.rb: -------------------------------------------------------------------------------- 1 | class CreateSchedules < ActiveRecord::Migration 2 | def change 3 | create_table :schedules do |t| 4 | t.datetime :starting_at 5 | t.datetime :ending_at 6 | t.float :latitude 7 | t.float :longitude 8 | t.string :street1 9 | t.string :street2 10 | 11 | t.integer :user_id 12 | t.timestamps 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | 9 | Delivery.create({featured: true}) 10 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | inflect.uncountable %w( journal ) 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20090421182220_create_packages.rb: -------------------------------------------------------------------------------- 1 | class CreatePackages < ActiveRecord::Migration 2 | def self.up 3 | create_table :packages do |t| 4 | t.string :description 5 | t.float :weight_in_grams 6 | t.float :height_in_meters 7 | t.float :width_in_meters 8 | t.float :depth_in_meters 9 | t.timestamps 10 | end 11 | end 12 | 13 | def self.down 14 | drop_table :packages 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20090428170519_create_journal.rb: -------------------------------------------------------------------------------- 1 | class CreateJournal < ActiveRecord::Migration 2 | def self.up 3 | create_table :journal do |t| 4 | t.integer :delivery_id 5 | t.integer :package_id 6 | t.integer :user_id 7 | t.integer :location_id 8 | t.float :fee 9 | t.string :note 10 | t.timestamps 11 | end 12 | end 13 | 14 | def self.down 15 | drop_table :journal 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /db/migrate/20090811235813_add_lat_long_to_location.rb: -------------------------------------------------------------------------------- 1 | class AddLatLongToLocation < ActiveRecord::Migration 2 | def self.up 3 | add_column :locations, :latitude, :float 4 | add_column :locations, :longitude, :float 5 | add_column :locations, :accuracy, :float 6 | end 7 | 8 | def self.down 9 | remove_column :locations, :latitude 10 | remove_column :locations, :longitude 11 | remove_column :locations, :accuracy 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/controllers/git_hub_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe GitHubController do 4 | 5 | before(:each) do 6 | controller.stub!(:set_timezone) 7 | end 8 | 9 | describe "GET 'commit'" do 10 | it "should be successful" do 11 | controller.should_receive(:shell) 12 | get 'commit', :payload => '{}' 13 | response.should be_success 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/views/git_hub/commit.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') 2 | 3 | describe "/git_hub/commit.html.erb" do 4 | # before(:each) do 5 | # render 'git_hub/commit' 6 | # end 7 | 8 | #Delete this example and add some real ones or delete this file 9 | # it "should tell you where to find the file" do 10 | # response.should have_tag('p', %r[Find me in app/views/git_hub/commit]) 11 | # end 12 | end 13 | -------------------------------------------------------------------------------- /spec/views/layouts/application.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/layouts/application.html.erb" do 4 | before(:each) do 5 | controller.should_receive(:user_signed_in?).and_return(false) 6 | render 7 | end 8 | 9 | it "should contain the google adsense code and unique ID" do 10 | rendered.should have_selector('div#google_adsense', :content => "getTracker\(\"#{SETTINGS["google"]["adsense"]["id"]}\"\)") 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/users/show.html.erb: -------------------------------------------------------------------------------- 1 | <% tab = params[:tab] || 'profile' %> 2 | <% content_for :title do %> 3 | User <%=h @user.username %> 4 | <% end %> 5 |
6 |

7 | User Profile for <%=h @user.username %> 8 |

9 | 10 | <%= render :partial => 'menu', :locals => {:user => @user} %> 11 | 12 | <% if ['profile', 'deliveries', 'location', 'billing'].include? tab %> 13 | <%= render :partial => tab, :locals => {:user => @user} %> 14 | <% end %> 15 |
16 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | EveryoneDelivers::Application.config.session_store :cookie_store, key: '_EveryoneDelivers_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # EveryoneDelivers::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /db/migrate/20090421181738_create_deliveries.rb: -------------------------------------------------------------------------------- 1 | class CreateDeliveries < ActiveRecord::Migration 2 | def self.up 3 | create_table :deliveries do |t| 4 | t.integer :fee_id 5 | t.integer :package_id 6 | t.integer :start_location_id 7 | t.integer :end_location_id 8 | t.integer :listing_user_id 9 | t.integer :delivering_user_id 10 | t.timestamps 11 | end 12 | end 13 | 14 | def self.down 15 | drop_table :deliveries 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20090803214257_add_time_to_fee.rb: -------------------------------------------------------------------------------- 1 | class AddTimeToFee < ActiveRecord::Migration 2 | def self.up 3 | add_column :fees, :delivery_due, :datetime 4 | Fee.reset_column_information 5 | Delivery.all.each{|d| d.fee.update_attribute(:delivery_due, d.created_at) if d.fee} 6 | Fee.all(:conditions => {:delivery_due => nil}).each{|f| f.update_attribute :delivery_due, Time.now} 7 | end 8 | 9 | def self.down 10 | remove_column :fees, :delivery_due 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/views/layouts/_menubar.html.erb: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /app/views/users/_billing.html.erb: -------------------------------------------------------------------------------- 1 | <% year = Time.now.year; month = Time.now.month %> 2 | <% all_deliveries = user.accepted_deliveries %> 3 | <% month_deliveries = user.accepted_deliveries(year,month) %> 4 |

Account

5 |

6 | Total Accepted deliveries : <%= all_deliveries.size %> 7 |

8 |

9 | Accepted deliveries for <%=year%>/<%=month%>: <%= month_deliveries.size %> 10 |

11 | $0.50 per delivery x <%= month_deliveries.size %> deliveries = $<%= 0.50 * month_deliveries.size %> 12 |

13 | -------------------------------------------------------------------------------- /spec/views/dashboard/index.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/dashboard/index.html.erb" do 4 | before(:each) do 5 | view.stub!(:user_signed_in?).and_return(false) 6 | end 7 | 8 | it "should render" do 9 | featured_delivery = mock_model(Delivery) 10 | featured_delivery.should_receive(:ok_to_display?).and_return(false) 11 | assign(:featured_delivery,featured_delivery) 12 | render 13 | rendered.should have_selector('div#sampledelivery') 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/views/layouts/_flashmsg.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <% if flash[:error] %> 3 |
4 | <%=h flash[:error] %> 5 |
6 | <% end %> 7 | <% if flash[:notice] %> 8 |
9 | <%=h flash[:notice] %> 10 |
11 | <% end %> 12 | <% if flash[:success] %> 13 |
14 | <%=h flash[:success] %> 15 |
16 | <% end %> 17 |
18 | -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into including all the files listed below. 2 | // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically 3 | // be included in the compiled file accessible from http://example.com/assets/application.js 4 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 5 | // the compiled file. 6 | // 7 | //= require jquery 8 | //= require jquery_ujs 9 | //= require_tree . 10 | -------------------------------------------------------------------------------- /app/controllers/journal_controller.rb: -------------------------------------------------------------------------------- 1 | class JournalController < ApplicationController 2 | 3 | def index 4 | @entries = Journal.all(:order => "id desc", :conditions => ["created_at > ?",1.month.ago]) 5 | end 6 | 7 | def count 8 | @entries = Journal.count(:conditions => ["note = ? and created_at > ?", 9 | params[:note], 10 | params[:hours].to_i.hours.ago]) 11 | render :json => {:count => @entries}.to_json 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | EveryoneDelivers::Application.config.secret_token = 'e1d1226ab2ebcd4d804bc15d3b6f88da26e04a5560da2094f2b178c03c664b4bfb1499948aa832caebde7acba9101c0a4d957c7d81548c457878e8cfae5ec1a2' 8 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require 'yaml' 2 | # This file is used by Rack-based servers to start the application. 3 | SETTINGS = YAML.load(File.open(File.join(File.dirname(__FILE__), "config/settings.yml"))) 4 | 5 | require './lib/shorten' 6 | require ::File.expand_path('../config/environment', __FILE__) 7 | 8 | use Shorten 9 | 10 | builder = Rack::Builder.new do 11 | map '/assets' do 12 | run Rack::File.new(File.join(File.dirname(__FILE__),"public/assets/")) 13 | end 14 | 15 | map '/' do 16 | run EveryoneDelivers::Application 17 | end 18 | end 19 | run builder 20 | -------------------------------------------------------------------------------- /lib/shorten.rb: -------------------------------------------------------------------------------- 1 | class Shorten 2 | def initialize(app) 3 | @app = app 4 | end 5 | 6 | def call(env) 7 | if env["HTTP_HOST"] == SETTINGS["redirect"]["hostname"] 8 | redir = env["SERVER_PROTOCOL"].split('/').first + "://"+ SETTINGS["email"]["domain"] + 9 | "/deliveries" + env["PATH_INFO"] 10 | status, headers, response = [ 302, {"Content-Type"=>"text/plain", "Location"=> redir }, [] ] 11 | else 12 | status, headers, response = @app.call(env) 13 | end 14 | [status, headers, response] 15 | end 16 | end -------------------------------------------------------------------------------- /spec/models/fee_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe Fee do 4 | before(:each) do 5 | @valid_attributes = { 6 | } 7 | end 8 | 9 | it "should create a new instance given valid attributes" do 10 | Fee.create!(@valid_attributes) 11 | end 12 | 13 | it "should sanitize and store new attributes" do 14 | fee = Fee.create!(@valid_attributes) 15 | new_attributes = { :display_price => "1.50" } 16 | fee.apply_form_attributes(new_attributes) 17 | fee.price_in_cents.should == 150 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /config/settings.yml.example: -------------------------------------------------------------------------------- 1 | --- 2 | journal: 3 | notification_email_address: "" 4 | bunny: 5 | start: 6 | user: 7 | pass: 8 | host: 9 | google: 10 | adsense: 11 | id: "UA-XXXXXX-X" 12 | maps: 13 | key: "" 14 | bing: 15 | maps: 16 | key: "" 17 | email: 18 | domain: "" 19 | from: "" 20 | getsatisfaction: 21 | company: "" 22 | exception_notifier: 23 | email: "" 24 | twitter: 25 | consumer_key: "" 26 | consumer_secret: "" 27 | oauth_token: "" 28 | oauth_secret: "" 29 | shortname: 30 | url: "http://shorturl.tld" 31 | geonames: 32 | username: 33 | 34 | -------------------------------------------------------------------------------- /app/views/layouts/_google_analytics.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 6 | 7 | 14 |
15 | -------------------------------------------------------------------------------- /spec/fixtures/deliveries.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html 2 | 3 | tg11: 4 | id: 1 5 | created_at: <%= Time.zone.parse("2009-01-01 12:00") %> 6 | tg12: 7 | id: 2 8 | created_at: <%= Time.zone.parse("2009-01-01 12:10") %> 9 | tg21: 10 | id: 3 11 | created_at: <%= Time.zone.parse("2009-01-01 11:00") %> 12 | tg22: 13 | id: 4 14 | created_at: <%= Time.zone.parse("2009-01-01 11:10") %> 15 | tg31: 16 | id: 5 17 | created_at: <%= Time.zone.parse("2009-01-01 01:00") %> 18 | tg32: 19 | id: 6 20 | created_at: <%= Time.zone.parse("2009-01-01 01:11") %> 21 | -------------------------------------------------------------------------------- /db/migrate/20101228194334_add_workflow_state.rb: -------------------------------------------------------------------------------- 1 | class AddWorkflowState < ActiveRecord::Migration 2 | def self.up 3 | add_column :deliveries, :workflow_state, :string 4 | Delivery.all.each do |d| 5 | if d.delivering_user 6 | d.update_attribute :workflow_state, "delivered" 7 | else 8 | if d.ok_to_display? 9 | d.update_attribute :workflow_state, "waiting" 10 | else 11 | d.update_attribute :workflow_state, "building" 12 | end 13 | end 14 | end 15 | end 16 | 17 | def self.down 18 | remove_column :deliveries, :workflow_state 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/controllers/session_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../spec_helper' 2 | 3 | describe SessionController do 4 | before(:each) do 5 | controller.stub!(:set_timezone) 6 | end 7 | 8 | it "logs in a first-time user" do 9 | token = 'abc123' 10 | user = mock_model(User) 11 | User.should_receive(:find_by_authentication_token).with(token).and_return(user) 12 | controller.should_receive(:sign_in) 13 | get :login_token, {:token => token} 14 | end 15 | 16 | it "should logout the user" do 17 | controller.should_receive(:reset_session) 18 | get :logout 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/views/deliveries/edit.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/deliveries/edit.html.erb" do 4 | before(:each) do 5 | view.stub!(:user_signed_in?).and_return(false) 6 | view.stub!(:current_user) 7 | end 8 | 9 | it "renders an empty delivery edit form" do 10 | delivery = mock_model(Delivery, :package => nil, :fee => nil, 11 | :delivering_user => nil, 12 | :start_location => nil, 13 | :end_location => nil) 14 | assign(:delivery, delivery) 15 | 16 | render 17 | 18 | end 19 | end -------------------------------------------------------------------------------- /app/views/users/_menu.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 21 |
22 | -------------------------------------------------------------------------------- /spec/views/deliveries/index.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/deliveries/index.html.erb" do 4 | before(:each) do 5 | end 6 | 7 | it "should render when someone is logged in" do 8 | view.should_receive(:user_signed_in?).twice.and_return(true) 9 | user = mock_model(User) 10 | assign(:clocked_ins,[user]) 11 | user.should_receive(:clocked_in?).and_return(false) 12 | user.should_receive(:username).and_return("bob") 13 | assign(:delivery_groups, []) 14 | view.should_receive(:current_user).twice.and_return(user) 15 | render 16 | rendered.should have_selector('p') 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /app/views/users/_profile.html.erb: -------------------------------------------------------------------------------- 1 | Username: <%=h @user.username %>
2 | Email: 3 | <% if current_user == @user %> 4 | <%= @user.email %> 5 | <% else %> 6 | Hidden 7 | <% end %> 8 |
9 | Time zone: <%= @user.time_zone %>
10 | Units: <%if @user.display_measurement == "imperial" %> 11 | Imperial (miles/pounds) 12 | <% end %> 13 | <%if @user.display_measurement == "metric" %> 14 | Metric (meters/kilograms) 15 | <% end %> 16 |
17 | <% if @user.email_on_new_listing %> 18 | Send 19 | <% else %> 20 | Do not send 21 | <% end %> 22 | an email when a new delivery is created.
23 | -------------------------------------------------------------------------------- /app/views/journal/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for(:title) do %> 2 | Journal 3 | <% end %> 4 | <%= @entries.size %> journal entries in the last month. 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <% @entries.each do |e| %> 15 | 16 | 17 | 18 | 19 | 20 | 21 | <% end %> 22 |
date delivery user note
<%=h e.created_at.in_time_zone("Pacific Time (US & Canada)").strftime('%h-%d %H:%m')%><%=e.delivery ? link_to(e.delivery_id, delivery_path(e.delivery_id)) : nil%><%=h e.user ? link_to(h(truncate(e.user.username, :length => 15)), user_path(e.user)) : nil%><%=h e.note%>
23 | -------------------------------------------------------------------------------- /db/migrate/20101207021937_create_slugs.rb: -------------------------------------------------------------------------------- 1 | class CreateSlugs < ActiveRecord::Migration 2 | def self.up 3 | create_table :slugs do |t| 4 | t.string :name 5 | t.integer :sluggable_id 6 | t.integer :sequence, :null => false, :default => 1 7 | t.string :sluggable_type, :limit => 40 8 | t.string :scope 9 | t.datetime :created_at 10 | end 11 | add_index :slugs, :sluggable_id 12 | add_index :slugs, [:name, :sluggable_type, :sequence, :scope], :name => "index_slugs_on_n_s_s_and_s", :unique => true 13 | 14 | # add_column :users, :cached_slug, :string 15 | end 16 | 17 | def self.down 18 | drop_table :slugs 19 | # remove_column :users, :cached_slug 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/mailers/delivery_mailer.rb: -------------------------------------------------------------------------------- 1 | class DeliveryMailer < ActionMailer::Base 2 | default from: SETTINGS["email"]["from"] 3 | 4 | def updated(delivery, user) 5 | @delivery = delivery 6 | mail(:to => user.email, 7 | :subject => "Delivery ##{delivery.id} details updated.") 8 | end 9 | 10 | def accepted(delivery) 11 | @delivery = delivery 12 | mail(:to => delivery.listing_user.email, 13 | :subject => "Delivery ##{delivery.id} accepted for delivery.") 14 | end 15 | 16 | def comment(delivery, comment) 17 | @delivery = delivery 18 | @comment = comment 19 | mail(:to => delivery.listing_user.email, 20 | :subject => "Delivery ##{delivery.id} has a new comment") 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | EveryoneDelivers::Application.routes.draw do 2 | resources :deliveries do 3 | member do 4 | put :accept 5 | put :confirm 6 | post :comment 7 | delete :comment_delete 8 | end 9 | end 10 | 11 | resources :users do 12 | member do 13 | put :update_location 14 | post :clock_in 15 | post :clock_out 16 | post :add_schedule 17 | get :schedule 18 | end 19 | end 20 | 21 | resources :locations 22 | resources :packages 23 | 24 | devise_for :users 25 | match '/' => 'dashboard#index', :as => :root 26 | match '/journal' => 'journal#index' 27 | match '/journal/count' => 'journal#count' 28 | match '/:controller(/:action(/:id))' 29 | 30 | end 31 | -------------------------------------------------------------------------------- /spec/models/package_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe Package do 4 | before(:each) do 5 | @valid_attributes = { 6 | } 7 | end 8 | 9 | it "should create a new instance given valid attributes" do 10 | Package.create!(@valid_attributes) 11 | end 12 | 13 | it "should sanitize and store new attributes" do 14 | package = Package.create!(@valid_attributes) 15 | description="desc" 16 | form_attributes = { :description => description, :height => "3.30" } 17 | package.apply_form_attributes(form_attributes) 18 | package.description.should == description 19 | package.height_in_meters.should > 0.08 #fix 20 | package.height_in_meters.should < 0.09 #fix 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/models/schedule.rb: -------------------------------------------------------------------------------- 1 | class Schedule < ActiveRecord::Base 2 | belongs_to :user 3 | 4 | def apply_form_fields(params) 5 | if params[:street1] 6 | self.street1 = params[:street1] 7 | end 8 | if params[:street2] 9 | self.street2 = params[:street2] 10 | end 11 | 12 | # default 13 | self.starting_at = Time.now 14 | 15 | if params["ending_at(1i)"] 16 | self.ending_at = Time.parse("#{params["ending_at(1i)"]}-#{params["ending_at(2i)"]}-#{params["ending_at(3i)"]} "+ 17 | "#{params["ending_at(4i)"]}:#{params["ending_at(5i)"]}") 18 | end 19 | 20 | if params[:latitude] 21 | self.latitude = params[:latitude] 22 | end 23 | if params[:street2] 24 | self.longitude = params[:longitude] 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /app/views/deliveries/_single_address_map.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%= image_tag location.gmap_static_html(100,100,14).html_safe, :alt => "map of #{location.name}" %> 5 |
6 |
7 |
<%= direction %> 8 | <% if to %> 9 | <%= link_to(to.username, to) %> 10 | <% end %>
11 |
12 | <% if location.name %> 13 | <%= location.name %>
14 | <% end %> 15 | <% location.street_parts.each do |part| %> 16 | <%=h part %>
17 | <% end %> 18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |

We've been notified about this issue and we'll take a look at it shortly.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /app/views/dashboard/biglogin.html: -------------------------------------------------------------------------------- 1 |
2 |

3 |

4 | Login with Google
5 | <%= link_to image_tag("google_button_150_47.png"), :controller => :session, 6 | :action => :login, 7 | :openid_identifier => "https://www.google.com/accounts/o8/id" %> 8 |
9 |
10 | Login with Yahoo
11 | <%= link_to image_tag("yahoo_button_150_47.png"), :controller => :session, 12 | :action => :login, 13 | :openid_identifier => "http://www.yahoo.com" %> 14 |
15 |

16 | 17 |
18 | -------------------------------------------------------------------------------- /app/views/dashboard/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

3 | EveryoneDelivers is a marketplace for delivery services. 4 |

5 | 6 |
7 |
8 |

9 | <%= link_to "Request a delivery.", deliveries_path, :method => :post %> 10 |

11 |

12 | Have items and food delivered to 13 | your door. You set the delivery cost. 14 |

15 |
16 |
17 |

18 | <%= link_to "See delivery requests.", deliveries_path %> 19 |

20 |

21 | Deliver items to people and earn 22 | the delivery bounty. 23 |

24 |
25 |
26 | 27 |
28 |
29 |
30 | <%= render :partial => "deliveries/single", :locals => {:delivery => @featured_delivery} %> 31 |
32 | 33 |
34 | -------------------------------------------------------------------------------- /app/views/layouts/_getsatisfaction.html.erb: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | -------------------------------------------------------------------------------- /db/migrate/20090424003439_add_open_id_store_to_db.rb: -------------------------------------------------------------------------------- 1 | # Use this migration to create the tables for the ActiveRecord store 2 | class AddOpenIdStoreToDb < ActiveRecord::Migration 3 | def self.up 4 | create_table "open_id_associations", :force => true do |t| 5 | t.column "server_url", :binary, :null => false 6 | t.column "handle", :string, :null => false 7 | t.column "secret", :binary, :null => false 8 | t.column "issued", :integer, :null => false 9 | t.column "lifetime", :integer, :null => false 10 | t.column "assoc_type", :string, :null => false 11 | end 12 | 13 | create_table "open_id_nonces", :force => true do |t| 14 | t.column :server_url, :string, :null => false 15 | t.column :timestamp, :integer, :null => false 16 | t.column :salt, :string, :null => false 17 | end 18 | end 19 | 20 | def self.down 21 | drop_table "open_id_associations" 22 | drop_table "open_id_nonces" 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/views/dashboard/contact.html.erb: -------------------------------------------------------------------------------- 1 |

Contact

2 | 3 |

People

4 |

5 | <%= image_tag 'don-hottub-deck.jpg', :style => "float: right; margin-left: 4em" %> 6 |

7 | <%= link_to 'Don Park', user_path('don-park')%> - Founder.
8 | Portland technologist and systems experimenter. 9 | don.park@everyonedelivers.com 10 |

11 |

12 | 13 |

Thanks to

14 | 22 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | EveryoneDelivers <%= yield :title %> 5 | <%= favicon_link_tag 'wheel.png' %> 6 | <%= stylesheet_link_tag "application" %> 7 | <%= javascript_include_tag "application" %> 8 | <%= csrf_meta_tags %> 9 | <%= render :partial => "layouts/google_maps" %> 10 | <%= yield :header %> 11 | 12 | 13 |
14 | <%# render :partial => "layouts/geode" %> 15 | <%= render :partial => "layouts/header" %> 16 | <% unless params[:controller] == "dashboard" %> 17 | <%= render :partial => "layouts/menubar" %> 18 | <% end %> 19 | <%= render :partial => "layouts/flashmsg" %> 20 |
21 | <%= yield %> 22 |
23 | <%= render :partial => "layouts/footer" %> 24 | <%= render :partial => "layouts/google_analytics" %> 25 | <%= render :partial => "layouts/getsatisfaction" %> 26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /app/models/fee.rb: -------------------------------------------------------------------------------- 1 | class Fee < ActiveRecord::Base 2 | has_many :deliveries 3 | 4 | def apply_form_attributes(params) 5 | return if params.nil? 6 | 7 | if params[:display_price] 8 | self.price_in_cents = (params[:display_price].to_f*100).to_i 9 | end 10 | 11 | if params["delivery_due(1i)"] 12 | time_string = "#{params["delivery_due(1i)"]}-#{params["delivery_due(2i)"]}-#{params["delivery_due(3i)"]} #{params["delivery_due(4i)"]}:#{params["delivery_due(5i)"]}" 13 | delivery_due_time = Time.zone.parse(time_string) 14 | self.delivery_due = delivery_due_time 15 | end 16 | 17 | if params[:payment_method] 18 | self.payment_method = params[:payment_method] 19 | end 20 | end 21 | 22 | def display_price 23 | "%0.2f" % float_price 24 | end 25 | 26 | def float_price 27 | if self.price_in_cents 28 | self.price_in_cents / 100.0 29 | else 30 | 0.0 31 | end 32 | end 33 | 34 | def ok_to_display? 35 | true 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe User do 4 | before(:each) do 5 | valid_attributes = { 6 | :username => "testuser", 7 | :email => "some@user", 8 | :authentication_token => "abc123" 9 | } 10 | @user = User.create!(valid_attributes) 11 | end 12 | 13 | it "should create a new instance given valid attributes" do 14 | @user.should be_valid 15 | end 16 | 17 | it "should clock in a user" do 18 | @user.clock_in! 19 | @user.should be_clocked_in 20 | end 21 | 22 | it "should clock out a user" do 23 | @user.clock_out! 24 | @user.should_not be_clocked_in 25 | end 26 | 27 | it "should tell who can edit this user" do 28 | @user.available_for_edit_by(nil).should be_false 29 | @user.available_for_edit_by(@user).should be_true 30 | end 31 | 32 | it "should find the completed deliveries for a given month" do 33 | @deliveries = @user.accepted_deliveries(2009,10) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | 3 | gem 'rails', '3.2.11' 4 | 5 | # Bundle edge Rails instead: 6 | # gem 'rails', :git => 'git://github.com/rails/rails.git' 7 | 8 | gem 'pg' 9 | 10 | 11 | # Gems used only for assets and not required 12 | # in production environments by default. 13 | group :assets do 14 | gem 'sass-rails', " ~> 3.2.5" 15 | gem 'coffee-rails', "~> 3.2.2" 16 | gem 'uglifier' 17 | end 18 | 19 | gem 'jquery-rails' 20 | gem 'devise' 21 | gem 'workflow' 22 | gem 'friendly_id', "~> 3.3.3.0" 23 | gem 'loofah' 24 | gem 'uuidtools' 25 | gem 'exception_notification' 26 | gem 'delayed_job_active_record' 27 | gem 'twitter' 28 | 29 | # Use unicorn as the web server 30 | # gem 'unicorn' 31 | 32 | # Deploy with Capistrano 33 | # gem 'capistrano' 34 | 35 | # To use debugger 36 | # gem 'ruby-debug19', :require => 'ruby-debug' 37 | 38 | group :development, :test do 39 | gem 'sqlite3' 40 | # Pretty printed test output 41 | gem 'turn', :require => false 42 | gem 'rspec-rails' 43 | gem 'webrat' 44 | gem 'letter_opener' 45 | end 46 | 47 | group :production do 48 | gem 'unicorn' 49 | end 50 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV["RAILS_ENV"] ||= 'test' 3 | require File.expand_path("../../config/environment", __FILE__) 4 | require 'rspec/rails' 5 | require 'webrat' 6 | 7 | # Requires supporting ruby files with custom matchers and macros, etc, 8 | # in spec/support/ and its subdirectories. 9 | Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} 10 | 11 | RSpec.configure do |config| 12 | # == Mock Framework 13 | # 14 | # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: 15 | # 16 | # config.mock_with :mocha 17 | # config.mock_with :flexmock 18 | # config.mock_with :rr 19 | config.mock_with :rspec 20 | 21 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 22 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 23 | 24 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 25 | # examples within a transaction, remove the following line or assign false 26 | # instead of true. 27 | config.use_transactional_fixtures = true 28 | end 29 | -------------------------------------------------------------------------------- /app/views/layouts/_header.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |
6 |
7 | <%= form_tag({:controller => :session, :action => :login}, {:id => 'loginform'}) do %> 8 | 9 | 10 | <% if user_signed_in? %> 11 | <%= link_to h(current_user.username), current_user, :class => "username" %> - 12 | <%= link_to t('header.logout'), :controller => :session, :action => :logout %> 13 | <% else %> 14 | Email: <%= text_field_tag :email, nil, :placeholder => t('header.email_login_placeholder'), 15 | :size => 20, :type => "email" %> 16 | <%= submit_tag t('header.login') %> 17 | <% end %> 18 | <% end %> 19 |
20 | 24 |
25 | 26 | 27 | 33 | -------------------------------------------------------------------------------- /spec/controllers/users_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe UsersController do 4 | 5 | before(:each) do 6 | controller.stub!(:authenticate_user!) 7 | controller.stub!(:set_timezone) 8 | @user = mock_model(User) 9 | controller.stub!(:current_user).and_return(@user) 10 | end 11 | 12 | it "should display details for a user" do 13 | user = mock_model(User) 14 | User.should_receive(:find).with(user.id.to_s).and_return(user) 15 | get :show, {:id => user.id} 16 | end 17 | 18 | it "should clock in a user" do 19 | User.should_receive(:find).with(@user.id.to_s).and_return(@user) 20 | @user.should_receive(:add_schedule) 21 | @user.should_receive(:clock_in!) 22 | @user.should_receive(:username).and_return('bob') 23 | get :clock_in, {:id => @user.id} 24 | response.should redirect_to(deliveries_path) 25 | end 26 | 27 | it "should clock out a user" do 28 | User.should_receive(:find).with(@user.id.to_s).and_return(@user) 29 | @user.should_receive(:clock_out!) 30 | @user.should_receive(:username).and_return('bob') 31 | get :clock_out, {:id => @user.id} 32 | response.should redirect_to(deliveries_path) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /app/models/location.rb: -------------------------------------------------------------------------------- 1 | class Location < ActiveRecord::Base 2 | has_many :deliveries 3 | has_many :sightings 4 | has_many :users, :through => :sightings 5 | 6 | def apply_form_attributes(params) 7 | return if params.nil? 8 | self.name = params[:name] 9 | self.street = params[:address] #todo: google geocode the address 10 | self.latitude = params[:latitude] 11 | self.longitude = params[:longitude] 12 | self.accuracy = params[:accuracy] 13 | end 14 | 15 | def ok_to_display? 16 | street && street.size > 0 17 | end 18 | 19 | def geocode! 20 | 21 | end 22 | 23 | def gmap_static_html(h,w,z) 24 | "http://dev.virtualearth.net/REST/v1/Imagery/Map/Road/?mapSize=#{h},#{w}&pushpin=#{self.latitude},#{self.longitude};33&key=#{SETTINGS["bing"]["maps"]["key"]}" 25 | # "http://maps.google.com/staticmap?center=#{self.latitude},#{self.longitude}&zoom=#{z}&size=#{h}x#{w}&key=#{SETTINGS["google"]["maps"]["key"]}&sensor=false&markers=#{self.latitude},#{self.longitude}" 26 | # "http://staticmap.openstreetmap.de/staticmap.php?center=#{self.latitude},#{self.longitude}&zoom=#{z}&size=#{h}x#{w}&markers=#{self.latitude},#{self.longitude}" 27 | end 28 | 29 | def street_parts 30 | parts = street.split(',',street.count(',')) 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /db/migrate/20111006165028_create_delayed_jobs.rb: -------------------------------------------------------------------------------- 1 | class CreateDelayedJobs < ActiveRecord::Migration 2 | def self.up 3 | create_table :delayed_jobs, :force => true do |table| 4 | table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue 5 | table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually. 6 | table.text :handler # YAML-encoded string of the object that will do work 7 | table.text :last_error # reason for last failure (See Note below) 8 | table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future. 9 | table.datetime :locked_at # Set when a client is working on this object 10 | table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead) 11 | table.string :locked_by # Who is working on this object (if locked) 12 | table.timestamps 13 | end 14 | 15 | add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority' 16 | end 17 | 18 | def self.down 19 | drop_table :delayed_jobs 20 | end 21 | end -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | EveryoneDelivers::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send 17 | config.action_mailer.raise_delivery_errors = false 18 | config.action_mailer.delivery_method = :letter_opener 19 | 20 | # Print deprecation notices to the Rails logger 21 | config.active_support.deprecation = :log 22 | 23 | # Only use best-standards-support built into browsers 24 | config.action_dispatch.best_standards_support = :builtin 25 | 26 | # Do not compress assets 27 | config.assets.compress = false 28 | 29 | # Expands the lines which load the assets 30 | config.assets.debug = true 31 | end 32 | -------------------------------------------------------------------------------- /app/controllers/session_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionController < ApplicationController 2 | 3 | def login_token 4 | user = User.find_by_authentication_token(params[:token]) 5 | if user 6 | logger.info("session: #{session.inspect}") 7 | sign_in user 8 | logger.info("session after login: #{session.inspect}") 9 | if session[:anonymous_delivery_id] 10 | delivery = Delivery.find(session[:anonymous_delivery_id]) 11 | redirect_to edit_delivery_path(delivery) 12 | else 13 | redirect_to :deliveries 14 | end 15 | else 16 | flash[:error] = "The login link is not valid. Please login with your email address to get a new link." 17 | redirect_to :root 18 | end 19 | end 20 | 21 | def login 22 | # email validation 23 | unless params[:email] && params[:email][/.@./] 24 | flash[:error] = "Please use an email address." 25 | redirect_to :root 26 | return 27 | end 28 | user = User.find_by_email(params[:email]) 29 | unless user 30 | logger.info "creating user #{params}" 31 | user = User.create_with_defaults!(:email => params[:email]) 32 | end 33 | logger.info "sending login email to #{user.email}" 34 | UserMailer.login_token_email(user).deliver 35 | flash[:notice] = "Login instructions sent to #{user.email}." 36 | redirect_to :deliveries 37 | end 38 | 39 | def logout 40 | reset_session 41 | flash[:notice] = "logged out" 42 | redirect_to :root 43 | end 44 | 45 | end 46 | -------------------------------------------------------------------------------- /app/controllers/git_hub_controller.rb: -------------------------------------------------------------------------------- 1 | class GitHubController < ApplicationController 2 | protect_from_forgery :except => :commit 3 | 4 | # Example github post 5 | #Processing ApplicationController#commit (for ::ffff:65.74.177.129 at 2009-06-23 06:03:24) [POST] 6 | #Parameters: {"payload"=>"{\"after\": \"801db8c488a37ff9a888a6fc1b5a5fca5290aeab\", \"ref\": \"refs/heads/master\", \"repository\": {\"owner\": {\"name\": \"donpdonp\", \"email\": \"don.park@gmail.com\"}, \"description\": \"crowdsourced services market\", \"forks\": 0, \"name\": \"everyonedelivers\", \"private\": false, \"url\": \"http://github.com/donpdonp/everyonedelivers\", \"fork\": false, \"watchers\": 1, \"homepage\": \"http://everyonedelivers.com\"}, \"before\": \"c4794c51b48bbf72951a8229556365fa67e1bbed\", \"commits\": [{\"modified\": [\"app/controllers/git_hub_controller.rb\"], \"added\": [], \"url\": \"http://github.com/donpdonp/everyonedelivers/commit/801db8c488a37ff9a888a6fc1b5a5fca5290aeab\", \"timestamp\": \"2009-06-22T23:03:14-07:00\", \"message\": \"always test.\", \"removed\": [], \"author\": {\"name\": \"Don Park\", \"email\": \"don@donpark.org\"}, \"id\": \"801db8c488a37ff9a888a6fc1b5a5fca5290aeab\"}]}"} 7 | def commit 8 | gparams = JSON.parse(params["payload"]) 9 | logger.info("github params: #{gparams}") 10 | Journal.create({:note => "Website code updated to #{gparams["after"]}"}) 11 | cmd = Rails.root+"github-pull.sh" 12 | logger.info("github commit: #{cmd}") 13 | out = shell(cmd) 14 | logger.info("github pull output: #{out}") 15 | render :nothing => true 16 | end 17 | 18 | # so we can mock this in a test 19 | def shell(cmd) 20 | `/bin/sh #{cmd}` 21 | end 22 | 23 | end 24 | -------------------------------------------------------------------------------- /app/views/deliveries/index.html.erb: -------------------------------------------------------------------------------- 1 |

2 | Deliver an item and earn the bounty! 3 |

4 | 5 |
6 |
7 |

8 | Available delivery people 9 |

10 |
11 |
    12 | <% @clocked_ins.each do |user| %> 13 | <% schedule = user.schedules.last %> 14 |
  • 15 | 16 | <%= link_to h(user.username), user %> 17 | 18 | 19 | <%= schedule.street1 %> and <%= schedule.street2 %> 20 | 21 | 22 | 23 |
  • 24 | <% end %> 25 |
26 |
27 |
28 |
29 | <% if user_signed_in? %> 30 | <% clockedin = current_user.clocked_in? %> 31 |
"> 32 | Clocked
33 | <%= clockedin ? "In" : "Out"%> 34 |
35 | <% if clockedin %> 36 | <%= form_tag(clockedin ? clock_out_user_path(current_user) : clock_in_user_path(current_user)) do %> 37 | <%= submit_tag "Clock #{clockedin ? "OUT" : "IN"}" %> 38 | <% end %> 39 | <% else %> 40 | <%= link_to 'Clock in', schedule_user_path(current_user) %> 41 | <% end %> 42 |
43 | <% end %> 44 |
45 | 46 |
47 | <% @delivery_groups.each do |group| %> 48 | <%= render :partial => 'deliveries/list', :locals => {:timedesc => group.first, :deliveries => group.last} %> 49 | <% end %> 50 |
51 | 52 | <% if user_signed_in? %> 53 | <% else %> 54 | Login to create or accept a delivery. 55 | <% end %> 56 | -------------------------------------------------------------------------------- /app/views/layouts/_geode.html.erb: -------------------------------------------------------------------------------- 1 | 45 | -------------------------------------------------------------------------------- /app/views/users/edit.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Edit User

3 | <%= form_for @user do |f| %> 4 |
5 | Identity 6 | <%= f.label :username, "username:" %> 7 | <%= f.text_field :username, :size => 40 %>
8 | <%= f.label :email, "email:" %> 9 | <%= @user.errors[:email].join %> 10 | <%= f.text_field :email, :size => 40 %> 11 |
12 |
13 | Internationalization 14 | <%= f.label :time_zone, "time zone:" %> 15 | <%= @user.errors[:time_zone].join %> 16 | <%= f.time_zone_select :time_zone, ActiveSupport::TimeZone.us_zones, :include_blank => true %> 17 | <% if @user.time_zone.blank? %> 18 | 33 | <% end %> 34 |
35 | <%= f.label :display_measurement, "units:" %> 36 | <%= @user.errors[:display_measurement].join %> 37 | <%= f.select :display_measurement, [["Imperial (pounds/inches)","imperial"],["Metric (grams/meters)","metric"]] %> 38 |
39 |
40 | Notification 41 | <%= f.label :email_on_new_listing, "Send an email for each new delivery listing:" %> 42 | <%= f.check_box :email_on_new_listing %> 43 |
44 |
45 | <%= f.submit %> 46 | <% end %> 47 |
48 | -------------------------------------------------------------------------------- /app/models/package.rb: -------------------------------------------------------------------------------- 1 | class Package < ActiveRecord::Base 2 | has_one :delivery 3 | 4 | def apply_form_attributes(params) 5 | return if params.nil? 6 | 7 | if params[:description] 8 | self.description = params[:description] 9 | end 10 | if params[:height] 11 | self.height_in_meters = inches_to_meters(params[:height]) 12 | end 13 | if params[:width] 14 | self.width_in_meters = inches_to_meters(params[:width]) 15 | end 16 | if params[:depth] 17 | self.depth_in_meters = inches_to_meters(params[:depth]) 18 | end 19 | if params[:weight] 20 | self.weight_in_grams = ounces_to_grams(params[:weight]) 21 | end 22 | if params[:display_price] 23 | self.price_in_cents = (params[:display_price].to_f*100).to_i 24 | end 25 | end 26 | 27 | def ok_to_display? 28 | description && description.size > 0 29 | end 30 | 31 | def has_dimensions? 32 | height_in_meters && width_in_meters && depth_in_meters 33 | end 34 | 35 | def height 36 | "%0.1f" % meters_to_inches(self.height_in_meters) 37 | end 38 | 39 | def width 40 | "%0.1f" % meters_to_inches(self.width_in_meters) 41 | end 42 | 43 | def depth 44 | "%0.1f" % meters_to_inches(self.depth_in_meters) 45 | end 46 | 47 | def weight 48 | "%0.1f" % grams_to_ounces(self.weight_in_grams) 49 | end 50 | 51 | def inches_to_meters(inch_s) 52 | inch_s.to_f*0.0254 53 | end 54 | 55 | def meters_to_inches(meters) 56 | meters/0.0254 57 | end 58 | 59 | def ounces_to_grams(ounces_s) 60 | ounces_s.to_f*28.3495 61 | end 62 | 63 | def grams_to_ounces(meters) 64 | weight_in_grams/28.3495 65 | end 66 | 67 | def display_price 68 | "%0.2f" % float_price 69 | end 70 | 71 | def float_price 72 | if self.price_in_cents 73 | self.price_in_cents / 100.0 74 | else 75 | 0.0 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /app/views/users/schedule.html.erb: -------------------------------------------------------------------------------- 1 | <% last_schedule = current_user.schedules.last %> 2 | 11 | 12 |
13 | 14 |

15 | Clock-In Position 16 |

17 | 18 | 19 | 20 | 21 |
22 |
23 | Center the map by address:
24 | 25 |
26 |
27 |
28 | 29 | <%= form_tag({:action => :clock_in}, {:id => "schedule_add"}) do %> 30 | 36 | 37 | 38 |

39 |

40 | Drag the map marker to your current location.
41 | The nearest intersection is used for 42 | your privacy.
43 |

44 | Nearest Intersection: (waiting for map) 45 |

46 |
47 | 48 | 49 | 50 | 51 |

52 | 53 | <%= submit_tag "Clock In"%> 54 | <% end %> 55 | 56 |
-------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | EveryoneDelivers::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Use SQL instead of Active Record's schema dumper when creating the test database. 33 | # This is necessary if your schema can't be completely dumped by the schema dumper, 34 | # like if you have constraints or database-specific column types 35 | # config.active_record.schema_format = :sql 36 | 37 | # Print deprecation notices to the stderr 38 | config.active_support.deprecation = :stderr 39 | 40 | # Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets 41 | config.assets.allow_debugging = true 42 | end 43 | -------------------------------------------------------------------------------- /spec/models/delivery_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe Delivery do 4 | fixtures :deliveries 5 | 6 | before(:each) do 7 | @valid_attributes = { 8 | } 9 | end 10 | 11 | it "should create a new instance given valid attributes" do 12 | Delivery.create!(@valid_attributes) 13 | end 14 | 15 | it "should find deliveries at most X hours old" do 16 | time = Time.parse("2009-01-01 12:45 UTC") 17 | deliveries = Delivery.find_at_most_hours_old(1,time) 18 | deliveries.size.should == 2 19 | # return in time-sorted order 20 | deliveries.first.created_at.should > deliveries.last.created_at 21 | end 22 | 23 | it "should find deliveries between X and Y X hours old" do 24 | time = Time.parse("2009-01-01 12:45 UTC") 25 | deliveries = Delivery.find_between_hours_old(1, 2, time) 26 | deliveries.size.should == 2 27 | # return in time-sorted order 28 | deliveries.first.created_at.should > deliveries.last.created_at 29 | end 30 | 31 | it "should find deliveries more than X hours old" do 32 | time = Time.parse("2009-01-01 12:45 UTC") 33 | deliveries = Delivery.find_more_than_hours_old(4, time) 34 | deliveries.size.should == 2 35 | # return in time-sorted order 36 | deliveries.first.created_at.should > deliveries.last.created_at 37 | end 38 | 39 | it "should start with the building state" do 40 | delivery = Delivery.new 41 | delivery.building?.should be_true 42 | end 43 | 44 | it "test if the delivery data is complete" do 45 | delivery = Delivery.new 46 | delivery.should_receive(:building?).and_return(true) 47 | delivery.should_receive(:ok_to_display?).and_return(true) 48 | delivery.should_receive(:ready!).and_return(true) 49 | delivery.check_for_completeness 50 | end 51 | 52 | it "journal and send email when ready" do 53 | delivery = Delivery.new 54 | delivery.should_receive(:email_notify_users) 55 | delivery.ready! 56 | end 57 | 58 | end 59 | -------------------------------------------------------------------------------- /app/views/deliveries/_single.html.erb: -------------------------------------------------------------------------------- 1 | <% if delivery.ok_to_display? %> 2 |
" style="margin-bottom: 10px;"> 3 | 4 |
"> 5 |
6 | <% if delivery.delivered? %> 7 | Delivered by 8 | <%= link_to h(delivery.delivering_user.username), delivery.delivering_user %> 9 | <% else %> 10 | <%= render :partial => "deliveries/single_due", :locals => {:fee => delivery.fee} %> 11 | <% end %> 12 |
13 | <%= link_to h(truncate(delivery.package.description, :length => 45)), delivery_path(delivery) %> 14 |
15 | 16 |
17 |
18 | Bounty 19 |
20 |
21 | $<%= delivery.fee.display_price %> 22 |
23 |
24 | 25 |
26 |
27 | <%= render :partial => "deliveries/single_address_map", 28 | :locals => {:location => delivery.start_location, 29 | :direction => "From:", :to => nil} %> 30 |
31 | 32 |
33 | <%= render :partial => "deliveries/single_address_map", 34 | :locals => {:location => delivery.end_location, 35 | :direction => "To: ", 36 | :to => delivery.listing_user} %> 37 |
38 |
39 | 40 | <% if delivery.available_for_delivery_by(current_user) %> 41 |
42 | <%= form_for delivery, :url => confirm_delivery_path(delivery), 43 | :html => {:method => :put} do |f| %> 44 | <%= f.submit 'I can make this delivery' %> 45 | <% end %> 46 |
47 | <% end %> 48 |
49 | <% end %> 50 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_filter :authenticate_user!, :except => [:show] 3 | protect_from_forgery :except => :update_location 4 | 5 | def show 6 | @user = User.find(params[:id]) 7 | end 8 | 9 | def edit 10 | @user = User.find(params[:id]) 11 | @user.soft_validate 12 | unless @user && @user.available_for_edit_by(current_user) 13 | flash[:error] = "Not allowed to edit #{params[:id]}" 14 | redirect_to root_path 15 | end 16 | end 17 | 18 | def update 19 | @user = User.find(params[:id]) 20 | if current_user == @user 21 | @user.apply_form_attributes(params[:user]) 22 | begin 23 | @user.save! 24 | flash[:notice] = "Profile updated" 25 | rescue ActiveRecord::RecordInvalid => e 26 | flash[:error] = "#{e}" 27 | end 28 | redirect_to @user 29 | else 30 | flash[:error] = "Permission denied" 31 | redirect_to root_path; 32 | end 33 | end 34 | 35 | def update_location 36 | @user = User.find(params[:id]) 37 | if current_user == @user 38 | location = Location.new 39 | location.apply_form_attributes(params) 40 | @user.locations << location 41 | end 42 | render :nothing => true 43 | end 44 | 45 | def clock_in 46 | @user = User.find(params[:id]) 47 | if current_user == @user 48 | schedule = Schedule.new 49 | schedule.apply_form_fields(params[:schedule]) 50 | @user.schedules << schedule 51 | @user.clock_in! 52 | flash[:notice] = "#{@user.username} is clocked in for one hour! Good luck." 53 | else 54 | flash[:error] = "Not authorized to clock in #{@user.username}" 55 | end 56 | redirect_to deliveries_path 57 | end 58 | 59 | def clock_out 60 | @user = User.find(params[:id]) 61 | if current_user == @user 62 | @user.clock_out! 63 | flash[:notice] = "#{@user.username} has been clocked out." 64 | else 65 | flash[:error] = "Not authorized to clock out #{@user.username}" 66 | end 67 | redirect_to deliveries_path 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | if defined?(Bundler) 6 | # If you precompile assets before deploying to production, use this line 7 | Bundler.require *Rails.groups(:assets => %w(development test)) 8 | # If you want your assets lazily compiled in production, use this line 9 | # Bundler.require(:default, :assets, Rails.env) 10 | end 11 | 12 | module EveryoneDelivers 13 | class Application < Rails::Application 14 | # Settings in config/environments/* take precedence over those specified here. 15 | # Application configuration should go into files in config/initializers 16 | # -- all .rb files in that directory are automatically loaded. 17 | 18 | # Custom directories with classes and modules you want to be autoloadable. 19 | # config.autoload_paths += %W(#{config.root}/extras) 20 | 21 | # Only load the plugins named here, in the order given (default is alphabetical). 22 | # :all can be used as a placeholder for all plugins not explicitly named. 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 24 | 25 | # Activate observers that should always be running. 26 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 27 | 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 30 | # config.time_zone = 'Central Time (US & Canada)' 31 | 32 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 33 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 34 | # config.i18n.default_locale = :de 35 | 36 | # Configure the default encoding used in templates for Ruby 1.9. 37 | config.encoding = "utf-8" 38 | 39 | # Configure sensitive parameters which will be filtered from the log file. 40 | config.filter_parameters += [:password] 41 | 42 | # Enable the asset pipeline 43 | config.assets.enabled = true 44 | 45 | # Version of your assets, change this if you want to expire all your assets 46 | config.assets.version = '1.0' 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/views/deliveries/show.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "/deliveries/show.html.erb" do 4 | before(:each) do 5 | view.stub!(:user_signed_in?).and_return(false) 6 | user = mock_model(User, :display_measurement => "metric") 7 | view.stub!(:current_user).and_return(user) 8 | end 9 | 10 | it "should render a delivery in the building state" do 11 | # Setup an empty delivery 12 | location = mock("Location", :latitude => 1, :longitude => 2, 13 | :street => "123 main") 14 | delivery = mock_model(Delivery, :start_location => location, :end_location => location) 15 | delivery.should_receive(:created_at).and_return(Time.now) 16 | delivery.should_receive(:listing_user) 17 | delivery.should_receive(:package).twice 18 | fee = mock_model(Fee, :delivery_due => Time.now, 19 | :display_price => "1", 20 | :payment_method => "cash") 21 | delivery.should_receive(:fee).and_return(fee) 22 | delivery.should_receive(:delivering_user) 23 | delivery.should_receive(:available_for_edit_by) 24 | delivery.should_receive(:start_end_distance) 25 | delivery.should_receive(:waiting?).and_return(false) 26 | assign(:delivery, delivery) 27 | 28 | render 29 | end 30 | 31 | it "should render a delivery with waiting state" do 32 | current_user = mock_model(User) 33 | view.should_receive(:current_user).twice.and_return(current_user) 34 | # Setup an empty delivery 35 | delivery = mock_model(Delivery) 36 | delivery.should_receive(:created_at).and_return(Time.now) 37 | user = mock_model(User) 38 | user.should_receive(:username).and_return("Bob") 39 | delivery.should_receive(:listing_user).and_return(user) 40 | delivery.should_receive(:package) 41 | delivery.should_receive(:start_location) 42 | delivery.should_receive(:start_location) 43 | delivery.should_receive(:start_location) 44 | delivery.should_receive(:end_location) 45 | delivery.should_receive(:fee) 46 | delivery.should_receive(:delivering_user) 47 | delivery.should_receive(:start_end_distance) 48 | delivery.should_receive(:available_for_delivery_by).with(current_user).and_return(false) 49 | delivery.should_receive(:available_for_edit_by).with(current_user).and_return(false) 50 | delivery.should_receive(:waiting?).and_return(true) 51 | delivery.should_receive(:comments).and_return([]) 52 | assign(:delivery, delivery) 53 | 54 | render 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | EveryoneDelivers::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to Rails.root.join("public/assets") 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Use a different logger for distributed setups 37 | # config.logger = SyslogLogger.new 38 | 39 | # Use a different cache store in production 40 | # config.cache_store = :mem_cache_store 41 | 42 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 43 | # config.action_controller.asset_host = "http://assets.example.com" 44 | 45 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 46 | # config.assets.precompile += %w( search.js ) 47 | 48 | # Disable delivery errors, bad email addresses will be ignored 49 | # config.action_mailer.raise_delivery_errors = false 50 | 51 | # Enable threaded mode 52 | # config.threadsafe! 53 | 54 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 55 | # the I18n.default_locale when a translation can not be found) 56 | config.i18n.fallbacks = true 57 | 58 | # Send deprecation notices to registered listeners 59 | config.active_support.deprecation = :notify 60 | end 61 | 62 | ActionMailer::Base.smtp_settings = {:address=>"localhost", 63 | :port=>25, 64 | :domain=>"localhost.localdomain", 65 | :enable_starttls_auto=>false} 66 | 67 | -------------------------------------------------------------------------------- /app/views/deliveries/confirm.html.erb: -------------------------------------------------------------------------------- 1 | 12 | 13 |
14 |

15 | Delivery #<%= @delivery.id %> "<%= @delivery.package.description %>" 16 |

17 | 18 | Are you sure you can make this delivery?
19 | 20 | 21 |
22 |
23 |
24 |
25 |
26 | 27 |
28 |

Plan

29 | 30 | 31 | Step 1: Travel to 32 | <%= @delivery.start_location.street %>
33 | 34 | Step 2: Acquire item, cost: $<%=@delivery.package.display_price%>
35 | 36 |
37 |
38 | Step 3:
39 |   40 |
41 |
42 | Travel to 43 | <%= @delivery.end_location.street %>
44 | Distance: in 45 | <%= distance_of_time_in_words_to_now(@delivery.fee.delivery_due) %>
46 |
47 |
48 |
49 | Step 4: Give item to <%= link_to_user(@delivery.listing_user) %>
50 | 51 | Step 5: Collect $<%=@delivery.package.display_price%> + $<%= @delivery.fee.display_price %> = $<%= @delivery.display_retail_plus_bounty %> paid with <%= @delivery.fee.payment_method %> 52 |
53 |
54 | 55 | 56 | <% if @delivery.fee.payment_method == "visa" %> 57 |

58 | For VISA payments you must be signed up with squareup.com and 59 | have already received the VISA Card reader in the mail. Then you can process a VISA card 60 | at the same time you make the delivery. Accept this delivery only if you are setup 61 | to use Square. 62 |

63 | <% end %> 64 | 65 | 66 |
67 | <%= form_for @delivery, :url => accept_delivery_path(@delivery), :html => {:method => :put} do |f| %> 68 | <%= f.submit 'Yes I accept' %> 69 | <% end %> 70 |
71 | 72 |
73 | <%= form_tag delivery_path(@delivery), :method => :get do %> 74 | <%= submit_tag 'No Thanks' %> 75 | <% end %> 76 |
77 |
-------------------------------------------------------------------------------- /config/locales/devise.en.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at http://github.com/plataformatec/devise/wiki/I18n 2 | 3 | en: 4 | errors: 5 | messages: 6 | expired: "has expired, please request a new one" 7 | not_found: "not found" 8 | already_confirmed: "was already confirmed, please try signing in" 9 | not_locked: "was not locked" 10 | not_saved: 11 | one: "1 error prohibited this %{resource} from being saved:" 12 | other: "%{count} errors prohibited this %{resource} from being saved:" 13 | 14 | devise: 15 | failure: 16 | already_authenticated: 'You are already signed in.' 17 | unauthenticated: 'You need to sign in or sign up before continuing.' 18 | unconfirmed: 'You have to confirm your account before continuing.' 19 | locked: 'Your account is locked.' 20 | invalid: 'Invalid email or password.' 21 | invalid_token: 'Invalid authentication token.' 22 | timeout: 'Your session expired, please sign in again to continue.' 23 | inactive: 'Your account was not activated yet.' 24 | sessions: 25 | signed_in: 'Signed in successfully.' 26 | signed_out: 'Signed out successfully.' 27 | passwords: 28 | send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' 29 | updated: 'Your password was changed successfully. You are now signed in.' 30 | updated_not_active: 'Your password was changed successfully.' 31 | send_paranoid_instructions: "If your e-mail exists on our database, you will receive a password recovery link on your e-mail" 32 | confirmations: 33 | send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' 34 | send_paranoid_instructions: 'If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes.' 35 | confirmed: 'Your account was successfully confirmed. You are now signed in.' 36 | registrations: 37 | signed_up: 'Welcome! You have signed up successfully.' 38 | inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.' 39 | updated: 'You updated your account successfully.' 40 | destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.' 41 | reasons: 42 | inactive: 'inactive' 43 | unconfirmed: 'unconfirmed' 44 | locked: 'locked' 45 | unlocks: 46 | send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' 47 | unlocked: 'Your account was successfully unlocked. You are now signed in.' 48 | send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.' 49 | omniauth_callbacks: 50 | success: 'Successfully authorized from %{kind} account.' 51 | failure: 'Could not authorize you from %{kind} because "%{reason}".' 52 | mailer: 53 | confirmation_instructions: 54 | subject: 'Confirmation instructions' 55 | reset_password_instructions: 56 | subject: 'Reset password instructions' 57 | unlock_instructions: 58 | subject: 'Unlock Instructions' 59 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | has_many :openidentities, :dependent => :destroy 3 | has_many :sightings 4 | has_many :locations, :through => :sightings 5 | has_many :schedules 6 | validates_presence_of :username, :email, :authentication_token 7 | validates_uniqueness_of :username, :email 8 | 9 | after_create :journal_on_create 10 | 11 | scope :clocked_ins, :conditions => "clocked_in is not null" 12 | 13 | has_friendly_id :username, :use_slug => true 14 | 15 | devise :token_authenticatable 16 | 17 | def self.create_with_defaults!(attributes) 18 | user = User.new(attributes) 19 | if attributes[:username].nil? 20 | user.username = pick_username(user.email) 21 | end 22 | user.display_measurement = "imperial" 23 | user.email_on_new_listing = false 24 | user.authentication_token = UUIDTools::UUID.random_create.to_s 25 | user.save! 26 | user 27 | end 28 | 29 | def apply_form_attributes(params) 30 | return if params.nil? 31 | 32 | if params[:email] 33 | self.email = params[:email] 34 | end 35 | 36 | if params[:username] 37 | self.username = params[:username] 38 | end 39 | 40 | if params[:time_zone] 41 | self.time_zone = params[:time_zone] 42 | end 43 | 44 | if params[:display_measurement] 45 | self.display_measurement = params[:display_measurement] 46 | end 47 | 48 | if params[:email_on_new_listing] 49 | self.email_on_new_listing = params[:email_on_new_listing] 50 | end 51 | end 52 | 53 | def available_for_edit_by(user) 54 | self == user 55 | end 56 | 57 | def openid 58 | self.openidentities.first 59 | end 60 | 61 | def journal_on_create 62 | Journal.create({:delivery => nil, :user => self, :note => "New User"}) 63 | end 64 | 65 | def clock_in! 66 | update_attribute :clocked_in, Time.now 67 | Journal.create({:delivery => nil, :user => self, :note => "Clocked In"}) 68 | end 69 | 70 | def clock_out! 71 | update_attribute :clocked_in, nil 72 | Journal.create({:delivery => nil, :user => self, :note => "Clocked Out"}) 73 | end 74 | 75 | def soft_validate 76 | # suggest to the user that field be filled in. 77 | if time_zone.blank? 78 | errors.add(:time_zone, "Please set a timezone") 79 | end 80 | if email.blank? 81 | errors.add(:email, "Please provide an email address") 82 | end 83 | if display_measurement.blank? 84 | errors.add(:display_measurement, "Please choose your units of measurement") 85 | end 86 | end 87 | 88 | def listed_deliveries 89 | deliveries = Delivery.all(:conditions => {:listing_user_id => self.id}, :order => "created_at desc, delivering_user_id asc") 90 | deliveries.select{|d| d.ok_to_display? } 91 | end 92 | 93 | def accepted_deliveries(year=nil, month=nil) 94 | if year && month 95 | mark = Time.parse("#{year}-#{month}-01") 96 | conditions = ["delivering_user_id = ? and accepted_at >= ? and accepted_at < ?", self.id, mark, mark.next_month ] 97 | else 98 | conditions = {:delivering_user_id => self.id} 99 | end 100 | deliveries = Delivery.all(:conditions => conditions, :order => "created_at desc, delivering_user_id asc") 101 | deliveries.select{|d| d.ok_to_display? } 102 | end 103 | 104 | def self.pick_username(email) 105 | username = email.split('@')[0] 106 | if User.find_by_username(username) 107 | logger.info("found! addin number") 108 | username += (rand(89999)+10000).to_s 109 | end 110 | logger.info("picked: #{username}") 111 | username 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /app/assets/javascripts/delivery_edit.js: -------------------------------------------------------------------------------- 1 | function formvalidation(event) { 2 | if($('#from_latitude').val().length > 0) { 3 | if($('#to_latitude').val().length > 0) { 4 | // Both points are verified. compute the distance 5 | p1 = new google.maps.LatLng($('#from_latitude').val(),$('#from_longitude').val()); 6 | p2 = new google.maps.LatLng($('#to_latitude').val(),$('#to_longitude').val()); 7 | $('#delivery_start_end_distance').val(""+distanceBetweenPoints(p1,p2)); 8 | return; 9 | } else { 10 | invalidate_to(); 11 | alert("Please correct the To address."); 12 | } 13 | } else { 14 | invalidate_from(); 15 | alert("Please correct the From address."); 16 | } 17 | return false; 18 | } 19 | 20 | function invalidate_from() { 21 | $('#from_latitude').val(""); 22 | $('#from_longitude').val(""); 23 | /*$('#from_address_msg').html("Validating.");*/ 24 | $('#from_address_label').addClass('error'); 25 | } 26 | 27 | function invalidate_to() { 28 | $('#to_latitude').val(""); 29 | $('#to_longitude').val(""); 30 | /*$('#to_address_msg').html("Validating.")*/ 31 | $('#to_address_label').addClass('error'); 32 | } 33 | 34 | function validate_from(latlng) { 35 | $('#from_address_map').html(static_map(latlng,150,70,15)); 36 | $('#from_address_label').removeClass('error'); 37 | } 38 | 39 | function validate_to(latlng) { 40 | $('#to_address_map').html(static_map(latlng,150,70,15)); 41 | $('#to_address_label').removeClass('error'); 42 | } 43 | 44 | function prevalidate_from() { 45 | var lat = $('#from_latitude').val(); 46 | var lng = $('#from_longitude').val(); 47 | if(lat.length > 0) { 48 | var latlng = new google.maps.LatLng(lat,lng); 49 | validate_from(latlng); 50 | } 51 | } 52 | 53 | function prevalidate_to() { 54 | var lat = $('#to_latitude').val(); 55 | var lng = $('#to_longitude').val(); 56 | if(lat.length > 0) { 57 | var latlng = new google.maps.LatLng(lat,lng); 58 | validate_to(latlng); 59 | } 60 | } 61 | 62 | function geocallback_from(results, status) { 63 | if(status == "OK") { 64 | var gLatLng = results[0].geometry.location; 65 | $('#from_latitude').val(""+gLatLng.lat()); 66 | $('#from_longitude').val(""+gLatLng.lng()); 67 | validate_from(gLatLng); 68 | } else { 69 | invalidate_from(); 70 | } 71 | } 72 | 73 | function geocallback_to(results, status) { 74 | if(status == "OK") { 75 | var gLatLng = results[0].geometry.location; 76 | $('#to_latitude').val(""+gLatLng.lat()); 77 | $('#to_longitude').val(""+gLatLng.lng()); 78 | validate_to(gLatLng); 79 | } else { 80 | invalidate_to(); 81 | } 82 | } 83 | 84 | function static_map(gLatLng, h, w, zoom) { 85 | var map_url = ""; 88 | console.log(map_url) 89 | return map_url; 90 | } 91 | 92 | function address_from_validate_click(event) { 93 | var geocoder = new google.maps.Geocoder(); 94 | var request = { address : $('#from_address').val() } 95 | geocoder.geocode(request, geocallback_from); 96 | event.preventDefault(); 97 | } 98 | 99 | function address_to_validate_click(event) { 100 | var geocoder = new google.maps.Geocoder(); 101 | var request = { address : $('#to_address').val() } 102 | geocoder.geocode(request, geocallback_to); 103 | event.preventDefault(); 104 | } 105 | 106 | function distanceBetweenPoints(p1, p2) { 107 | if (!p1 || !p2) { 108 | return 0; 109 | } 110 | 111 | var R = 6371000; // Radius of the Earth in m 112 | var dLat = (p2.lat() - p1.lat()) * Math.PI / 180; 113 | var dLon = (p2.lng() - p1.lng()) * Math.PI / 180; 114 | var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + 115 | Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * 116 | Math.sin(dLon / 2) * Math.sin(dLon / 2); 117 | var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 118 | var d = R * c; 119 | return d; 120 | } 121 | 122 | 123 | function setup() { 124 | $('#from_address').blur(address_from_validate_click) 125 | /*$('#from_address_validate').click(address_from_validate_click);*/ 126 | $('#to_address').blur(address_to_validate_click) 127 | /*$('#to_address_validate').click(address_to_validate_click);*/ 128 | $('.edit_delivery').submit(formvalidation); 129 | $('#from_address').change(invalidate_from); 130 | $('#to_address').change(invalidate_to); 131 | prevalidate_from(); 132 | prevalidate_to(); 133 | } 134 | 135 | 136 | -------------------------------------------------------------------------------- /app/models/delivery.rb: -------------------------------------------------------------------------------- 1 | class Delivery < ActiveRecord::Base 2 | 3 | include Workflow 4 | include ActionView::Helpers::DateHelper 5 | 6 | belongs_to :fee 7 | belongs_to :package 8 | belongs_to :start_location, :class_name => "Location" 9 | belongs_to :end_location, :class_name => "Location" 10 | belongs_to :listing_user, :class_name => "User" 11 | belongs_to :delivering_user, :class_name => "User" 12 | has_many :comments 13 | 14 | after_create :journal_on_create 15 | after_save :check_for_completeness 16 | 17 | workflow do 18 | state :building do 19 | event :ready, :transitions_to => :waiting 20 | end 21 | state :waiting do 22 | event :accept, :transitions_to => :accepted 23 | end 24 | state :accepted do 25 | event :deliver, :transitions_to => :delivered 26 | end 27 | state :delivered 28 | end 29 | 30 | scope :buildings, :conditions => { :workflow_state => "building" } 31 | scope :waitings, :conditions => { :workflow_state => "waiting" } 32 | 33 | def check_for_completeness 34 | if building? && ok_to_display? 35 | ready! 36 | end 37 | end 38 | 39 | def ready 40 | Journal.create({:delivery => self, :user => listing_user, :note => "Emailed delivery update notice"}) 41 | email_notify_users # todo: make job 42 | TwitterJob.new(ready_message).send_later(:perform) 43 | end 44 | 45 | def email_notify_users 46 | User.all(:conditions => {:email_on_new_listing => true}).each do |user| 47 | DeliveryMailer.updated(self, user).deliver 48 | end 49 | end 50 | 51 | def apply_form_attributes(params) 52 | return if params.nil? 53 | self.start_end_distance = params[:start_end_distance].to_i 54 | end 55 | 56 | def ok_to_display? 57 | !!(fee && fee.ok_to_display? && package && package.ok_to_display? && start_location && start_location.ok_to_display? && end_location && end_location.ok_to_display? && listing_user) 58 | end 59 | 60 | def overdue?(time = Time.now) 61 | if fee 62 | fee.delivery_due < time 63 | else 64 | true 65 | end 66 | end 67 | 68 | def delivered? 69 | !!delivering_user 70 | end 71 | 72 | def available_for_delivery_by(user) 73 | user && user != listing_user && delivering_user.nil? && !overdue? && !featured 74 | end 75 | 76 | def available_for_edit_by(user) 77 | user && user == listing_user 78 | end 79 | 80 | def journal_on_create 81 | Journal.create({:delivery => self, :user => self.listing_user, :note => "Building Delivery"}) 82 | end 83 | 84 | def deliverer(user) 85 | self.delivering_user = user 86 | self.accepted_at = Time.now 87 | Journal.create({:delivery => self, :user => user, :note => "Accepted delivery."}) 88 | end 89 | 90 | def display_retail_plus_bounty 91 | "%0.2f" % ((self.package.price_in_cents + self.fee.price_in_cents) / 100.0) 92 | end 93 | 94 | def listing_fee_in_cents 95 | if self.fee.price_in_cents >= 300 96 | 0.50 97 | else 98 | 0.0 99 | end 100 | end 101 | 102 | def display_listing_fee 103 | "%0.2f" % (listing_fee_in_cents/100.0) 104 | end 105 | 106 | def ready_message 107 | url = "#{SETTINGS["shortname"]["url"]}/#{id}" 108 | due = "Due in #{distance_of_time_in_words_to_now(fee.delivery_due)}." 109 | "\"#{package.description[0,136-url.length-due.length]}\" #{due} #{url}" 110 | end 111 | 112 | def self.find_at_most_hours_old(hours, time=Time.zone.now) 113 | start = hours.hours.ago(time) 114 | stop = time 115 | find_between_times(start,stop) 116 | end 117 | 118 | def self.find_more_than_hours_old(hours, time=Time.zone.now) 119 | start = Time.zone.at(0) 120 | stop = hours.hours.ago(time) 121 | find_between_times(start,stop) 122 | end 123 | 124 | def self.find_between_hours_old(smaller, larger, time=Time.zone.now) 125 | start = larger.hours.ago(time) 126 | stop = smaller.hours.ago(time) 127 | find_between_times(start,stop) 128 | end 129 | 130 | def self.find_between_times(start,stop) 131 | all(:conditions => ["created_at >= ? and created_at < ?", start, stop], :order => "created_at desc, delivering_user_id asc") 132 | end 133 | 134 | def self.find_due_after_time(due_time) 135 | joins(:fee). 136 | where(["fees.delivery_due >= ?", due_time]). 137 | order("fees.delivery_due asc") 138 | end 139 | 140 | def self.find_due_between_times(start,stop) 141 | joins(:fee). 142 | where(["fees.delivery_due >= ? and fees.delivery_due < ?", start, stop]). 143 | order("fees.delivery_due desc") 144 | end 145 | end 146 | -------------------------------------------------------------------------------- /app/assets/javascripts/gmaps.js.erb: -------------------------------------------------------------------------------- 1 | function mapinitialize(start_lat, start_long, draggable) { 2 | var lat, lng, zoom; 3 | if(start_lat) { 4 | lat = start_lat 5 | lng = start_long 6 | zoom = 12 7 | } else { 8 | lat = 45 9 | lng = -120 10 | zoom = 4 11 | } 12 | var start = new google.maps.LatLng(lat, lng); 13 | var map = new google.maps.Map(document.getElementById("gmap"), 14 | {mapTypeId: google.maps.MapTypeId.ROADMAP, 15 | center: start, 16 | zoom: zoom}); 17 | marker_start = new google.maps.Marker({position:start, 18 | draggable: draggable}); 19 | if(draggable) { 20 | google.maps.event.addListener(marker_start, 'dragend', function(event) {mark_dragged(event.latLng)}); 21 | } 22 | 23 | marker_start.setMap(map); 24 | return map; 25 | } 26 | 27 | function map_destination(map, end_lat, end_long, units) { 28 | var start = map.getCenter(); 29 | var end = new google.maps.LatLng(end_lat, end_long); 30 | var bounds = new google.maps.LatLngBounds(); 31 | bounds.extend(start); 32 | bounds.extend(end); 33 | map.fitBounds(bounds); 34 | 35 | var marker_end = new google.maps.Marker({position:end}); 36 | marker_end.setMap(map); 37 | 38 | 39 | var directions = new google.maps.DirectionsService(); 40 | var request = { origin : start, 41 | destination : end, 42 | travelMode : google.maps.DirectionsTravelMode.DRIVING, 43 | unitSystem: units }; 44 | directions.route(request, show_directions_callback_builder(map)); 45 | } 46 | 47 | function map_riders(map, riders) { 48 | var bounds = map.getBounds() 49 | for(var i=0,len=riders.length; i", 66 | {success:intersection_update, dataType: "json"}) 67 | } 68 | 69 | function intersection_update(data, status) { 70 | if (status == "success") { 71 | var streetname, msg; 72 | if (data.intersection) { 73 | msg = ""+data.intersection.street1+"" + 74 | ' and ' + 75 | ""+data.intersection.street2+"" 76 | $('#street1_field').val(data.intersection.street1) 77 | $('#street2_field').val(data.intersection.street2) 78 | } else { 79 | msg = "No intersection near this location. Please try again." 80 | } 81 | $('#gmapmsg').html(msg) 82 | } 83 | } 84 | 85 | function show_directions_callback_builder(map) { 86 | // use a closure to make map a local variable 87 | return function show_directions(result, status) { 88 | if(status == "NOT_FOUND") { 89 | $('#gmaperror').html("Route not found"); 90 | } 91 | if(status == "OK") { 92 | renderer = new google.maps.DirectionsRenderer({directions: result, 93 | suppressMarkers : true}); 94 | renderer.setMap(map); 95 | $('#travel_distance').html(result.routes[0].legs[0].distance.text) 96 | } 97 | } 98 | } 99 | 100 | function gmapcenter(map, street) { 101 | var geocoder = new google.maps.Geocoder(); 102 | var request = {address: street}; 103 | geocoder.geocode(request, function(addresses, result, status){ 104 | gmapcenterfinish(map, addresses, result, status)}) 105 | } 106 | 107 | function gmapcenterfinish(map, addresses, result, status){ 108 | if (addresses[0]) { 109 | var address = addresses[0]; 110 | var start = new google.maps.LatLng(address.geometry.location.lat(), 111 | address.geometry.location.lng()); 112 | map.setCenter(start) 113 | map.setZoom(14) 114 | marker_start.setPosition(start) 115 | mark_dragged(start) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/assets/images/wheel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | 50 | 51 | 52 | 53 | 58 | 68 | 78 | 84 | 90 | 96 | 102 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /spec/controllers/deliveries_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') 2 | 3 | describe DeliveriesController do 4 | 5 | context "when logged in" do 6 | before(:each) do 7 | controller.stub!(:user_signed_in?).and_return(true) 8 | @user = mock_model(User) 9 | controller.stub!(:current_user).and_return(@user) 10 | controller.stub!(:set_timezone) 11 | end 12 | 13 | it "lists deliveries" do 14 | get :index 15 | end 16 | 17 | it "creates a delivery" do 18 | delivery = mock_model(Delivery) 19 | Delivery.should_receive(:create).and_return(delivery) 20 | post :create 21 | response.should redirect_to(edit_delivery_path(delivery)) 22 | end 23 | 24 | it "shows the details of a delivery" do 25 | delivery = mock_model(Delivery) 26 | Delivery.should_receive(:find).and_return(delivery) 27 | get :show, {:id => delivery.id} 28 | response.should render_template("show") 29 | end 30 | 31 | it "edits a delivery" do 32 | delivery = mock_model(Delivery) 33 | Delivery.should_receive(:find).and_return(delivery) 34 | delivery.should_receive(:listing_user).and_return(mock_model(User)) 35 | delivery.should_receive(:available_for_edit_by).with(@user).and_return(true) 36 | get :edit, {:id => delivery.id} 37 | response.should render_template("edit") 38 | end 39 | 40 | context "updates a delivery" do 41 | before(:each) do 42 | bob = mock_model(User) 43 | #bob.should_receive(:username).and_return("bob") 44 | @delivery = mock_model(Delivery) 45 | @delivery.should_receive(:fee=) 46 | @delivery.should_receive(:package=) 47 | @delivery.should_receive(:start_location=) 48 | @delivery.should_receive(:end_location=) 49 | @delivery.should_receive(:save).and_return(true) 50 | @delivery.should_receive(:apply_form_attributes) 51 | Delivery.should_receive(:find).and_return(@delivery) 52 | end 53 | 54 | it "when the delivery has a creator" do 55 | @delivery.should_receive(:available_for_edit_by).with(@user).and_return(true) 56 | @delivery.should_receive(:listing_user).and_return(@user) 57 | put :update, {:id => @delivery.id} 58 | response.should redirect_to(delivery_path(@delivery)) 59 | end 60 | 61 | it "when the delivery was created anonymously" do 62 | @delivery.should_receive(:listing_user) 63 | session[:anonymous_delivery_id] = @delivery.id 64 | put :update, {:id => @delivery.id} 65 | response.should redirect_to(:controller => :dashboard, :action => :start_delivery) 66 | end 67 | end 68 | 69 | it "should destroy a delivery" do 70 | delivery = mock_model(Delivery) 71 | delivery.should_receive(:destroy) 72 | Delivery.should_receive(:find).and_return(delivery) 73 | delete :destroy 74 | response.should redirect_to(deliveries_path) 75 | end 76 | 77 | it "should accept a delivery" do 78 | bob = mock_model(User) 79 | lister = mock_model(User) 80 | delivery = mock_model(Delivery) 81 | delivery.should_receive(:building?).and_return(false) 82 | delivery.should_receive(:accepted?).and_return(false) 83 | delivery.should_receive(:waiting?).and_return(true) 84 | delivery.should_receive(:deliverer).with(@user) 85 | delivery.should_receive(:save!) 86 | delivery.should_receive(:accept!) 87 | delivery.should_receive(:listing_user).and_return(bob) 88 | mailer = mock("Delivery Mailer") 89 | mailer.should_receive(:deliver) 90 | DeliveryMailer.should_receive(:accepted).with(delivery).and_return(mailer) 91 | Delivery.should_receive(:find).with(delivery.id.to_s).and_return(delivery) 92 | put :accept, {:id => delivery.id, "commit"=>"Yes I accept"} 93 | response.should redirect_to(delivery_path(delivery)) 94 | end 95 | end 96 | 97 | context "when logged out" do 98 | before(:each) do 99 | controller.stub!(:user_signed_in?).and_return(false) 100 | controller.stub!(:current_user) 101 | controller.stub!(:set_timezone) 102 | end 103 | 104 | it "edits a delivery" do 105 | delivery = mock_model(Delivery) 106 | Delivery.should_receive(:find).and_return(delivery) 107 | session[:anonymous_delivery_id] = delivery.id 108 | get :edit, {:id => delivery.id} 109 | response.should render_template("edit") 110 | end 111 | 112 | 113 | it "should update a delivery" do 114 | bob = mock_model(User) 115 | #bob.should_receive(:username).and_return("bob") 116 | delivery = mock_model(Delivery) 117 | delivery.should_receive(:available_for_edit_by).with(@user).and_return(true) 118 | delivery.should_receive(:fee=) 119 | delivery.should_receive(:package=) 120 | delivery.should_receive(:start_location=) 121 | delivery.should_receive(:end_location=) 122 | delivery.should_receive(:save).and_return(true) 123 | delivery.should_receive(:apply_form_attributes) 124 | delivery.should_receive(:listing_user).and_return(nil) 125 | Delivery.should_receive(:find).and_return(delivery) 126 | put :update, {:id => delivery.id} 127 | response.should redirect_to(:controller => :dashboard, :action => :start_delivery) 128 | end 129 | end 130 | end 131 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20130929215541) do 15 | 16 | create_table "comments", :force => true do |t| 17 | t.integer "delivery_id" 18 | t.integer "user_id" 19 | t.string "text" 20 | t.datetime "created_at" 21 | t.datetime "updated_at" 22 | end 23 | 24 | create_table "delayed_jobs", :force => true do |t| 25 | t.integer "priority", :default => 0 26 | t.integer "attempts", :default => 0 27 | t.text "handler" 28 | t.text "last_error" 29 | t.datetime "run_at" 30 | t.datetime "locked_at" 31 | t.datetime "failed_at" 32 | t.string "locked_by" 33 | t.datetime "created_at" 34 | t.datetime "updated_at" 35 | t.string "queue" 36 | end 37 | 38 | add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority" 39 | 40 | create_table "deliveries", :force => true do |t| 41 | t.integer "fee_id" 42 | t.integer "package_id" 43 | t.integer "start_location_id" 44 | t.integer "end_location_id" 45 | t.integer "listing_user_id" 46 | t.integer "delivering_user_id" 47 | t.datetime "created_at" 48 | t.datetime "updated_at" 49 | t.integer "start_end_distance" 50 | t.datetime "accepted_at" 51 | t.boolean "featured" 52 | t.string "workflow_state" 53 | end 54 | 55 | create_table "fees", :force => true do |t| 56 | t.integer "price_in_cents" 57 | t.datetime "created_at" 58 | t.datetime "updated_at" 59 | t.datetime "delivery_due" 60 | t.string "payment_method" 61 | end 62 | 63 | create_table "journal", :force => true do |t| 64 | t.integer "delivery_id" 65 | t.integer "package_id" 66 | t.integer "user_id" 67 | t.integer "location_id" 68 | t.float "fee" 69 | t.string "note" 70 | t.datetime "created_at" 71 | t.datetime "updated_at" 72 | end 73 | 74 | create_table "locations", :force => true do |t| 75 | t.string "street" 76 | t.string "zipcode" 77 | t.datetime "created_at" 78 | t.datetime "updated_at" 79 | t.float "latitude" 80 | t.float "longitude" 81 | t.float "accuracy" 82 | t.string "name" 83 | end 84 | 85 | create_table "open_id_associations", :force => true do |t| 86 | t.binary "server_url", :null => false 87 | t.string "handle", :null => false 88 | t.binary "secret", :null => false 89 | t.integer "issued", :null => false 90 | t.integer "lifetime", :null => false 91 | t.string "assoc_type", :null => false 92 | end 93 | 94 | create_table "open_id_nonces", :force => true do |t| 95 | t.string "server_url", :null => false 96 | t.integer "timestamp", :null => false 97 | t.string "salt", :null => false 98 | end 99 | 100 | create_table "openidentities", :force => true do |t| 101 | t.string "url" 102 | t.integer "user_id" 103 | t.datetime "created_at" 104 | t.datetime "updated_at" 105 | end 106 | 107 | create_table "packages", :force => true do |t| 108 | t.string "description" 109 | t.float "weight_in_grams" 110 | t.float "height_in_meters" 111 | t.float "width_in_meters" 112 | t.float "depth_in_meters" 113 | t.datetime "created_at" 114 | t.datetime "updated_at" 115 | t.integer "price_in_cents" 116 | end 117 | 118 | create_table "schedules", :force => true do |t| 119 | t.datetime "starting_at" 120 | t.datetime "ending_at" 121 | t.float "latitude" 122 | t.float "longitude" 123 | t.string "street1" 124 | t.string "street2" 125 | t.integer "user_id" 126 | t.datetime "created_at" 127 | t.datetime "updated_at" 128 | end 129 | 130 | create_table "sightings", :force => true do |t| 131 | t.integer "user_id" 132 | t.integer "location_id" 133 | t.datetime "created_at" 134 | t.datetime "updated_at" 135 | end 136 | 137 | create_table "slugs", :force => true do |t| 138 | t.string "name" 139 | t.integer "sluggable_id" 140 | t.integer "sequence", :default => 1, :null => false 141 | t.string "sluggable_type", :limit => 40 142 | t.string "scope" 143 | t.datetime "created_at" 144 | end 145 | 146 | add_index "slugs", ["name", "sluggable_type", "sequence", "scope"], :name => "index_slugs_on_n_s_s_and_s", :unique => true 147 | add_index "slugs", ["sluggable_id"], :name => "index_slugs_on_sluggable_id" 148 | 149 | create_table "users", :force => true do |t| 150 | t.string "username" 151 | t.datetime "created_at" 152 | t.datetime "updated_at" 153 | t.string "time_zone" 154 | t.string "display_measurement" 155 | t.string "email" 156 | t.datetime "clocked_in" 157 | t.boolean "email_on_new_listing" 158 | t.string "authentication_token" 159 | end 160 | 161 | end 162 | -------------------------------------------------------------------------------- /app/controllers/deliveries_controller.rb: -------------------------------------------------------------------------------- 1 | class DeliveriesController < ApplicationController 2 | before_filter :load_resource, :except => [:index, :create] 3 | 4 | def index 5 | @delivery_groups = [ ] 6 | if params[:q] 7 | # postgresql full-text search 8 | one_month = Delivery.all(:conditions => ["to_tsvector('english', packages.description) "+ 9 | "@@ to_tsquery('english', ?)", params[:q]], :include => :package) 10 | flash[:notice] = "Search results for \"#{params[:q]}\"" 11 | else 12 | now = Time.now 13 | one_month = Delivery.waitings.find_due_after_time(now) + 14 | Delivery.waitings.find_due_between_times(1.month.ago, now) 15 | end 16 | @delivery_groups << ["less than a month old", one_month] if one_month.size > 0 17 | #four_hours = Delivery.find_between_hours_old(1,4).select{|d| d.ok_to_display?} 18 | #@delivery_groups << ["one to four hours old", four_hours] if four_hours.size > 0 19 | #many_hours = Delivery.find_more_than_hours_old(4).select{|d| d.ok_to_display?} 20 | #@delivery_groups << ["more than four hours old", many_hours] if many_hours.size > 0 21 | 22 | @clocked_ins = User.clocked_ins 23 | end 24 | 25 | def create 26 | delivery = Delivery.create({:listing_user => current_user}) 27 | session[:anonymous_delivery_id] = delivery.id unless user_signed_in? 28 | redirect_to edit_delivery_path(delivery) 29 | end 30 | 31 | def show 32 | end 33 | 34 | def edit 35 | if user_signed_in? 36 | if @delivery.listing_user.nil? 37 | if params[:id].to_i == session[:anonymous_delivery_id] 38 | flash[:notice] = "Thank you for logging in. Please review the delivery before saving." 39 | session[:anonymous_delivery_id] = nil 40 | logger.info("assigning formerly anonymous listing") 41 | @delivery.listing_user = current_user 42 | @delivery.save! 43 | else 44 | flash[:error] = "Delivery ##{@delivery.id} was not started with this browser." 45 | redirect_to root_path 46 | end 47 | else 48 | unless @delivery.available_for_edit_by(current_user) 49 | flash[:error] = "Not allowed to edit delivery #{params[:id]}" 50 | redirect_to root_path 51 | end 52 | end 53 | else 54 | if @delivery.id == session[:anonymous_delivery_id] 55 | logger.info("editing under anonymous_delivery_id") 56 | else 57 | flash[:error] = "Login to edit a delivery request." 58 | redirect_to root_path 59 | end 60 | end 61 | end 62 | 63 | def update 64 | # update form is also a creation form for the dependent models 65 | unless (params[:id].to_i == session[:anonymous_delivery_id]) || 66 | @delivery.available_for_edit_by(current_user) 67 | flash[:error] = "Not allowed to edit delivery #{params[:id]}" 68 | redirect_to root_path 69 | return 70 | end 71 | @delivery.apply_form_attributes(params[:delivery]) 72 | 73 | fee = Fee.new 74 | fee.apply_form_attributes(params[:fee]) 75 | fee.save! 76 | @delivery.fee = fee 77 | 78 | package = Package.new 79 | package.apply_form_attributes(params[:package]) 80 | package.save! 81 | @delivery.package = package 82 | 83 | location = Location.new 84 | location.apply_form_attributes(params[:from]) 85 | location.save! 86 | @delivery.start_location = location 87 | 88 | location = Location.new 89 | location.apply_form_attributes(params[:to]) 90 | location.save! 91 | @delivery.end_location = location 92 | 93 | if @delivery.save 94 | if @delivery.listing_user 95 | redirect_to delivery_path(@delivery) 96 | else 97 | redirect_to :controller => :dashboard, :action => :start_delivery 98 | end 99 | else 100 | redirect_to edit_delivery_path(@delivery) 101 | end 102 | end 103 | 104 | def destroy 105 | @delivery.destroy 106 | Journal.create({:delivery => @delivery, :user => current_user, :note => "Destroyed Delivery"}) 107 | redirect_to :deliveries 108 | end 109 | 110 | def confirm 111 | end 112 | 113 | def accept 114 | if params["commit"]=="Yes I accept" 115 | if @delivery.accepted? 116 | flash[:error] = "Delivery has already been accepted!" 117 | end 118 | if @delivery.waiting? 119 | @delivery.deliverer(current_user) 120 | @delivery.save! 121 | @delivery.accept! 122 | DeliveryMailer.accepted(@delivery).deliver 123 | Journal.create({:delivery => @delivery, :user => @delivery.listing_user, :note => "emailed delivery accepted letter"}) 124 | flash[:notice] = "Delivery accepted!" 125 | end 126 | if @delivery.building? 127 | flash[:error] = "Delivery is not ready yet!" 128 | end 129 | end 130 | redirect_to delivery_path(@delivery) 131 | end 132 | 133 | def comment 134 | comment = @delivery.comments.create(:text => params[:comment][:text], 135 | :user_id => current_user.id) 136 | DeliveryMailer.comment(@delivery, comment).deliver 137 | redirect_to @delivery 138 | end 139 | 140 | def comment_delete 141 | @delivery.comments.find(params[:comment_id]).destroy 142 | redirect_to @delivery 143 | end 144 | 145 | private 146 | def load_resource 147 | @delivery = Delivery.find(params[:id]) 148 | unless @delivery 149 | flash[:error] = "Delivery ##{params[:id]} does not exist." 150 | redirect_to :deliveries 151 | end 152 | end 153 | end 154 | -------------------------------------------------------------------------------- /app/assets/images/wheel-e.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | 50 | 51 | 52 | 53 | 58 | 68 | 78 | 84 | 90 | 96 | 102 | 110 | E 122 | 123 | 124 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | actionmailer (3.2.11) 5 | actionpack (= 3.2.11) 6 | mail (~> 2.4.4) 7 | actionpack (3.2.11) 8 | activemodel (= 3.2.11) 9 | activesupport (= 3.2.11) 10 | builder (~> 3.0.0) 11 | erubis (~> 2.7.0) 12 | journey (~> 1.0.4) 13 | rack (~> 1.4.0) 14 | rack-cache (~> 1.2) 15 | rack-test (~> 0.6.1) 16 | sprockets (~> 2.2.1) 17 | activemodel (3.2.11) 18 | activesupport (= 3.2.11) 19 | builder (~> 3.0.0) 20 | activerecord (3.2.11) 21 | activemodel (= 3.2.11) 22 | activesupport (= 3.2.11) 23 | arel (~> 3.0.2) 24 | tzinfo (~> 0.3.29) 25 | activeresource (3.2.11) 26 | activemodel (= 3.2.11) 27 | activesupport (= 3.2.11) 28 | activesupport (3.2.11) 29 | i18n (~> 0.6) 30 | multi_json (~> 1.0) 31 | addressable (2.3.2) 32 | ansi (1.4.3) 33 | arel (3.0.2) 34 | babosa (0.3.8) 35 | bcrypt-ruby (3.0.1) 36 | builder (3.0.4) 37 | coffee-rails (3.2.2) 38 | coffee-script (>= 2.2.0) 39 | railties (~> 3.2.0) 40 | coffee-script (2.2.0) 41 | coffee-script-source 42 | execjs 43 | coffee-script-source (1.4.0) 44 | delayed_job (3.0.4) 45 | activesupport (~> 3.0) 46 | delayed_job_active_record (4.0.0) 47 | activerecord (>= 3.0, < 4.1) 48 | delayed_job (>= 3.0, < 4.1) 49 | devise (2.2.0) 50 | bcrypt-ruby (~> 3.0) 51 | orm_adapter (~> 0.1) 52 | railties (~> 3.1) 53 | warden (~> 1.2.1) 54 | diff-lcs (1.1.3) 55 | erubis (2.7.0) 56 | eventmachine (1.0.0) 57 | exception_notification (3.0.0) 58 | actionmailer (>= 3.0.4) 59 | tinder (~> 1.8) 60 | execjs (1.4.0) 61 | multi_json (~> 1.0) 62 | faraday (0.8.4) 63 | multipart-post (~> 1.1) 64 | faraday_middleware (0.9.0) 65 | faraday (>= 0.7.4, < 0.9) 66 | friendly_id (3.3.3.0) 67 | babosa (~> 0.3.0) 68 | hashie (1.2.0) 69 | hike (1.2.1) 70 | http_parser.rb (0.5.3) 71 | i18n (0.6.1) 72 | journey (1.0.4) 73 | jquery-rails (2.1.4) 74 | railties (>= 3.0, < 5.0) 75 | thor (>= 0.14, < 2.0) 76 | json (1.7.6) 77 | kgio (2.7.4) 78 | launchy (2.1.2) 79 | addressable (~> 2.3) 80 | letter_opener (1.0.0) 81 | launchy (>= 2.0.4) 82 | loofah (1.2.1) 83 | nokogiri (>= 1.4.4) 84 | mail (2.4.4) 85 | i18n (>= 0.4.0) 86 | mime-types (~> 1.16) 87 | treetop (~> 1.4.8) 88 | mime-types (1.19) 89 | multi_json (1.5.0) 90 | multipart-post (1.1.5) 91 | nokogiri (1.5.6) 92 | orm_adapter (0.4.0) 93 | pg (0.14.1) 94 | polyglot (0.3.3) 95 | rack (1.4.3) 96 | rack-cache (1.2) 97 | rack (>= 0.4) 98 | rack-ssl (1.3.2) 99 | rack 100 | rack-test (0.6.2) 101 | rack (>= 1.0) 102 | rails (3.2.11) 103 | actionmailer (= 3.2.11) 104 | actionpack (= 3.2.11) 105 | activerecord (= 3.2.11) 106 | activeresource (= 3.2.11) 107 | activesupport (= 3.2.11) 108 | bundler (~> 1.0) 109 | railties (= 3.2.11) 110 | railties (3.2.11) 111 | actionpack (= 3.2.11) 112 | activesupport (= 3.2.11) 113 | rack-ssl (~> 1.3.2) 114 | rake (>= 0.8.7) 115 | rdoc (~> 3.4) 116 | thor (>= 0.14.6, < 2.0) 117 | raindrops (0.10.0) 118 | rake (10.0.3) 119 | rdoc (3.12) 120 | json (~> 1.4) 121 | rspec-core (2.12.2) 122 | rspec-expectations (2.12.1) 123 | diff-lcs (~> 1.1.3) 124 | rspec-mocks (2.12.1) 125 | rspec-rails (2.12.1) 126 | actionpack (>= 3.0) 127 | activesupport (>= 3.0) 128 | railties (>= 3.0) 129 | rspec-core (~> 2.12.0) 130 | rspec-expectations (~> 2.12.0) 131 | rspec-mocks (~> 2.12.0) 132 | sass (3.2.5) 133 | sass-rails (3.2.5) 134 | railties (~> 3.2.0) 135 | sass (>= 3.1.10) 136 | tilt (~> 1.3) 137 | simple_oauth (0.1.9) 138 | sprockets (2.2.2) 139 | hike (~> 1.2) 140 | multi_json (~> 1.0) 141 | rack (~> 1.0) 142 | tilt (~> 1.1, != 1.3.0) 143 | sqlite3 (1.3.6) 144 | thor (0.16.0) 145 | tilt (1.3.3) 146 | tinder (1.9.2) 147 | eventmachine (~> 1.0) 148 | faraday (~> 0.8) 149 | faraday_middleware (~> 0.9) 150 | hashie (~> 1.0) 151 | json (~> 1.7.5) 152 | mime-types (~> 1.19) 153 | multi_json (~> 1.5) 154 | twitter-stream (~> 0.1) 155 | treetop (1.4.12) 156 | polyglot 157 | polyglot (>= 0.3.1) 158 | turn (0.9.6) 159 | ansi 160 | twitter (4.4.0) 161 | faraday (~> 0.8) 162 | multi_json (~> 1.3) 163 | simple_oauth (~> 0.1.6) 164 | twitter-stream (0.1.16) 165 | eventmachine (>= 0.12.8) 166 | http_parser.rb (~> 0.5.1) 167 | simple_oauth (~> 0.1.4) 168 | tzinfo (0.3.35) 169 | uglifier (1.3.0) 170 | execjs (>= 0.3.0) 171 | multi_json (~> 1.0, >= 1.0.2) 172 | unicorn (4.5.0) 173 | kgio (~> 2.6) 174 | rack 175 | raindrops (~> 0.7) 176 | uuidtools (2.1.3) 177 | warden (1.2.1) 178 | rack (>= 1.0) 179 | webrat (0.7.3) 180 | nokogiri (>= 1.2.0) 181 | rack (>= 1.0) 182 | rack-test (>= 0.5.3) 183 | workflow (0.8.6) 184 | 185 | PLATFORMS 186 | ruby 187 | 188 | DEPENDENCIES 189 | coffee-rails (~> 3.2.2) 190 | delayed_job_active_record 191 | devise 192 | exception_notification 193 | friendly_id (~> 3.3.3.0) 194 | jquery-rails 195 | letter_opener 196 | loofah 197 | pg 198 | rails (= 3.2.11) 199 | rspec-rails 200 | sass-rails (~> 3.2.5) 201 | sqlite3 202 | turn 203 | twitter 204 | uglifier 205 | unicorn 206 | uuidtools 207 | webrat 208 | workflow 209 | -------------------------------------------------------------------------------- /app/views/deliveries/show.html.erb: -------------------------------------------------------------------------------- 1 | <% if @delivery.start_location && @delivery.end_location %> 2 | 20 | <% end %> 21 | 22 |
23 | 24 |

25 | Delivery #<%= @delivery.id %> 26 | <% package = @delivery.package %> 27 | <% if package %> 28 | <%=h @delivery.package.description %> 29 | <% end %> 30 | <% if @delivery.available_for_edit_by(current_user) %> 31 | (<%= link_to "edit", edit_delivery_path(@delivery) %>) 32 | <% end %> 33 |

34 | 35 |
36 |

Status

37 |

38 | <% if @delivery.delivering_user %> 39 | Delivery accepted by: <%= link_to_user @delivery.delivering_user %> 40 | <% else %> 41 | <% if @delivery.waiting? %> 42 | Available for delivery. 43 | <% else %> 44 | Unfinished 45 | <% end %> 46 | <% end %> 47 |
48 | 49 | Listed by: <%= link_to_user @delivery.listing_user %>
50 | 51 | Listed at: <%= @delivery.created_at.strftime("%l:%M%P %Z %d-%b-%Y") %>
52 |

53 |
54 | 55 |
56 |

Package

57 | <% if package %> 58 |

59 | Description: "<%=h @delivery.package.description %>" 60 |
61 | <% if package.has_dimensions? %> 62 | Height: <%= @delivery.package.height %>" 63 | Width: <%= @delivery.package.width %>" 64 | Depth: <%= @delivery.package.depth %>" 65 | <% end %> 66 |

67 | <% else %> 68 |

69 | no package has been specified 70 |

71 | <% end %> 72 |
73 | 74 |
75 |

Price and Bounty

76 |

77 | <% if package %> 78 | Retail price: $<%= @delivery.package.display_price %>
79 | <% end %> 80 | <% if @delivery.fee %> 81 | Bounty: $<%= @delivery.fee.display_price %>
82 | Payment method: <%= @delivery.fee.payment_method %>
83 |
84 | <% else %> 85 | no delivery fee has been specified 86 | <% end %> 87 |

88 |
89 | 90 |
91 |
92 | 93 |
94 | <% if @delivery.start_location && @delivery.end_location %> 95 |
96 |
97 | <% end %> 98 |
99 | 100 |
101 |
102 |

From

103 |

104 | <% if @delivery.start_location %> 105 | <%= @delivery.start_location.name %>
106 | <%= @delivery.start_location.street %> 107 | <% else %> 108 | no start location has been specified 109 | <% end %> 110 |

111 |
112 | 113 |
114 |

To

115 |

116 | <% if @delivery.end_location %> 117 | <%= @delivery.end_location.name %>
118 | <%= @delivery.end_location.street %> 119 | <% else %> 120 | no end location has been specified 121 | <% end %> 122 |

123 |
124 | 125 |
126 | <% if @delivery.start_end_distance && @delivery.start_end_distance > 0 %> 127 |

Distance

128 |

129 | Travel distance: 130 |

131 | <% end %> 132 |
133 | 134 |
135 |

Time

136 | <% if @delivery.fee %> 137 | Due Date: <%= @delivery.fee.delivery_due.strftime("%l:%M%P %Z %d-%b-%Y") %>
138 | <% if @delivery.fee.delivery_due >= Time.now %> 139 | Due In: <%= distance_of_time_in_words_to_now(@delivery.fee.delivery_due) %> 140 | <% else %> 141 | Overdue by: <%= distance_of_time_in_words_to_now(@delivery.fee.delivery_due) %> 142 | <% end %> 143 | <% end %> 144 |
145 | 146 | <% if @delivery.available_for_delivery_by(current_user) %> 147 | <%= form_for @delivery, :url => confirm_delivery_path(@delivery), :html => {:method => :put} do |f| %> 148 | <%= f.submit 'I can make this delivery' %> 149 | <% end %> 150 | <% end %> 151 | 152 |
153 | 154 |
155 | Comments 156 |
    157 | <% @delivery.comments.each do |comment| %> 158 |
  • 159 | <%= link_to_user comment.user %>: 160 | <%= comment.text %> 161 | <% if current_user == comment.user %> 162 | <%= link_to 'X', {:action => :comment_delete, :comment_id => comment.id}, 163 | :method => :delete %> 164 | <% end %> 165 |
  • 166 | <% end %> 167 |
168 | <% if user_signed_in? %> 169 | <%= form_tag({:action => :comment}, {:method => "post"}) do %> 170 | Add comment: <%= text_field_tag "comment[text]" %> <%= submit_tag "Post" %> 171 | <% end %> 172 | <% end %> 173 |
174 |
175 | -------------------------------------------------------------------------------- /app/views/deliveries/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :header do %> 2 | 5 | <% end %> 6 | 7 | Delivery Request #<%= @delivery.id %> 8 | 9 | <%= form_for(@delivery) do |f| %> 10 | 11 |
12 | Item 13 | Description <%= text_field_tag "package[description]", 14 | @delivery.package ? @delivery.package.description : "", :size => 50, 15 | :autofocus => "" %> 16 | 17 | 30 |
31 | 32 |
33 | Pick-up Address 34 |
35 |
36 | Person or Business Name 37 | <%= text_field_tag "from[name]", 38 | @delivery.start_location ? @delivery.start_location.name : "", 39 | :size => 20, :placeholder => "Corner Store" %>
40 | Address 41 | <%= text_field_tag "from[address]", 42 | @delivery.start_location ? @delivery.start_location.street : "", 43 | :size => 40, :placeholder => "900 Main St, Portland, Or" %> 44 | 45 | 46 | <%= hidden_field_tag "from[latitude]", @delivery.start_location ? @delivery.start_location.latitude : "" %> 47 | <%= hidden_field_tag "from[longitude]", @delivery.start_location ? @delivery.start_location.longitude : "" %> 48 |
49 |
50 | 51 |
52 | Drop-off Address 53 |
54 |
55 | Person or Business Name 56 | <%= text_field_tag "to[name]", 57 | @delivery.end_location ? @delivery.end_location.name : "", 58 | :size => 20, :placeholder => "Hungry Citizen" %>
59 | Address 60 | <%= text_field_tag "to[address]", 61 | @delivery.end_location ? @delivery.end_location.street : "", 62 | :size => 40, :placeholder => "1200 Thurston St, Portland, Or" %> 63 | 64 | 65 | <%= hidden_field_tag "to[latitude]", @delivery.end_location ? @delivery.end_location.latitude : ""%> 66 | <%= hidden_field_tag "to[longitude]", @delivery.end_location ? @delivery.end_location.longitude : ""%> 67 |
68 |
69 | 70 |
71 | Time 72 | Delivery should be completed by
73 | <% if @delivery.fee 74 | due_time = @delivery.fee.delivery_due.in_time_zone 75 | else 76 | due_time = Time.zone.now 77 | end %> 78 | <%= datetime_select("fee","delivery_due", :default => due_time, :ampm => true) %> 79 | <%= Time.zone.name.sub(/\(.*\)/,'') %> 80 | 81 | 86 |
87 | 88 |
89 | Price / Bounty 90 | If the delivery person will be purchasing the item, give the retail price.
91 | Retail Price $<%= text_field_tag "package[display_price]", 92 | @delivery.package ? @delivery.package.display_price : "", :size => 2 %> 93 |
94 | The higher the bounty, the more likely it will be completed.
95 | Bounty Amount $<%= text_field_tag "fee[display_price]", 96 | @delivery.fee ? @delivery.fee.display_price : "0.00", :size => 4 %> 97 |
98 | 99 |
100 | Payment 101 | I agree to pay the retail price (if any) plus the bounty amount
102 | 103 | to the delivery person upon delivery using 104 | <% if @delivery.fee %> 105 | <% @delivery.fee.errors.full_messages.each do |msg| %> 106 |
  • <%= msg %>
  • 107 | <% end %> 108 | <% end %> 109 | 113 |
    114 | 115 | <%= hidden_field_tag "delivery[start_end_distance]", ""%> 116 | 117 |
    118 | <%= f.submit "Save Details" %> 119 |
    120 | <% end %> 121 | 122 | 123 | <%= button_to "Cancel Listing", delivery_path(@delivery), :confirm => "Delete this delivery listing?", :method => :delete %> 124 | 125 | 126 | -------------------------------------------------------------------------------- /app/assets/images/seal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | 50 | 51 | 52 | 53 | 58 | 71 | 74 | 84 | 94 | 100 | 106 | 112 | 118 | 124 | 125 | EveryoneDelivers 136 | 137 | 138 | -------------------------------------------------------------------------------- /app/assets/stylesheets/main.scss: -------------------------------------------------------------------------------- 1 | $backbackground: #454141; 2 | $background: #545151; 3 | $color1: #5b8207; 4 | $color2: #9CC445; 5 | $listingcolor1: #bebebe; 6 | 7 | body { 8 | background-color: $backbackground; 9 | margin-top: 0px; 10 | } 11 | 12 | .container { 13 | font-family: arial; 14 | padding-top: 2px; 15 | margin-left: 10px; 16 | margin-right: 10px; 17 | background: $background; 18 | color: white; 19 | border-radius: 9px; 20 | } 21 | 22 | .container a { 23 | text-decoration: none; 24 | color: #41c30b; 25 | } 26 | 27 | .container a:hover { 28 | color: #51d31b; 29 | text-decoration: underline; 30 | } 31 | 32 | .header { 33 | background: $color1; 34 | margin: 5px; 35 | padding: 5px; 36 | border-radius: 9px; 37 | color: white; 38 | } 39 | 40 | .header .logo img{ 41 | border: 0; 42 | vertical-align: -50%; 43 | } 44 | 45 | .header .logo .logotext { 46 | font-size: 120% 47 | } 48 | 49 | .header .logo .logotext a{ 50 | color: white 51 | } 52 | 53 | .header a { 54 | color: $color2; 55 | font-family: sans-serif; 56 | } 57 | 58 | .header a:hover { 59 | color: white; 60 | font-family: sans-serif; 61 | text-decoration: underline; 62 | } 63 | 64 | .header ul { 65 | margin:0px; 66 | padding:0px; 67 | display:inline; 68 | list-style-type:none; 69 | float: left 70 | } 71 | 72 | .header li { 73 | display:inline; 74 | /* border-right:1px solid #333333; */ 75 | margin:0px; 76 | padding:0px; 77 | } 78 | 79 | div.header #sub { 80 | padding: 5px; 81 | float: right; 82 | } 83 | 84 | .header .username { 85 | color: white; 86 | } 87 | 88 | 89 | #logotext { 90 | font-size: 150%; 91 | } 92 | 93 | 94 | .dark { 95 | background-color: #656161; 96 | } 97 | 98 | .light { 99 | background-color: $backbackground; 100 | } 101 | 102 | .error { 103 | color: red; 104 | font-size: 110%; 105 | } 106 | 107 | .flashmsgs { 108 | margin-top: 0.6em; 109 | text-align: center; 110 | } 111 | 112 | .clockedinbutton { 113 | float: left; 114 | text-align: center; 115 | margin-top: 5% 116 | } 117 | 118 | .clockedin { 119 | background: $color2; 120 | } 121 | 122 | .clockedout { 123 | margin-left: 10; 124 | background-color: $color1; 125 | } 126 | 127 | .clockedinbox { 128 | float: right; 129 | color: white; 130 | margin-right: 3%; 131 | } 132 | 133 | .clockedinpeople { 134 | background: #5B8207; 135 | float:left; 136 | border-radius: 9px 9px 0 0; 137 | } 138 | 139 | .clockedinpeople p { 140 | margin-top: 0.5em; 141 | margin-bottom: 0px; 142 | margin-left: 0.3em; 143 | margin-right: 0.3em; 144 | border-bottom-style: solid; 145 | text-align: center 146 | } 147 | 148 | .clockedinpeople ul { 149 | list-style: none; 150 | padding-left: 5%; 151 | margin-top: 0px; 152 | margin-bottom: 5%; 153 | } 154 | 155 | .clockedinpeople .username { 156 | font-size: 16pt; 157 | } 158 | 159 | .clockedinpeople li a { 160 | } 161 | 162 | .clockedinpeople li a:hover { 163 | text-decoration: underline; 164 | } 165 | 166 | .clockedintime { 167 | font-size: 80%; 168 | } 169 | 170 | form.edit_delivery { 171 | color: white; 172 | text-align: center; 173 | width: 80%; 174 | margin-left: auto; 175 | margin-right: auto; 176 | } 177 | 178 | #slogan { 179 | margin-top: 0px; 180 | margin-left: 15px 181 | } 182 | 183 | #splash { 184 | text-align: center; 185 | } 186 | 187 | #splashwhy { 188 | width: 40%; 189 | margin-left: auto; 190 | margin-right: auto; 191 | margin-bottom: 0px; 192 | } 193 | 194 | #splash h3 { 195 | color: orange; 196 | font-size: 120%; 197 | } 198 | 199 | #splashrow { 200 | overflow: auto; 201 | } 202 | 203 | #splashleft { 204 | float: left; 205 | width: 25%; 206 | margin-left: 25%; 207 | } 208 | #splashleft p{ 209 | border-right-style: solid; 210 | } 211 | 212 | #splashright { 213 | float: left; 214 | width: 25%; 215 | margin-right: 25%; 216 | } 217 | 218 | .menubar { 219 | margin-top: 0.6em; 220 | padding: 8px; 221 | background: $color2; 222 | color: #D8E3C1; 223 | overflow: auto; 224 | clear: right; 225 | } 226 | 227 | .menubar a { 228 | text-decoration: underline; 229 | color: white; 230 | } 231 | 232 | .menubar a:hover { 233 | color: #33527A; 234 | text-decoration: underline; 235 | } 236 | 237 | .menubar ul { 238 | margin-left: auto; 239 | margin-right: auto; 240 | margin-top: 0px; 241 | margin-bottom: 0px; 242 | padding:0px; 243 | display:inline; 244 | list-style-type:none; 245 | float: left; 246 | } 247 | 248 | .menubar li { 249 | display:inline; 250 | margin:5px; 251 | padding:1px; 252 | } 253 | 254 | .menubar li a { 255 | } 256 | 257 | .menubar input { 258 | border: 0; 259 | } 260 | 261 | .menubar form#new_delivery { 262 | float: left; 263 | } 264 | 265 | #content { 266 | margin-top: 10px; 267 | overflow: auto; 268 | } 269 | 270 | .listbox { 271 | overflow: auto; 272 | } 273 | 274 | .deliverylist { 275 | margin-top: 0px; 276 | margin-bottom: 10px; 277 | margin-left: 10px; 278 | list-style-type: none; 279 | padding-left: 0px; 280 | -moz-border-radius: 5px; 281 | -webkit-border-radius: 5px; 282 | } 283 | 284 | .deliverylist li { 285 | padding: 4px; 286 | } 287 | 288 | .deliverytimes { 289 | float: left; 290 | } 291 | 292 | .deliveryitem { 293 | border-radius: 6px; 294 | } 295 | 296 | .packagename { 297 | font-size: 140%; 298 | font-weight: bold; 299 | background: #689ca7; 300 | border-radius: 9px 9px 0 0; 301 | color: white; 302 | text-align: center; 303 | } 304 | 305 | .packagename a { 306 | color: white; 307 | } 308 | 309 | .packagename a:hover { 310 | color: white; 311 | } 312 | 313 | .deliveryitem div.overdue { 314 | background: #526d73; 315 | } 316 | 317 | .deliverypackageinfo { 318 | float: left; 319 | text-align: left; 320 | background: #a4c1c5; 321 | color: black; 322 | border-bottom-right-radius: 1.1em; 323 | padding: 1%; 324 | -moz-border-radius-bottomright: 1.1em; 325 | -webkit-border-bottom-right-radius: 1.1em; 326 | -o-border-bottom-right-radius: 1.1em; 327 | -ms-border-bottom-right-radius: 1.1em; 328 | } 329 | 330 | .deliverypackageinfo .bountytitle { 331 | font-size: 70%; 332 | text-align: center; 333 | } 334 | 335 | .deliverypackageinfo .deliveryfee { 336 | font-size: 110%; 337 | font-weight: bold; 338 | font-size: 150%; 339 | } 340 | 341 | .deliverylistinguser { 342 | font-size: 80%; 343 | } 344 | 345 | .deliverypackageprice a { 346 | color: #8D9D73; 347 | } 348 | 349 | .deliverypackageprice a:hover { 350 | color: green; 351 | } 352 | 353 | .deliverydetail { 354 | width: 80%; 355 | margin-left: auto; 356 | margin-right: auto; 357 | } 358 | 359 | .deliverydetail h4 { 360 | margin-top: 0px; 361 | margin-bottom: 0px; 362 | text-align: center; 363 | } 364 | 365 | .deliverydetail .addressparts h4 { 366 | text-align: left; 367 | } 368 | 369 | .deliverydetail p { 370 | margin-top: 0px; 371 | margin-bottom: 1em; 372 | } 373 | 374 | .deliverydetail .map { 375 | float:left; 376 | margin-right: 40px 377 | } 378 | 379 | .deliverydetail .info { 380 | float:left; 381 | margin-right: 2em; 382 | } 383 | 384 | .deliverydetail .comments { 385 | clear:left 386 | } 387 | 388 | .deliveryconfirm { 389 | width: 80%; 390 | margin-left: auto; 391 | margin-right: auto; 392 | } 393 | 394 | .deliveryconfirm .map { 395 | float: right; 396 | } 397 | 398 | .googlestaticmap { 399 | margin-left: auto; 400 | margin-right: auto; 401 | overflow: auto; 402 | } 403 | 404 | .googlestaticmap img { 405 | } 406 | 407 | .googlestaticmap .direction { 408 | font-weight: bold; 409 | font-size: 100%; 410 | margin-bottom: 5%; 411 | } 412 | 413 | .mapaddr { 414 | margin-left: 10%; 415 | margin-right: 10% 416 | } 417 | 418 | .mapaddr .address { 419 | } 420 | 421 | .mapaddr .map { 422 | float: left; 423 | text-align: center; 424 | width: 100px; 425 | } 426 | 427 | .deliveryitem { 428 | text-align: center; 429 | } 430 | 431 | .deliveryitem .duedate { 432 | float: right; 433 | font-size: 70%; 434 | color: white; 435 | margin-right: 0.5em 436 | } 437 | 438 | .deliveryitem .duedate a{ 439 | color: orange; 440 | } 441 | .deliveryitem .duedate a:hover{ 442 | color: #FF7A38; 443 | } 444 | 445 | .deliverypackagefromto { 446 | margin-top: 0.3em; 447 | } 448 | 449 | .deliverypackagefromto .halffromto { 450 | width: 50%; 451 | float: left; 452 | } 453 | 454 | #footer { 455 | margin-top: 10px; 456 | text-align: center; 457 | font-size: 80%; 458 | } 459 | 460 | #geomsg { 461 | margin-right: 20px; 462 | color: $color2; 463 | } 464 | 465 | .centered_50percent { 466 | margin-left: auto; 467 | margin-right: auto; 468 | width: 50%; 469 | } 470 | 471 | .textaligncenter { 472 | text-align: center; 473 | } 474 | 475 | #openidprovidertable { 476 | font-size: 130%; 477 | } 478 | 479 | .openidproviderbox { 480 | } 481 | 482 | .openidproviderbox img { 483 | border: 0; 484 | background: white; 485 | -moz-border-radius: 5px; 486 | -webkit-border-radius: 5px; 487 | } 488 | 489 | .biglogin { 490 | font-size: 110%; 491 | } 492 | 493 | #edituser form { 494 | width: 50%; 495 | } 496 | 497 | #edituser label { 498 | width: 5em; 499 | font-size: 150%; 500 | } 501 | 502 | .fieldWithErrors { 503 | color: yellow; 504 | } 505 | 506 | #usershow { 507 | width: 90%; 508 | margin-left: auto; 509 | margin-right: auto; 510 | } 511 | 512 | #usermenu ul { 513 | background: $backbackground; 514 | } 515 | 516 | #usermenu li { 517 | display: inline; 518 | margin-right: 5em; 519 | } 520 | 521 | #sampledelivery { 522 | width: 80%; 523 | margin-right: auto; 524 | margin-left: auto; 525 | list-style: none; 526 | margin-top: 1em; 527 | } 528 | 529 | .payment_methods { 530 | list-style-type: none; 531 | display: inline; 532 | padding-left: 0px; 533 | } 534 | 535 | .clockinschedule { 536 | width:80%; 537 | margin-left: auto; 538 | margin-right: auto 539 | } 540 | 541 | #gmapmsg .street{ 542 | background: $color1; 543 | padding: 0.2em; 544 | } 545 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | == Welcome to Rails 2 | 3 | Rails is a web-application framework that includes everything needed to create 4 | database-backed web applications according to the Model-View-Control pattern. 5 | 6 | This pattern splits the view (also called the presentation) into "dumb" 7 | templates that are primarily responsible for inserting pre-built data in between 8 | HTML tags. The model contains the "smart" domain objects (such as Account, 9 | Product, Person, Post) that holds all the business logic and knows how to 10 | persist themselves to a database. The controller handles the incoming requests 11 | (such as Save New Account, Update Product, Show Post) by manipulating the model 12 | and directing data to the view. 13 | 14 | In Rails, the model is handled by what's called an object-relational mapping 15 | layer entitled Active Record. This layer allows you to present the data from 16 | database rows as objects and embellish these data objects with business logic 17 | methods. You can read more about Active Record in 18 | link:files/vendor/rails/activerecord/README.html. 19 | 20 | The controller and view are handled by the Action Pack, which handles both 21 | layers by its two parts: Action View and Action Controller. These two layers 22 | are bundled in a single package due to their heavy interdependence. This is 23 | unlike the relationship between the Active Record and Action Pack that is much 24 | more separate. Each of these packages can be used independently outside of 25 | Rails. You can read more about Action Pack in 26 | link:files/vendor/rails/actionpack/README.html. 27 | 28 | 29 | == Getting Started 30 | 31 | 1. At the command prompt, create a new Rails application: 32 | rails new myapp (where myapp is the application name) 33 | 34 | 2. Change directory to myapp and start the web server: 35 | cd myapp; rails server (run with --help for options) 36 | 37 | 3. Go to http://localhost:3000/ and you'll see: 38 | "Welcome aboard: You're riding Ruby on Rails!" 39 | 40 | 4. Follow the guidelines to start developing your application. You can find 41 | the following resources handy: 42 | 43 | * The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html 44 | * Ruby on Rails Tutorial Book: http://www.railstutorial.org/ 45 | 46 | 47 | == Debugging Rails 48 | 49 | Sometimes your application goes wrong. Fortunately there are a lot of tools that 50 | will help you debug it and get it back on the rails. 51 | 52 | First area to check is the application log files. Have "tail -f" commands 53 | running on the server.log and development.log. Rails will automatically display 54 | debugging and runtime information to these files. Debugging info will also be 55 | shown in the browser on requests from 127.0.0.1. 56 | 57 | You can also log your own messages directly into the log file from your code 58 | using the Ruby logger class from inside your controllers. Example: 59 | 60 | class WeblogController < ActionController::Base 61 | def destroy 62 | @weblog = Weblog.find(params[:id]) 63 | @weblog.destroy 64 | logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") 65 | end 66 | end 67 | 68 | The result will be a message in your log file along the lines of: 69 | 70 | Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! 71 | 72 | More information on how to use the logger is at http://www.ruby-doc.org/core/ 73 | 74 | Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are 75 | several books available online as well: 76 | 77 | * Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) 78 | * Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) 79 | 80 | These two books will bring you up to speed on the Ruby language and also on 81 | programming in general. 82 | 83 | 84 | == Debugger 85 | 86 | Debugger support is available through the debugger command when you start your 87 | Mongrel or WEBrick server with --debugger. This means that you can break out of 88 | execution at any point in the code, investigate and change the model, and then, 89 | resume execution! You need to install ruby-debug to run the server in debugging 90 | mode. With gems, use sudo gem install ruby-debug. Example: 91 | 92 | class WeblogController < ActionController::Base 93 | def index 94 | @posts = Post.all 95 | debugger 96 | end 97 | end 98 | 99 | So the controller will accept the action, run the first line, then present you 100 | with a IRB prompt in the server window. Here you can do things like: 101 | 102 | >> @posts.inspect 103 | => "[#nil, "body"=>nil, "id"=>"1"}>, 105 | #"Rails", "body"=>"Only ten..", "id"=>"2"}>]" 107 | >> @posts.first.title = "hello from a debugger" 108 | => "hello from a debugger" 109 | 110 | ...and even better, you can examine how your runtime objects actually work: 111 | 112 | >> f = @posts.first 113 | => #nil, "body"=>nil, "id"=>"1"}> 114 | >> f. 115 | Display all 152 possibilities? (y or n) 116 | 117 | Finally, when you're ready to resume execution, you can enter "cont". 118 | 119 | 120 | == Console 121 | 122 | The console is a Ruby shell, which allows you to interact with your 123 | application's domain model. Here you'll have all parts of the application 124 | configured, just like it is when the application is running. You can inspect 125 | domain models, change values, and save to the database. Starting the script 126 | without arguments will launch it in the development environment. 127 | 128 | To start the console, run rails console from the application 129 | directory. 130 | 131 | Options: 132 | 133 | * Passing the -s, --sandbox argument will rollback any modifications 134 | made to the database. 135 | * Passing an environment name as an argument will load the corresponding 136 | environment. Example: rails console production. 137 | 138 | To reload your controllers and models after launching the console run 139 | reload! 140 | 141 | More information about irb can be found at: 142 | link:http://www.rubycentral.org/pickaxe/irb.html 143 | 144 | 145 | == dbconsole 146 | 147 | You can go to the command line of your database directly through rails 148 | dbconsole. You would be connected to the database with the credentials 149 | defined in database.yml. Starting the script without arguments will connect you 150 | to the development database. Passing an argument will connect you to a different 151 | database, like rails dbconsole production. Currently works for MySQL, 152 | PostgreSQL and SQLite 3. 153 | 154 | == Description of Contents 155 | 156 | The default directory structure of a generated Ruby on Rails application: 157 | 158 | |-- app 159 | | |-- assets 160 | | |-- images 161 | | |-- javascripts 162 | | `-- stylesheets 163 | | |-- controllers 164 | | |-- helpers 165 | | |-- mailers 166 | | |-- models 167 | | `-- views 168 | | `-- layouts 169 | |-- config 170 | | |-- environments 171 | | |-- initializers 172 | | `-- locales 173 | |-- db 174 | |-- doc 175 | |-- lib 176 | | `-- tasks 177 | |-- log 178 | |-- public 179 | |-- script 180 | |-- test 181 | | |-- fixtures 182 | | |-- functional 183 | | |-- integration 184 | | |-- performance 185 | | `-- unit 186 | |-- tmp 187 | | |-- cache 188 | | |-- pids 189 | | |-- sessions 190 | | `-- sockets 191 | `-- vendor 192 | |-- assets 193 | `-- stylesheets 194 | `-- plugins 195 | 196 | app 197 | Holds all the code that's specific to this particular application. 198 | 199 | app/assets 200 | Contains subdirectories for images, stylesheets, and JavaScript files. 201 | 202 | app/controllers 203 | Holds controllers that should be named like weblogs_controller.rb for 204 | automated URL mapping. All controllers should descend from 205 | ApplicationController which itself descends from ActionController::Base. 206 | 207 | app/models 208 | Holds models that should be named like post.rb. Models descend from 209 | ActiveRecord::Base by default. 210 | 211 | app/views 212 | Holds the template files for the view that should be named like 213 | weblogs/index.html.erb for the WeblogsController#index action. All views use 214 | eRuby syntax by default. 215 | 216 | app/views/layouts 217 | Holds the template files for layouts to be used with views. This models the 218 | common header/footer method of wrapping views. In your views, define a layout 219 | using the layout :default and create a file named default.html.erb. 220 | Inside default.html.erb, call <% yield %> to render the view using this 221 | layout. 222 | 223 | app/helpers 224 | Holds view helpers that should be named like weblogs_helper.rb. These are 225 | generated for you automatically when using generators for controllers. 226 | Helpers can be used to wrap functionality for your views into methods. 227 | 228 | config 229 | Configuration files for the Rails environment, the routing map, the database, 230 | and other dependencies. 231 | 232 | db 233 | Contains the database schema in schema.rb. db/migrate contains all the 234 | sequence of Migrations for your schema. 235 | 236 | doc 237 | This directory is where your application documentation will be stored when 238 | generated using rake doc:app 239 | 240 | lib 241 | Application specific libraries. Basically, any kind of custom code that 242 | doesn't belong under controllers, models, or helpers. This directory is in 243 | the load path. 244 | 245 | public 246 | The directory available for the web server. Also contains the dispatchers and the 247 | default HTML files. This should be set as the DOCUMENT_ROOT of your web 248 | server. 249 | 250 | script 251 | Helper scripts for automation and generation. 252 | 253 | test 254 | Unit and functional tests along with fixtures. When using the rails generate 255 | command, template test files will be generated for you and placed in this 256 | directory. 257 | 258 | vendor 259 | External libraries that the application depends on. Also includes the plugins 260 | subdirectory. If the app has frozen rails, those gems also go here, under 261 | vendor/rails/. This directory is in the load path. 262 | -------------------------------------------------------------------------------- /config/initializers/devise.rb: -------------------------------------------------------------------------------- 1 | # Use this hook to configure devise mailer, warden hooks and so forth. The first 2 | # four configuration values can also be set straight in your models. 3 | Devise.setup do |config| 4 | # ==> Mailer Configuration 5 | # Configure the e-mail address which will be shown in Devise::Mailer, 6 | # note that it will be overwritten if you use your own mailer class with default "from" parameter. 7 | config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com" 8 | 9 | # Configure the class responsible to send e-mails. 10 | # config.mailer = "Devise::Mailer" 11 | 12 | # ==> ORM configuration 13 | # Load and configure the ORM. Supports :active_record (default) and 14 | # :mongoid (bson_ext recommended) by default. Other ORMs may be 15 | # available as additional gems. 16 | require 'devise/orm/active_record' 17 | 18 | # ==> Configuration for any authentication mechanism 19 | # Configure which keys are used when authenticating a user. The default is 20 | # just :email. You can configure it to use [:username, :subdomain], so for 21 | # authenticating a user, both parameters are required. Remember that those 22 | # parameters are used only when authenticating and not when retrieving from 23 | # session. If you need permissions, you should implement that in a before filter. 24 | # You can also supply a hash where the value is a boolean determining whether 25 | # or not authentication should be aborted when the value is not present. 26 | # config.authentication_keys = [ :email ] 27 | 28 | # Configure parameters from the request object used for authentication. Each entry 29 | # given should be a request method and it will automatically be passed to the 30 | # find_for_authentication method and considered in your model lookup. For instance, 31 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. 32 | # The same considerations mentioned for authentication_keys also apply to request_keys. 33 | # config.request_keys = [] 34 | 35 | # Configure which authentication keys should be case-insensitive. 36 | # These keys will be downcased upon creating or modifying a user and when used 37 | # to authenticate or find a user. Default is :email. 38 | config.case_insensitive_keys = [ :email ] 39 | 40 | # Configure which authentication keys should have whitespace stripped. 41 | # These keys will have whitespace before and after removed upon creating or 42 | # modifying a user and when used to authenticate or find a user. Default is :email. 43 | config.strip_whitespace_keys = [ :email ] 44 | 45 | # Tell if authentication through request.params is enabled. True by default. 46 | # config.params_authenticatable = true 47 | 48 | # Tell if authentication through HTTP Basic Auth is enabled. False by default. 49 | # config.http_authenticatable = false 50 | 51 | # If http headers should be returned for AJAX requests. True by default. 52 | # config.http_authenticatable_on_xhr = true 53 | 54 | # The realm used in Http Basic Authentication. "Application" by default. 55 | # config.http_authentication_realm = "Application" 56 | 57 | # It will change confirmation, password recovery and other workflows 58 | # to behave the same regardless if the e-mail provided was right or wrong. 59 | # Does not affect registerable. 60 | # config.paranoid = true 61 | 62 | # ==> Configuration for :database_authenticatable 63 | # For bcrypt, this is the cost for hashing the password and defaults to 10. If 64 | # using other encryptors, it sets how many times you want the password re-encrypted. 65 | # 66 | # Limiting the stretches to just one in testing will increase the performance of 67 | # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use 68 | # a value less than 10 in other environments. 69 | config.stretches = Rails.env.test? ? 1 : 10 70 | 71 | # Setup a pepper to generate the encrypted password. 72 | # config.pepper = "579e13091633e07ec9c46c50e3dabfd213f01049393b5860757bdc119b069583b8ec7e230062c939fbd54e40bc54b23955e24df492b131d7045334dc2ac1a45f" 73 | 74 | # ==> Configuration for :confirmable 75 | # The time you want to give your user to confirm his account. During this time 76 | # he will be able to access your application without confirming. Default is 0.days 77 | # When confirm_within is zero, the user won't be able to sign in without confirming. 78 | # You can use this to let your user access some features of your application 79 | # without confirming the account, but blocking it after a certain period 80 | # (ie 2 days). 81 | # config.confirm_within = 2.days 82 | 83 | # Defines which key will be used when confirming an account 84 | # config.confirmation_keys = [ :email ] 85 | 86 | # ==> Configuration for :rememberable 87 | # The time the user will be remembered without asking for credentials again. 88 | # config.remember_for = 2.weeks 89 | 90 | # If true, a valid remember token can be re-used between multiple browsers. 91 | # config.remember_across_browsers = true 92 | 93 | # If true, extends the user's remember period when remembered via cookie. 94 | # config.extend_remember_period = false 95 | 96 | # If true, uses the password salt as remember token. This should be turned 97 | # to false if you are not using database authenticatable. 98 | config.use_salt_as_remember_token = true 99 | 100 | # Options to be passed to the created cookie. For instance, you can set 101 | # :secure => true in order to force SSL only cookies. 102 | # config.cookie_options = {} 103 | 104 | # ==> Configuration for :validatable 105 | # Range for password length. Default is 6..128. 106 | # config.password_length = 6..128 107 | 108 | # Email regex used to validate email formats. It simply asserts that 109 | # an one (and only one) @ exists in the given string. This is mainly 110 | # to give user feedback and not to assert the e-mail validity. 111 | # config.email_regexp = /\A[^@]+@[^@]+\z/ 112 | 113 | # ==> Configuration for :timeoutable 114 | # The time you want to timeout the user session without activity. After this 115 | # time the user will be asked for credentials again. Default is 30 minutes. 116 | # config.timeout_in = 30.minutes 117 | 118 | # ==> Configuration for :lockable 119 | # Defines which strategy will be used to lock an account. 120 | # :failed_attempts = Locks an account after a number of failed attempts to sign in. 121 | # :none = No lock strategy. You should handle locking by yourself. 122 | # config.lock_strategy = :failed_attempts 123 | 124 | # Defines which key will be used when locking and unlocking an account 125 | # config.unlock_keys = [ :email ] 126 | 127 | # Defines which strategy will be used to unlock an account. 128 | # :email = Sends an unlock link to the user email 129 | # :time = Re-enables login after a certain amount of time (see :unlock_in below) 130 | # :both = Enables both strategies 131 | # :none = No unlock strategy. You should handle unlocking by yourself. 132 | # config.unlock_strategy = :both 133 | 134 | # Number of authentication tries before locking an account if lock_strategy 135 | # is failed attempts. 136 | # config.maximum_attempts = 20 137 | 138 | # Time interval to unlock the account if :time is enabled as unlock_strategy. 139 | # config.unlock_in = 1.hour 140 | 141 | # ==> Configuration for :recoverable 142 | # 143 | # Defines which key will be used when recovering the password for an account 144 | # config.reset_password_keys = [ :email ] 145 | 146 | # Time interval you can reset your password with a reset password key. 147 | # Don't put a too small interval or your users won't have the time to 148 | # change their passwords. 149 | config.reset_password_within = 2.hours 150 | 151 | # ==> Configuration for :encryptable 152 | # Allow you to use another encryption algorithm besides bcrypt (default). You can use 153 | # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, 154 | # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) 155 | # and :restful_authentication_sha1 (then you should set stretches to 10, and copy 156 | # REST_AUTH_SITE_KEY to pepper) 157 | # config.encryptor = :sha512 158 | 159 | # ==> Configuration for :token_authenticatable 160 | # Defines name of the authentication token params key 161 | # config.token_authentication_key = :auth_token 162 | 163 | # If true, authentication through token does not store user in session and needs 164 | # to be supplied on each request. Useful if you are using the token as API token. 165 | # config.stateless_token = false 166 | 167 | # ==> Scopes configuration 168 | # Turn scoped views on. Before rendering "sessions/new", it will first check for 169 | # "users/sessions/new". It's turned off by default because it's slower if you 170 | # are using only default views. 171 | # config.scoped_views = false 172 | 173 | # Configure the default scope given to Warden. By default it's the first 174 | # devise role declared in your routes (usually :user). 175 | # config.default_scope = :user 176 | 177 | # Configure sign_out behavior. 178 | # Sign_out action can be scoped (i.e. /users/sign_out affects only :user scope). 179 | # The default is true, which means any logout action will sign out all active scopes. 180 | # config.sign_out_all_scopes = true 181 | 182 | # ==> Navigation configuration 183 | # Lists the formats that should be treated as navigational. Formats like 184 | # :html, should redirect to the sign in page when the user does not have 185 | # access, but formats like :xml or :json, should return 401. 186 | # 187 | # If you have any extra navigational formats, like :iphone or :mobile, you 188 | # should add them to the navigational formats lists. 189 | # 190 | # The :"*/*" and "*/*" formats below is required to match Internet 191 | # Explorer requests. 192 | # config.navigational_formats = [:"*/*", "*/*", :html] 193 | 194 | # The default HTTP method used to sign out a resource. Default is :delete. 195 | config.sign_out_via = :delete 196 | 197 | # ==> OmniAuth 198 | # Add a new OmniAuth provider. Check the wiki for more information on setting 199 | # up on your models and hooks. 200 | # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' 201 | 202 | # ==> Warden configuration 203 | # If you want to use other strategies, that are not supported by Devise, or 204 | # change the failure app, you can configure them inside the config.warden block. 205 | # 206 | # config.warden do |manager| 207 | # manager.failure_app = AnotherApp 208 | # manager.intercept_401 = false 209 | # manager.default_strategies(:scope => :user).unshift :some_external_strategy 210 | # end 211 | end 212 | --------------------------------------------------------------------------------