fraternity 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 368f6c901620e8bfbcbc5629d415e279065d4256
4
+ data.tar.gz: 69c4ce243b0eced4e297b46209a9ae4928bfb555
5
+ SHA512:
6
+ metadata.gz: 369a256c3764c6f2b86730b79d06c913221cee6663ea948f537f17f889bc4babfde4a9f9ed28f1142935e9030e1c5d65a9fab55659e3e1a4884e612bf8aa0dd0
7
+ data.tar.gz: cf7db18d627e19eafe6c19b93d0025c6977605891ab975825adeab378277bc978ee4d9dac4bbe8e3a604b4a077f482ad9b83e951f076e09933e980706470504c
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ repo_token: 0434oPH5AmyPXuVPweKtCWtPXgI5ytvyN
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /coverage
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.0
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby '2.2.0'
4
+
5
+ gemspec
6
+
7
+ group :development, :test do
8
+ gem 'rspec'
9
+ gem 'coveralls'
10
+ gem 'sqlite3'
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,62 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fraternity (0.0.1)
5
+ lotus-model
6
+ lotus-validations
7
+ rake
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ coveralls (0.7.2)
13
+ multi_json (~> 1.3)
14
+ rest-client (= 1.6.7)
15
+ simplecov (>= 0.7)
16
+ term-ansicolor (= 1.2.2)
17
+ thor (= 0.18.1)
18
+ diff-lcs (1.2.5)
19
+ docile (1.1.5)
20
+ lotus-model (0.2.1)
21
+ lotus-utils (~> 0.3, >= 0.3.2)
22
+ sequel (~> 4.9)
23
+ lotus-utils (0.3.3)
24
+ lotus-validations (0.2.3)
25
+ lotus-utils (~> 0.3, >= 0.3.3)
26
+ mime-types (2.4.3)
27
+ multi_json (1.10.1)
28
+ rake (10.4.2)
29
+ rest-client (1.6.7)
30
+ mime-types (>= 1.16)
31
+ rspec (3.1.0)
32
+ rspec-core (~> 3.1.0)
33
+ rspec-expectations (~> 3.1.0)
34
+ rspec-mocks (~> 3.1.0)
35
+ rspec-core (3.1.7)
36
+ rspec-support (~> 3.1.0)
37
+ rspec-expectations (3.1.2)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.1.0)
40
+ rspec-mocks (3.1.3)
41
+ rspec-support (~> 3.1.0)
42
+ rspec-support (3.1.2)
43
+ sequel (4.18.0)
44
+ simplecov (0.9.1)
45
+ docile (~> 1.1.0)
46
+ multi_json (~> 1.0)
47
+ simplecov-html (~> 0.8.0)
48
+ simplecov-html (0.8.0)
49
+ sqlite3 (1.3.10)
50
+ term-ansicolor (1.2.2)
51
+ tins (~> 0.8)
52
+ thor (0.18.1)
53
+ tins (0.13.2)
54
+
55
+ PLATFORMS
56
+ ruby
57
+
58
+ DEPENDENCIES
59
+ coveralls
60
+ fraternity!
61
+ rspec
62
+ sqlite3
data/README.md ADDED
@@ -0,0 +1,145 @@
1
+ Fraternity
2
+ ==========
3
+
4
+ [ ![Codeship Status for brilliantfantastic/fraternity](https://codeship.com/projects/3fe0d950-80a4-0132-9038-321707412590/status?branch=master)](https://codeship.com/projects/57522)
5
+ [![Coverage Status](https://coveralls.io/repos/brilliantfantastic/fraternity/badge.svg)](https://coveralls.io/r/brilliantfantastic/fraternity)
6
+ [![Code Climate](https://codeclimate.com/github/brilliantfantastic/fraternity/badges/gpa.svg)](https://codeclimate.com/github/brilliantfantastic/fraternity)
7
+
8
+ ## DESCRIPTION
9
+
10
+ An easier way to rush for a beta.
11
+
12
+ A gem allows you to collect and store (using only [the Lotus framework](http://lotusrb.com) as of now) a list of pledges who would like access to your beta. You can send out bids to those pledges and allow them to gain access to your beta.
13
+
14
+ ## INSTALLATION
15
+
16
+ Add this line to your Gemfile:
17
+
18
+ ```
19
+ gem 'fraternity'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ ```
25
+ bundle install
26
+ ```
27
+
28
+ Or install it yourself:
29
+
30
+ ```
31
+ gem install fraternity
32
+ ```
33
+
34
+ Create the database table needed:
35
+
36
+ ```
37
+ bundle exec rake fraternity:install DESTINATION="db/migrate"
38
+ ```
39
+
40
+ The above will create the following table.
41
+
42
+ ```
43
+ create_table :pledges do |t|
44
+ t.primary_key :id
45
+ String :token
46
+ String :email
47
+ String :first_name
48
+ String :last_name
49
+ Integer :initiation_number
50
+ DateTime :invited_at
51
+ DateTime :accepted_at
52
+ end
53
+ ```
54
+
55
+ ## USAGE
56
+
57
+ If you are unfamiliar with the terminology, you can read up at [http://www.unlv.edu/getinvolved/greek-definitions](http://www.unlv.edu/getinvolved/greek-definitions).
58
+
59
+ ### Configuring
60
+
61
+ In order to use your Fraternity, you have to configure it before you use it.
62
+
63
+ ```
64
+ Fraternity.configure do |config|
65
+ configure.database_url = ENV["DATABASE_URL"]
66
+ configure.send_invite = lambda do |pledge|
67
+ BetaMailer.invite_email(pledge).deliver
68
+ end
69
+ end
70
+ ```
71
+
72
+ ### Pledging
73
+
74
+ To sign up pledges, you first need to rush. Collect email addresses (and any additional information) to get in line for membership at the frat house.
75
+
76
+ ```
77
+ params = { email: "jeremy.piven@example.com" } # Optional attributes you want to save such as first_name, last_name, etc.
78
+ pledge = Fraternity.rush! params
79
+ ```
80
+
81
+ The above saves the information to the pledges database and creates a token for a `Pledge`
82
+
83
+ ### Moving up the initiation line
84
+
85
+ **Coming soon**
86
+
87
+ ### Inviting a new pledge
88
+
89
+ Send out email invitations to the next set of pledges based on their initiation number. A quota is specified for the number you want to invite.
90
+
91
+ ```
92
+ invited = Fraternity.bid! quota
93
+ ```
94
+
95
+ The above saves the date/time of the invite to all the invited pledges and returns an array of the invited.
96
+
97
+ The above will also call the `send_invite` proc that you have set up in the configuration. You are responsible for sending the invite to the pledge any way you like.
98
+
99
+ Find out if a pledge has been invited
100
+
101
+ ```
102
+ Fraternity::Pledge.find(123).invited?
103
+ ```
104
+
105
+ Resend an invite
106
+
107
+ ```
108
+ Fraternity::Pledge.find(123).bid!
109
+ ```
110
+
111
+ ### Accepting a pledge
112
+
113
+ Check to see if a pledge is ready to be crossed into a full time member (invited and not crossed)
114
+
115
+ ```
116
+ Fraternity::Pledge.find(token).ready?
117
+ ```
118
+
119
+ Check to see if a pledge has been crossed into a full member
120
+
121
+ ```
122
+ Fraternity::Pledge.find(token).crossed?
123
+ ```
124
+
125
+ Convert the pledge into a full member (accept the invitation).
126
+
127
+ ```
128
+ Fraternity::Pledge.cross! token
129
+ ```
130
+
131
+ ## CONTRIBUTING
132
+
133
+ 1. Clone the repository `git clone https://github.com/brilliantfantastic/fraternity`
134
+ 1. Create a feature branch `git checkout -b my-awesome-feature`
135
+ 1. Codez!
136
+ 1. Commit your changes (small commits please)
137
+ 1. Push your new branch `git push origin my-awesome-feature`
138
+ 1. Create a pull request `hub pull-request -b brilliantfantastic:master -h brilliantfantastic:my-awesome-feature`
139
+
140
+ ## RELEASING A NEW GEM
141
+
142
+ 1. Bump the VERSION in `lib/fraternity/version.rb`
143
+ 1. Commit changes and push to GitHub
144
+ 1. run `bundle exec rake build`
145
+ 1. run `bundle exec rake release`
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ begin
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task default: :spec
7
+ rescue LoadError
8
+ end
9
+
10
+ require 'coveralls/rake/task'
11
+ Coveralls::RakeTask.new
12
+
13
+ namespace :fraternity do
14
+ task :install do
15
+ # read the migration
16
+ base_file_name = "create_pledges.rb"
17
+ template = File.join File.dirname(__FILE__), "lib/generators/fraternity/templates/migration", base_file_name
18
+ contents = File.open(template) { |f| f.read }
19
+
20
+ # create the migration
21
+ destination = ENV["DESTINATION"] || "."
22
+ unless File.directory?(destination)
23
+ FileUtils.mkdir_p destination
24
+ end
25
+ timestamp = Time.now.to_i
26
+ destination_file = File.join destination, "#{timestamp}_#{base_file_name}"
27
+ File.open(destination_file, 'w') { |f| f.write(contents) }
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fraternity/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fraternity"
8
+ spec.version = Fraternity::VERSION
9
+
10
+ spec.authors = ["Jamie Wright"]
11
+ spec.email = ["jamie@brilliantfantastic.com"]
12
+
13
+ spec.summary = "An easier way to rush for a beta"
14
+ spec.description = %q{
15
+ Collect and store a list of pledges who would like access to your beta. You can send out bids to those
16
+ pledges and allow them to gain access to your beta.
17
+ }
18
+
19
+ spec.homepage = "http://github.com/brilliantfantastic/fraternity"
20
+ spec.license = "MIT"
21
+
22
+ spec.files = `git ls-files`.split($/)
23
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "rake"
27
+ spec.add_dependency "lotus-model"
28
+ spec.add_dependency "lotus-validations"
29
+ end
@@ -0,0 +1,14 @@
1
+ module Fraternity
2
+ class Bidder
3
+ def initialize(pledge)
4
+ @pledge = pledge
5
+ end
6
+
7
+ def bid!
8
+ @pledge.invite!
9
+ Repositories::PledgeRepository.persist @pledge
10
+ Fraternity.configuration.send_invite.call @pledge
11
+ @pledge
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ module Fraternity
2
+ class Configuration
3
+ attr_accessor :database_url, :send_invite
4
+
5
+ def initialize
6
+ @send_invite = lambda { |pledge| pledge }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Fraternity
2
+ class PerpError < StandardError; end
3
+ end
@@ -0,0 +1,45 @@
1
+ require "lotus/validations"
2
+
3
+ module Fraternity
4
+ class Pledge
5
+ include Lotus::Validations
6
+
7
+ attr_accessor :id, :email, :first_name, :last_name, :token, :initiation_number, :invited_at, :accepted_at
8
+
9
+ validates :email, presence: true, format: /[-0-9a-zA-Z.+_]+@[-0-9a-zA-Z.+_]+\.[a-zA-Z]{2,4}/
10
+ validates :token, presence: true
11
+ validates :initiation_number, presence: true
12
+
13
+ def initialize(attributes={})
14
+
15
+ @id, @email, @first_name, @last_name, @token, @initiation_number, @invited_at, @accepted_at =
16
+ attributes.values_at :id, :email, :first_name, :last_name, :token, :initiation_number, :invited_at, :accepted_at
17
+ end
18
+
19
+ def bid!
20
+ Bidder.new(self).bid!
21
+ end
22
+
23
+ def invite!
24
+ self.invited_at = DateTime.now
25
+ end
26
+
27
+ def invited?
28
+ !self.invited_at.nil?
29
+ end
30
+
31
+ def cross!(token)
32
+ raise Fraternity::PerpError if !invited?
33
+ raise Fraternity::TokenMismatchError.new(self.token, token) if token != self.token
34
+ self.accepted_at = DateTime.now
35
+ end
36
+
37
+ def crossed?
38
+ !self.accepted_at.nil?
39
+ end
40
+
41
+ def ready?
42
+ self.invited? && !self.crossed?
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ require 'lotus/repository'
2
+
3
+ module Fraternity
4
+ module Repositories
5
+ class PledgeRepository
6
+ include Lotus::Repository
7
+
8
+ def self.find_by_id(id)
9
+ query do
10
+ where(id: id)
11
+ end.first
12
+ end
13
+
14
+ def self.find_by_token(token)
15
+ query do
16
+ where(token: token)
17
+ end.first
18
+ end
19
+
20
+ def self.oldest_uninvited_by_initiation_number(limit=8)
21
+ query do
22
+ where(invited_at: nil).
23
+ order(:initiation_number)
24
+ end.limit(limit)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ require "lotus/model/mapper"
2
+ require "lotus/model/adapters/sql_adapter"
3
+ require_relative "repositories/pledge_repository"
4
+
5
+ module Fraternity
6
+ module Repositories
7
+ @@mapping = Lotus::Model::Mapper.new do
8
+ collection :pledges do
9
+ entity Fraternity::Pledge
10
+ repository PledgeRepository
11
+
12
+ attribute :id, Integer
13
+ attribute :email, String
14
+ attribute :first_name, String
15
+ attribute :last_name, String
16
+ attribute :token, String
17
+ attribute :initiation_number, Integer
18
+ attribute :invited_at, DateTime
19
+ attribute :accepted_at, DateTime
20
+ end
21
+ end
22
+
23
+ def self.mapping
24
+ @@mapping
25
+ end
26
+
27
+ def self.initiation!(database_url)
28
+ adapter = Lotus::Model::Adapters::SqlAdapter.new(mapping, database_url)
29
+ PledgeRepository.adapter = adapter
30
+ mapping.load!
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ require 'securerandom'
2
+
3
+ module Fraternity
4
+ class TemporaryToken
5
+ def self.generate_random_token
6
+ SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Fraternity
2
+ class TokenMismatchError < StandardError
3
+ def initialize(expected_token, actual_token)
4
+ super "Expected token #{expected_token}, but was #{actual_token}"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Fraternity
2
+ VERSION = "0.0.1"
3
+ end
data/lib/fraternity.rb ADDED
@@ -0,0 +1,42 @@
1
+ require "fraternity/version"
2
+ require "fraternity/bidder"
3
+ require "fraternity/configuration"
4
+ require "fraternity/perp_error"
5
+ require "fraternity/pledge"
6
+ require "fraternity/repositories"
7
+ require "fraternity/temporary_token"
8
+ require "fraternity/token_mismatch_error"
9
+
10
+ module Fraternity
11
+ def self.configuration
12
+ @configuration ||= Fraternity::Configuration.new
13
+ end
14
+
15
+ def self.configure(initiate=true)
16
+ yield configuration if block_given?
17
+ Repositories.initiation! configuration.database_url if initiate
18
+ end
19
+
20
+ def self.rush(params={})
21
+ params[:token] ||= TemporaryToken.generate_random_token
22
+ params[:initiation_number] ||= Time.now.to_i
23
+ Fraternity::Pledge.new params
24
+ end
25
+
26
+ def self.rush!(params)
27
+ Repositories::PledgeRepository.create self.rush(params)
28
+ end
29
+
30
+ def self.bid!(quota)
31
+ Repositories::PledgeRepository.oldest_uninvited_by_initiation_number(quota).collect do |pledge|
32
+ pledge.bid!
33
+ end
34
+ end
35
+
36
+ def self.find(identifier)
37
+ if identifier.is_a? Integer
38
+ return Repositories::PledgeRepository.find_by_id identifier
39
+ end
40
+ Repositories::PledgeRepository.find_by_token identifier
41
+ end
42
+ end
@@ -0,0 +1,14 @@
1
+ Sequel.migration do
2
+ change do
3
+ create_table :pledges do
4
+ primary_key :id
5
+ String :token
6
+ String :email
7
+ String :first_name
8
+ String :last_name
9
+ Integer :initiation_number
10
+ DateTime :invited_at
11
+ DateTime :accepted_at
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+ describe Fraternity::Configuration do
2
+ it "has a default send_invite proc" do
3
+ configuration = Fraternity::Configuration.new
4
+ expect { configuration.send_invite.call(nil) }.to_not raise_error
5
+ end
6
+ end
@@ -0,0 +1,105 @@
1
+ describe Fraternity::Pledge do
2
+ describe "validations" do
3
+ it "requires an email address" do
4
+ pledge = Fraternity::Pledge.new
5
+ expect(pledge).to_not be_valid
6
+ expect(pledge.errors.for(:email).first.validation).to eq :presence
7
+ end
8
+
9
+ it "requires a valid email address" do
10
+ pledge = Fraternity::Pledge.new email: "blah@test"
11
+ expect(pledge).to_not be_valid
12
+ expect(pledge.errors.for(:email).first.validation).to eq :format
13
+ end
14
+
15
+ it "requires a token" do
16
+ pledge = Fraternity::Pledge.new email: "jimmy@example.com", token: ""
17
+ expect(pledge).to_not be_valid
18
+ expect(pledge.errors.for(:token).first.validation).to eq :presence
19
+ end
20
+
21
+ it "requires an initiation number" do
22
+ pledge = Fraternity::Pledge.new email: "jimmy@example.com", token: "123456", initiation_number: ""
23
+ expect(pledge).to_not be_valid
24
+ expect(pledge.errors.for(:initiation_number).first.validation).to eq :presence
25
+ end
26
+ end
27
+
28
+ describe "#invited?" do
29
+ it "is not invited if the date and time when they were invited is not set" do
30
+ pledge = Fraternity::Pledge.new
31
+ expect(pledge).to_not be_invited
32
+ end
33
+
34
+ it "is invited if the date and time when they were invited is set" do
35
+ pledge = Fraternity::Pledge.new invited_at: DateTime.now
36
+ expect(pledge).to be_invited
37
+ end
38
+ end
39
+
40
+ describe "#invite!" do
41
+ it "sets the date and time of when the pledge was invited to the current date and time" do
42
+ pledge = Fraternity::Pledge.new
43
+ pledge.invite!
44
+ expect(pledge).to be_invited
45
+ end
46
+ end
47
+
48
+ describe "#crossed?" do
49
+ it "is not crossed if they have not accepted the invitation" do
50
+ pledge = Fraternity::Pledge.new
51
+ expect(pledge).to_not be_crossed
52
+ end
53
+
54
+ it "is crossed if they have accepted the invitation" do
55
+ pledge = Fraternity::Pledge.new accepted_at: DateTime.now
56
+ expect(pledge).to be_crossed
57
+ end
58
+ end
59
+
60
+ describe "#cross!" do
61
+ it "sets the date and time of when the pledge has accepted the invite to the current date and time" do
62
+ token = "12345"
63
+ pledge = Fraternity::Pledge.new token: token, invited_at: DateTime.now
64
+ pledge.cross! token
65
+ expect(pledge).to be_crossed
66
+ end
67
+
68
+ it "does not cross over if the token does not match" do
69
+ pledge = Fraternity::Pledge.new token: "12345", invited_at: DateTime.now
70
+ expect { pledge.cross! "blah" }.to raise_error Fraternity::TokenMismatchError
71
+ end
72
+
73
+ it "does not cross over if the pledge was not invited" do
74
+ token = "12345"
75
+ pledge = Fraternity::Pledge.new token: token
76
+ expect { pledge.cross! token }.to raise_error Fraternity::PerpError
77
+ end
78
+ end
79
+
80
+ describe "#bid!" do
81
+ it "updates the date and time they were invited" do
82
+ pledge = Fraternity::Pledge.new id: 123, token: "12345", email: "jimmy@example.com", invited_at: DateTime.new(2015, 1, 18)
83
+ allow(Fraternity::Repositories::PledgeRepository).to receive(:persist).and_return pledge
84
+ pledge.bid!
85
+ expect(((DateTime.now - pledge.invited_at) * 24 * 60 * 60).to_i).to be < 1
86
+ end
87
+ end
88
+
89
+ describe "#ready?" do
90
+ it "returns true if the pledge is invited but not yet crossed" do
91
+ pledge = Fraternity::Pledge.new token: "1234", invited_at: DateTime.now
92
+ expect(pledge).to be_ready
93
+ end
94
+
95
+ it "is not ready if they have not been invited" do
96
+ pledge = Fraternity::Pledge.new token: "1234"
97
+ expect(pledge).to_not be_ready
98
+ end
99
+
100
+ it "is not ready if they have crossed" do
101
+ pledge = Fraternity::Pledge.new token: "1234", invited_at: DateTime.now, accepted_at: DateTime.now
102
+ expect(pledge).to_not be_ready
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,56 @@
1
+ describe Fraternity::Repositories::PledgeRepository do
2
+ before { load_repositories! }
3
+
4
+ describe ".find_by_token" do
5
+ let(:token) { "YUSGH764" }
6
+ let(:pledge) { Fraternity::Repositories::PledgeRepository.create(Fraternity::Pledge.new(email: "jimmy@example.com", token: token, initiation_number: Time.now.to_i)) }
7
+
8
+ it "returns the first pledge with the token" do
9
+ pledge
10
+ actual = Fraternity::Repositories::PledgeRepository.find_by_token token
11
+ expect(actual.id).to eq pledge.id
12
+ end
13
+
14
+ it "returns nil if the pledge does not exist" do
15
+ actual = Fraternity::Repositories::PledgeRepository.find_by_token "blah"
16
+ expect(actual).to be_nil
17
+ end
18
+ end
19
+
20
+ describe ".find_by_id" do
21
+ let(:pledge) { Fraternity::Repositories::PledgeRepository.create(Fraternity::Pledge.new(email: "jimmy@example.com", token: "12345", initiation_number: Time.now.to_i)) }
22
+
23
+ it "returns the first pledge with the id" do
24
+ pledge
25
+ actual = Fraternity::Repositories::PledgeRepository.find_by_id pledge.id
26
+ expect(actual.id).to eq pledge.id
27
+ end
28
+
29
+ it "returns nil if the pledge does not exist" do
30
+ actual = Fraternity::Repositories::PledgeRepository.find_by_id 123
31
+ expect(actual).to be_nil
32
+ end
33
+ end
34
+
35
+ describe ".oldest_univited_by_initiation_number" do
36
+ let(:four_days_ago) { Time.now.to_i - 24 * 60 * 60 * 4 }
37
+ let(:six_days_ago) { Time.now.to_i - 24 * 60 * 60 * 6 }
38
+ let(:ten_days_ago) { Time.now.to_i - 24 * 60 * 60 * 10 }
39
+
40
+ let(:oldest_pledge) { Fraternity::Repositories::PledgeRepository.create(Fraternity::Pledge.new(email: "jimmy@example.com", token: "1234", initiation_number: ten_days_ago)) }
41
+ let(:middle_pledge) { Fraternity::Repositories::PledgeRepository.create(Fraternity::Pledge.new(email: "robert@example.com", token: "5678", initiation_number: six_days_ago)) }
42
+ let(:newest_pledge) { Fraternity::Repositories::PledgeRepository.create(Fraternity::Pledge.new(email: "john@example.com", token: "9123", initiation_number: four_days_ago)) }
43
+
44
+ before { [middle_pledge, newest_pledge, oldest_pledge] } # place in database in this order
45
+
46
+ it "returns the oldest pledges based on their initiation number" do
47
+ pledges = Fraternity::Repositories::PledgeRepository.oldest_uninvited_by_initiation_number
48
+ expect(pledges.map(&:email)).to eq ["jimmy@example.com", "robert@example.com", "john@example.com"]
49
+ end
50
+
51
+ it "returns a limited number of pledges" do
52
+ pledges = Fraternity::Repositories::PledgeRepository.oldest_uninvited_by_initiation_number(2)
53
+ expect(pledges.map(&:email)).to eq ["jimmy@example.com", "robert@example.com"]
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,8 @@
1
+ describe Fraternity::Repositories do
2
+ describe ".initiation!" do
3
+ it "sets the adapters for the repositories to a SQL adapter" do
4
+ Fraternity::Repositories.initiation! "sqlite://blah.db"
5
+ expect(Fraternity::Repositories::PledgeRepository.instance_variable_get("@adapter")).to be_instance_of Lotus::Model::Adapters::SqlAdapter
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ describe Fraternity::TemporaryToken do
2
+ describe ".generate_random_token" do
3
+ it "generates a unique random token" do
4
+ tokens = []
5
+ 50.times { tokens << Fraternity::TemporaryToken.generate_random_token }
6
+ expect(tokens.uniq.length).to eq 50
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ describe Fraternity::TokenMismatchError do
2
+ it "describes the mismatched tokens" do
3
+ expected = "1234"
4
+ actual = "5678"
5
+ error = Fraternity::TokenMismatchError.new expected, actual
6
+ (expect(error.message)).to eq "Expected token #{expected}, but was #{actual}"
7
+ end
8
+ end
@@ -0,0 +1,99 @@
1
+ describe Fraternity do
2
+ describe ".bid!" do
3
+ let(:pledge) { Fraternity::Repositories::PledgeRepository.create(Fraternity::Pledge.new(email: "jimmy@example.com", token: "1234", initiation_number: Time.now.to_i)) }
4
+
5
+ before do
6
+ load_repositories!
7
+ pledge
8
+ end
9
+
10
+ it "invites the uninvited" do
11
+ pledges = Fraternity.bid! 5
12
+ expect(pledges.to_a[0].id).to eq pledge.id
13
+ expect(pledges.to_a[0]).to be_invited
14
+ end
15
+
16
+ it "sends the invite" do
17
+ sent_invite = false
18
+ Fraternity.configure(false) do |c|
19
+ c.send_invite = lambda do |pledge|
20
+ sent_invite = true
21
+ end
22
+ end
23
+ pledges = Fraternity.bid! 5
24
+ expect(sent_invite).to be true
25
+ end
26
+ end
27
+
28
+ describe ".configure" do
29
+ it "yields an instance of configuration" do
30
+ Fraternity.configure(false) do |config|
31
+ expect(config).to eq Fraternity.configuration
32
+ end
33
+ end
34
+ end
35
+
36
+ describe ".find" do
37
+ let(:token) { "HJDKSYS6782W" }
38
+ let(:pledge) { Fraternity::Pledge.new id: 123, token: token, email: "jimmy@example.com" }
39
+
40
+ it "returns a pledge based on their token" do
41
+ allow(Fraternity::Repositories::PledgeRepository).to receive(:find_by_token).and_return pledge
42
+ actual = Fraternity.find token
43
+ expect(actual.id).to eq pledge.id
44
+ end
45
+
46
+ it "returns a pledge based on their id" do
47
+ allow(Fraternity::Repositories::PledgeRepository).to receive(:find_by_id).and_return pledge
48
+ actual = Fraternity.find pledge.id
49
+ expect(actual.id).to eq pledge.id
50
+ end
51
+ end
52
+
53
+ describe ".rush" do
54
+ it "rushes with parameters that describe the pledge" do
55
+ expect { Fraternity.rush email: "blah" }.to_not raise_error
56
+ end
57
+
58
+ it "creates a new pledge with the specified parameters" do
59
+ pledge = Fraternity.rush email: "jimmy@example.com"
60
+ expect(pledge.email).to eq "jimmy@example.com"
61
+ end
62
+
63
+ it "populates a token for the pledge to use for joining" do
64
+ pledge = Fraternity.rush
65
+ expect(pledge.token).to_not be_empty
66
+ end
67
+
68
+ it "uses the provided token if there is one" do
69
+ pledge = Fraternity.rush token: "blah"
70
+ expect(pledge.token).to eq "blah"
71
+ end
72
+
73
+ it "creates an initiation number" do
74
+ pledge = Fraternity.rush
75
+ expect(pledge.initiation_number).to_not be_nil
76
+ initiated_at = Time.at pledge.initiation_number
77
+ expect((Time.now - initiated_at).to_i).to be < 1
78
+ end
79
+
80
+ it "uses the provided initiation number if there is one" do
81
+ pledge = Fraternity.rush initiation_number: 12345
82
+ expect(pledge.initiation_number).to eq 12345
83
+ end
84
+ end
85
+
86
+ describe ".rush!" do
87
+ before { load_repositories! }
88
+
89
+ it "creates a new pledge with the specified parameters" do
90
+ pledge = Fraternity.rush! email: "jimmy@example.com"
91
+ expect(pledge.email).to eq "jimmy@example.com"
92
+ end
93
+
94
+ it "saves the new pledge to the database" do
95
+ pledge = Fraternity.rush! email: "jimmy@example.com"
96
+ expect(pledge.id).to_not be_nil
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,29 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ require "fraternity"
5
+
6
+ ROOT = File.expand_path('../../', __FILE__)
7
+ Dir[File.join(ROOT, 'spec', 'support', '**/*.rb')].each { |f| require f }
8
+
9
+ RSpec.configure do |config|
10
+ config.expect_with :rspec do |expectations|
11
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
12
+ end
13
+
14
+ config.mock_with :rspec do |mocks|
15
+ mocks.verify_partial_doubles = true
16
+ end
17
+
18
+ config.filter_run :focus
19
+ config.run_all_when_everything_filtered = true
20
+
21
+ if config.files_to_run.one?
22
+ config.default_formatter = 'doc'
23
+ end
24
+
25
+ config.profile_examples = 10
26
+
27
+ config.order = :random
28
+ Kernel.srand config.seed
29
+ end
@@ -0,0 +1,6 @@
1
+ def load_repositories!
2
+ require "lotus/model/adapters/memory_adapter"
3
+ mapping = Fraternity::Repositories.mapping
4
+ Fraternity::Repositories::PledgeRepository.adapter = Lotus::Model::Adapters::MemoryAdapter.new mapping
5
+ mapping.load!
6
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fraternity
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jamie Wright
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: lotus-model
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: lotus-validations
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: "\n Collect and store a list of pledges who would
56
+ like access to your beta. You can send out bids to those\n pledges
57
+ and allow them to gain access to your beta.\n "
58
+ email:
59
+ - jamie@brilliantfantastic.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".coveralls.yml"
65
+ - ".gitignore"
66
+ - ".rspec"
67
+ - ".ruby-version"
68
+ - Gemfile
69
+ - Gemfile.lock
70
+ - README.md
71
+ - Rakefile
72
+ - fraternity.gemspec
73
+ - lib/fraternity.rb
74
+ - lib/fraternity/bidder.rb
75
+ - lib/fraternity/configuration.rb
76
+ - lib/fraternity/perp_error.rb
77
+ - lib/fraternity/pledge.rb
78
+ - lib/fraternity/repositories.rb
79
+ - lib/fraternity/repositories/pledge_repository.rb
80
+ - lib/fraternity/temporary_token.rb
81
+ - lib/fraternity/token_mismatch_error.rb
82
+ - lib/fraternity/version.rb
83
+ - lib/generators/fraternity/templates/migration/create_pledges.rb
84
+ - spec/fraternity/configuration_spec.rb
85
+ - spec/fraternity/pledge_spec.rb
86
+ - spec/fraternity/repositories/pledge_repository_spec.rb
87
+ - spec/fraternity/repositories_spec.rb
88
+ - spec/fraternity/temporary_token_spec.rb
89
+ - spec/fraternity/token_mismatch_error_spec.rb
90
+ - spec/fraternity_spec.rb
91
+ - spec/spec_helper.rb
92
+ - spec/support/repository_helper.rb
93
+ homepage: http://github.com/brilliantfantastic/fraternity
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.4.5
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: An easier way to rush for a beta
117
+ test_files:
118
+ - spec/fraternity/configuration_spec.rb
119
+ - spec/fraternity/pledge_spec.rb
120
+ - spec/fraternity/repositories/pledge_repository_spec.rb
121
+ - spec/fraternity/repositories_spec.rb
122
+ - spec/fraternity/temporary_token_spec.rb
123
+ - spec/fraternity/token_mismatch_error_spec.rb
124
+ - spec/fraternity_spec.rb
125
+ - spec/spec_helper.rb
126
+ - spec/support/repository_helper.rb