Permalink
Browse files

one damn big initial commit, done singup operation and tests for it

  • Loading branch information...
0 parents commit bcff59424a32695007fbbb019b9cba26190058e6 @nu7hatch committed Jul 14, 2012
@@ -0,0 +1,7 @@
+RACK_ENV=development
+DATABASE_ADAPTER=mysql2
+DATABASE_NAME=airstrip
+DATABASE_HOST=localhost
+DATABASE_PORT=3306
+DATABASE_USER=root
+DATABASE_PASS=pass
@@ -0,0 +1,17 @@
+*.gem
+*.rbc
+.bundle
+.config
+.hop
+.env
+coverage
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
+Gemfile.lock
+log/*.log
+\#*
+.\#*
2 .rspec
@@ -0,0 +1,2 @@
+--color
+--format Fuubar
@@ -0,0 +1,8 @@
+# -*- ruby -*-
+source "http://rubygems.org"
+gemspec
+
+group :development do
+ gem 'fuubar'
+ gem 'mysql2'
+end
@@ -0,0 +1 @@
+web: bundle exec rackup
@@ -0,0 +1,37 @@
+# -*- ruby -*-
+require "bundler/gem_tasks"
+require "rspec/core/rake_task"
+
+desc 'Default: run specs.'
+task :default => :spec
+
+desc "Run specs"
+RSpec::Core::RakeTask.new do |t|
+ t.pattern = "./spec/{,**/}*_spec.rb"
+end
+
+namespace :db do
+ desc "Migrate the database through scripts in db/migrate. Target specific version with VERSION=x"
+ task :migrate => :environment do
+ ActiveRecord::Migrator.migrate('db/migrate', ENV["VERSION"] ? ENV["VERSION"].to_i : nil )
+ end
+
+ desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
+ task :rollback => :environment do
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
+ ActiveRecord::Migrator.rollback('db/migrate', step)
+ end
+end
+
+task :environment do
+ require File.expand_path('../config/boot', __FILE__)
+end
+
+desc "Opens console with loaded app env."
+task :console do
+ $LOAD_PATH.unshift("./lib")
+ require 'airstrip'
+ require 'irb'
+ ARGV.clear
+ IRB.start
+end
@@ -0,0 +1,29 @@
+# -*- ruby -*-
+require 'rubygems'
+require File.expand_path("../lib/airstrip/version", __FILE__)
+
+Gem::Specification.new do |s|
+ s.name = "airstrip"
+ s.version = Airstrip.version
+ s.summary = "Sinatra application for landing pages"
+ s.description = "Airstrip is an open source Sinatra application used for creating neat and simple landing pages"
+ s.authors = ["Krzysztof Kowalik"]
+ s.email = "chris@nu7hat.ch"
+ s.homepage = "http://airstrip.github.com/"
+ s.license = "MIT"
+
+ s.files = Dir["{lib/**/*.rb,spec/**/*.rb,public/**/*,views/**/*,Rakefile,README.md,ChangeLog,*.gemspec}"]
+ s.test_files = Dir["spec/**/*.rb"]
+ s.require_paths = ["lib"]
+
+ s.add_dependency "rake"
+ s.add_dependency "mail"
+ s.add_dependency "json"
+ s.add_dependency "activesupport"
+ s.add_dependency "activerecord"
+ s.add_dependency "activemodel"
+ s.add_dependency "sinatra"
+
+ s.add_development_dependency "rspec", "~> 2.4"
+ s.add_development_dependency "mocha", "0.11.4"
+end
@@ -0,0 +1,6 @@
+require 'bundler'
+Bundler.setup
+
+RACK_ENV = ENV["RACK_ENV"] || 'development'
+
+require File.expand_path("../database", __FILE__)
@@ -0,0 +1,17 @@
+require 'active_record'
+require 'logger'
+
+if RACK_ENV != 'production'
+ ENV['DATABASE_NAME'] += "_#{RACK_ENV}"
+end
+
+ActiveRecord::Base.establish_connection({
+ :adapter => ENV['DATABASE_ADAPTER'],
+ :database => ENV['DATABASE_NAME'],
+ :host => ENV['DATABASE_HOST'],
+ :username => ENV['DATABASE_USER'],
+ :password => ENV['DATABASE_PASS']
+})
+
+db_log_file = File.expand_path('../../log/database.log', __FILE__)
+ActiveRecord::Base.logger = Logger.new(File.open(db_log_file, 'a'))
@@ -0,0 +1,11 @@
+class CreateSignups < ActiveRecord::Migration
+ def change
+ create_table :signups do |t|
+ t.string :email, :null => false
+ t.string :ip_address, :null => false
+ t.string :referrer
+
+ t.timestamps
+ end
+ end
+end
@@ -0,0 +1,46 @@
+require 'active_model'
+require 'active_support/all'
+require 'active_model/validations'
+require 'mail'
+
+# Public: Neat email validator little bit improved. More information on
+# the author's blog post: http://my.rails-royce.org/2010/07/21/email-validation-in-ruby-on-rails-without-regexp/
+#
+# Usage:
+#
+# class User
+# validates :email, :presence => true, :email => true
+# end
+#
+class EmailValidator < ActiveModel::EachValidator
+ def validate_each(record, attribute, value)
+ unless valid_email?(value)
+ msg = options[:message]
+ msg ||= I18n.t(:"validators.email.invalid", :default => "has invalid format")
+ record.errors[attribute] << msg
+ end
+ end
+
+ protected
+
+ # Internal: Takes an email and returns whether is invalid or not.
+ #
+ # email - A String email address to be validated.
+ #
+ # Returns true if email is valid.
+ def valid_email?(email)
+ mail = Mail::Address.new(email)
+
+ # We must check that value contains a domain and that value is
+ # an email address
+ result = mail.domain && mail.address == email
+ tree = mail.__send__(:tree)
+
+ # We need to dig into treetop. A valid domain must have
+ # dot_atom_text elements size > 1. Addresses like user@localhost
+ # are excluded. Treetop must respond to domain.
+ result && (tree.domain.dot_atom_text.elements.size > 1)
+ rescue => e
+ false
+ end
+end
@@ -0,0 +1,18 @@
+require 'sinatra'
+require 'json'
+require 'active_record'
+
+unless defined?(AIRSTRIP_PATH)
+ AIRSTRIP_PATH = File.expand_path("../../", __FILE__)
+end
+
+require 'core_ext/hash'
+require 'active_model/validators/email_validator'
+
+require 'airstrip/version'
+require 'airstrip/models/signup'
+require 'airstrip/services/signup_service'
+require 'airstrip/app'
+
+module Airstrip
+end
@@ -0,0 +1,32 @@
+module Airstrip
+ class App < Sinatra::Application
+ set :public_folder, File.join(AIRSTRIP_PATH, 'public')
+ set :views, File.join(AIRSTRIP_PATH, 'views')
+ enable :sessions
+
+ post "/signup.json" do
+ content_type "application/json"
+ SignupService.call(self).to_json
+ end
+
+ get "/" do
+ erb :index
+ end
+
+ get "/admin" do
+ if signed_in?
+ redirect_to "/admin/signups"
+ else
+ erb :login
+ end
+ end
+
+ get "/admin/signups" do
+ erb :signups_list
+ end
+
+ post "/admin/session" do
+
+ end
+ end
+end
@@ -0,0 +1,22 @@
+module Airstrip
+ # Signup entity represents single user signed up for the beta
+ # access.
+ #
+ # Schema info
+ #
+ # Table name: signups
+ #
+ # id :integer(11), not null, primary key
+ # email :string(255), not null
+ # ip_address :string(255), not null
+ # referrer :string(255)
+ # created_at :timestamp, not null
+ #
+ class Signup < ActiveRecord::Base
+ validates :email, :email => true, :uniqueness => true
+
+ def set_client_info(ip, referrer)
+ self.ip_address, self.referrer = ip, referrer
+ end
+ end
+end
@@ -0,0 +1,13 @@
+module Airstrip
+ class SignupService
+ def self.call(app)
+ @signup = Signup.new(app.params[:signup])
+ @signup.set_client_info(app.request.ip, app.session[:referrer])
+ @signup.save!
+
+ @signup.attributes.pick('email')
+ rescue => e # TODO: specify activerecord error
+ @signup.errors
+ end
+ end
+end
@@ -0,0 +1,8 @@
+module Airstrip
+ VERSION = "0.0.1"
+
+ # Public: Returns current version number.
+ def self.version
+ VERSION
+ end
+end
@@ -0,0 +1,18 @@
+module Airstrip
+ module HashExt
+ # Public: Returns new hash composed only from specified keys.
+ #
+ # keys - An Array of keys to be picked up.
+ #
+ # Returns new hash.
+ def pick(*keys)
+ {}.tap do |result|
+ keys.each { |k| result[k] = self[k] }
+ end
+ end
+ end
+end
+
+class Hash
+ include Airstrip::HashExt
+end
No changes.
@@ -0,0 +1,25 @@
+require File.expand_path("../../../spec_helper", __FILE__)
+
+class DummyModelWithEmail
+ include ActiveModel::Validations
+
+ attr_accessor :email
+ validates :email, :presence => true, :email => true
+
+ def initialize(email)
+ @email = email
+ end
+end
+
+describe EmailValidator do
+ it "adds validation error when email is invalid" do
+ dummy = DummyModelWithEmail.new("invalid@email")
+ dummy.should_not be_valid
+ dummy.errors[:email].should include("has invalid format")
+ end
+
+ it "does nothing when email is valid" do
+ dummy = DummyModelWithEmail.new("chris@nu7hat.ch")
+ dummy.should be_valid
+ end
+end
@@ -0,0 +1,13 @@
+require File.expand_path("../../spec_helper", __FILE__)
+
+describe Hash do
+ describe "#pick" do
+ it "returns new hash composed from the specified keys" do
+ hash = { :foo => 1, :bar => 2, :baz => 3 }
+ new_hash = hash.pick(:foo, :baz)
+ new_hash.keys.should =~ [:foo, :baz]
+ new_hash[:foo].should == 1
+ new_hash[:baz].should == 3
+ end
+ end
+end
@@ -0,0 +1,11 @@
+require File.expand_path("../../spec_helper", __FILE__)
+
+describe Airstrip::Signup do
+ describe "#set_client_info" do
+ it "sets given client's ip and referer information" do
+ subject.set_client_info("127.0.0.1", "google.com")
+ subject.ip_address.should == "127.0.0.1"
+ subject.referrer.should == "google.com"
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit bcff594

Please sign in to comment.