invite_only 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f8e2a675b3381913c09924c4bf4a0615f9f5843f
4
+ data.tar.gz: e1adef2dacc69f6c4b6852b93b2f109a578a5fa8
5
+ SHA512:
6
+ metadata.gz: 4a0e65ec20150146fd8177f6f77500f02e12715719d5d0c9e685d78194bb3c58deb6dbfb29a9bbe9312a292ff787d4ea79373127664badbe31e1c08aed7a8028
7
+ data.tar.gz: 11f1161fa342b83f40bc5c891fdd52491896a32a54cd5f60f5f7ede0cd7a34afc0f9083b2b89e7a66b675b5566ed23a3591a1a2c16f5bf94c10128059a00b5d4
data/.DS_Store ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in invite_only.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Mez
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,128 @@
1
+ Invite Only
2
+ ==============
3
+
4
+ [![Build Status](https://travis-ci.org/mez/invite_only.png?branch=master)](https://travis-ci.org/mez/invite_only)
5
+
6
+
7
+ This gem was inspired by acts_as_tenant. I really liked the fail-safe and out-of-the-way manner of acts_as_tenant! Hence, this is a very low level abstraction layer to help deal with invites to your applications and integrates (near) seamless with Rails.
8
+
9
+ In addition, acts_as_tenant:
10
+
11
+ * auto validates on create for any model that you want invite only for.
12
+ * sets up a helper method to allow you to create invite codes.
13
+
14
+ Installation
15
+ ------------
16
+ invite_only is tested for Rails 3.2 and up.
17
+
18
+ To use it, add it to your Gemfile:
19
+ ```sh
20
+ gem 'invite_only'
21
+ ```
22
+
23
+ ```sh
24
+ bundle install
25
+ ```
26
+ Run the generator to create the migration
27
+ ```sh
28
+ rails g inviter
29
+ ```
30
+
31
+ Getting started
32
+ ===============
33
+ There are three steps to get your app going with invite_only:
34
+
35
+ 1. enable_invite_only on your controller.
36
+ 2. call invite_only on the model you want protected.
37
+ 3. add virtual attribute :invite_code
38
+
39
+ Calling enable_invite_only on your controller
40
+ --------------------------
41
+
42
+ Add the enable_invite_only to a controller to get the helper method you need to generate a code.
43
+ ```ruby
44
+ class ApplicationController < ActionController::Base
45
+ enable_invite_only
46
+ end
47
+ ```
48
+ Now you will have a helper method called 'create_invite_code_for(identifier)'. The identifier is the string you use to uniquely identify the model. For example a User.email or User.username. Any string you want to id with. For example..
49
+
50
+ ```ruby
51
+ code = create_invite_code_for('foo@bar.com')
52
+ ```
53
+
54
+ Calling invite_only on your model
55
+ -------------------
56
+ ```ruby
57
+ class User < ActiveRecord::Base
58
+ invite_only(:email)
59
+ end
60
+ ```
61
+
62
+ 'invite_only(identifier=:email)' used in the model. Here identifier is the column the model uses as the identifier. invite_only defaults to :email, but in case you want to use for example :username or anything you like you can. This is used during the validation as the attribute to use for look up.
63
+
64
+ Adding virtual attribute :invite_only
65
+ -------------------
66
+ ```ruby
67
+ class User < ActiveRecord::Base
68
+ invite_only(:email)
69
+ attr_accessor :invite_code
70
+ end
71
+ ```
72
+
73
+ Thats it! Now whenever you try to save an invite_only model, it will not work unless you have the correct :invite_code. How you pass the value to the model is up to you. Simply just add the text field for the code in the form_for the model you are interested in.
74
+
75
+ To disable all this, simple remove the 'invite_only' call from the model.
76
+
77
+ Configuration options
78
+ ---------------------
79
+
80
+ You can control the different types of validation messages you can display. The attributes you have to create readers for are the following below.
81
+
82
+ ```ruby
83
+ attr_writer :code_blank_message,
84
+ :code_invalid_message,
85
+ :code_identifier_invalid_message,
86
+ :code_already_used_message
87
+ ```
88
+
89
+
90
+ The default validation error messages you get out of the box are.
91
+
92
+
93
+ | attribute name | Default |
94
+ |-----------------------------------|---------------------------------------------------|
95
+ | :code_blank_message | "is missing." |
96
+ | :code_invalid_message | "does not work with that #{identifier.to_s}." |
97
+ | :code_identifier_invalid_message | "is not valid." |
98
+ | :code_already_used_message | "has already been used." |
99
+
100
+ An example of setting your own error message is below
101
+
102
+ ```ruby
103
+ class User < ActiveRecord::Base
104
+ invite_only(:email)
105
+
106
+ protected
107
+ def code_blank_message
108
+ 'code is blank'
109
+ end
110
+ end
111
+ ```
112
+
113
+
114
+ To Do
115
+ -----
116
+ * Add support for mongodb
117
+
118
+ Bug reports & suggested improvements
119
+ ------------------------------------
120
+ If you have found a bug or want to suggest an improvement, please use our issue tracked at:
121
+
122
+ [github.com/mez/invite_only/issues](http://github.com/mez/invite_only/issues)
123
+
124
+ If you want to contribute, fork the project, code your improvements and make a pull request on [Github](http://github.com/mez/invite_only/). When doing so, please don't forget to add tests. If your contribution is fixing a bug it would be perfect if you could also submit a failing test, illustrating the issue.
125
+
126
+ License
127
+ -------
128
+ Copyright (c) 2014 Mez Gebre, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
6
+ task :test => :spec
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'invite_only/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "invite_only"
8
+ spec.version = InviteOnly::VERSION
9
+ spec.authors = ["Mez Gebre"]
10
+ spec.email = ["mez@jetcode.io"]
11
+ spec.summary = %q{Low level invite system.}
12
+ spec.description = %q{If you have a model (User, Account, etc..) and you only want invited people to be allowed creating those resource.
13
+ Good example is while in beta, invite only account creation.}
14
+ spec.homepage = "https://github.com/mez/invite_only"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency('rspec')
25
+ spec.add_development_dependency('rspec-rails')
26
+ spec.add_development_dependency('database_cleaner')
27
+ spec.add_development_dependency('sqlite3')
28
+ spec.add_development_dependency('debugger')
29
+
30
+ spec.add_dependency('rails','~> 3.2')
31
+ end
data/lib/.DS_Store ADDED
Binary file
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate inviter Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,19 @@
1
+ class InviterGenerator < Rails::Generators::Base
2
+ include Rails::Generators::Migration
3
+ extend Rails::Generators::Migration
4
+
5
+ source_root File.expand_path('../templates', __FILE__)
6
+
7
+
8
+ def self.next_migration_number(path)
9
+ Time.now.utc.strftime("%Y%m%d%H%M%S%6N")
10
+ end
11
+
12
+ #need to create the Invite table. Start out only supporting activerecord
13
+ def setup_active_record_for_invite_only
14
+ template "invite.rb", "app/models/invite.rb"
15
+ migration_template "create_invites.rb", "db/migrate/create_invites.rb"
16
+ rake 'db:migrate'
17
+ end
18
+
19
+ end
@@ -0,0 +1,11 @@
1
+ class CreateInvites < ActiveRecord::Migration
2
+ def change
3
+ create_table :invites do |t|
4
+ t.string :identifier
5
+ t.string :code
6
+ t.boolean :is_used, default: false
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ class Invite < ActiveRecord::Base
2
+
3
+ end
@@ -0,0 +1,25 @@
1
+ module InviteOnly
2
+ module ControllerExtensions
3
+
4
+ #use this method to enable invite only helper method in your controllers/views
5
+ def enable_invite_only
6
+ self.class_eval do
7
+ helper_method :create_invite_code_for
8
+
9
+ #use this helper to generate the code you need to hand off to the person
10
+ #identifier can be anything that IDs the person i.e. Email|Username etc...
11
+ #identifier: type=string
12
+ def create_invite_code_for(identifier)
13
+ #if email has been invited before, just update with new code.
14
+ invite = Invite.find_or_initialize_by identifier:identifier
15
+ #code is only valid for the identifier provided and can only be used once.
16
+ invite.is_used=false
17
+ invite.code=SecureRandom.urlsafe_base64
18
+ invite.save! #no need to validate
19
+ return invite.code
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ module InviteOnly
2
+ class Error < StandardError
3
+ end
4
+
5
+ module Errors
6
+ class NotRespondingToInviteCode < InviteOnly::Error
7
+ end
8
+
9
+ class NotRespondingToIdentifier < InviteOnly::Error
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,81 @@
1
+ module InviteOnly
2
+
3
+ module ModelExtensions
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def invite_only(identifier = :email, options={})
10
+
11
+ #on create make sure invite code is good
12
+ #validate :invite_code_legit?, on: :create
13
+
14
+ validate Proc.new {|m|
15
+ #first check we have the attributes we need
16
+ # You need to have an identifier default='email' and an 'invite_code' either as virtual attributes or columns
17
+ # in this model!
18
+ raise InviteOnly::Errors::NotRespondingToIdentifier unless m.respond_to? identifier.to_sym
19
+ raise InviteOnly::Errors::NotRespondingToInviteCode unless m.respond_to? :invite_code
20
+
21
+ #make sure it is not blank
22
+ if m.invite_code.blank?
23
+ errors.add(:invite_code, m.code_blank_message)
24
+ return
25
+ end
26
+
27
+ #make sure it is an existing code.
28
+ invite = Invite.find_by_code m.invite_code
29
+ if invite.nil?
30
+ errors.add(:invite_code, m.code_invalid_message)
31
+ return
32
+ end
33
+ #make sure it matches the identifier invite.
34
+ if invite.identifier != m.send(identifier.to_sym)
35
+ errors.add(:invite_code, m.code_identifier_invalid_message)
36
+ return
37
+ end
38
+
39
+ if invite.is_used
40
+ errors.add(:invite_code, m.code_already_used_message)
41
+ return
42
+ end
43
+ }, :on => :create
44
+
45
+ #if all checks out, be sure to invalidated code. Use Once Policy
46
+ after_create {
47
+ #look up the invite recode with the invite_code and mark it used.
48
+ invite = Invite.find_by_code self.invite_code
49
+ invite.is_used = true
50
+ invite.save!
51
+ }
52
+
53
+ private
54
+ #these are private scoped attributes used for the invite messages in validation
55
+ attr_writer :code_blank_message,
56
+ :code_invalid_message,
57
+ :code_identifier_invalid_message,
58
+ :code_already_used_message
59
+
60
+ #set the reader for the message validations if not set
61
+ define_method :code_blank_message do
62
+ @code_blank_message ||= "is missing."
63
+ end
64
+
65
+ define_method :code_identifier_invalid_message do
66
+ @code_identifier_invalid_message ||= "does not work with that #{identifier.to_s}."
67
+ end
68
+
69
+ define_method :code_invalid_message do
70
+ @code_invalid_message ||= "is not valid."
71
+ end
72
+
73
+ define_method :code_already_used_message do
74
+ @code_already_used_message ||= "has already been used."
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,3 @@
1
+ module InviteOnly
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ #RAILS_3 = ::ActiveRecord::VERSION::MAJOR >= 3
2
+
3
+ require "active_record"
4
+ require "action_controller"
5
+ require "active_model"
6
+
7
+
8
+ #$LOAD_PATH.unshift(File.dirname(__FILE__))
9
+
10
+ require "invite_only/version"
11
+ require "invite_only/errors"
12
+ require "invite_only/controller_extensions"
13
+ require "invite_only/model_extensions"
14
+
15
+ #$LOAD_PATH.shift
16
+
17
+ if defined?(ActiveRecord::Base)
18
+ ActiveRecord::Base.send(:include, InviteOnly::ModelExtensions)
19
+ ActionController::Base.extend InviteOnly::ControllerExtensions
20
+ end
21
+
22
+ module InviteOnly
23
+ end
data/spec/debug.log ADDED
@@ -0,0 +1,116 @@
1
+ # Logfile created on 2014-03-03 10:28:40 -0500 by logger.rb/44203
2
+ D, [2014-03-03T10:28:40.508658 #33360] DEBUG -- :  (0.3ms) CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "email" varchar(255)) 
3
+ D, [2014-03-03T10:28:40.509273 #33360] DEBUG -- :  (0.1ms) CREATE TABLE "accounts" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "username" varchar(255))
4
+ D, [2014-03-03T10:28:40.511405 #33360] DEBUG -- :  (0.1ms) CREATE TABLE "invites" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "is_used" boolean DEFAULT 'f', "code" varchar(255), "identifier" varchar(255)) 
5
+ D, [2014-03-03T10:28:40.512535 #33360] DEBUG -- :  (0.1ms) CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL)
6
+ D, [2014-03-03T10:28:40.512870 #33360] DEBUG -- :  (0.1ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
7
+ D, [2014-03-03T10:28:40.513033 #33360] DEBUG -- :  (0.0ms) SELECT version FROM "schema_migrations"
8
+ D, [2014-03-03T10:28:40.513176 #33360] DEBUG -- :  (0.1ms) INSERT INTO "schema_migrations" (version) VALUES ('1')
9
+ D, [2014-03-03T10:28:40.538433 #33360] DEBUG -- :  (0.1ms) DELETE FROM "users";
10
+ D, [2014-03-03T10:28:40.538633 #33360] DEBUG -- :  (0.1ms) SELECT name FROM sqlite_master WHERE type='table' AND name='sqlite_sequence';
11
+ D, [2014-03-03T10:28:40.538784 #33360] DEBUG -- :  (0.1ms) DELETE FROM sqlite_sequence where name = 'users';
12
+ D, [2014-03-03T10:28:40.538913 #33360] DEBUG -- :  (0.0ms) DELETE FROM "accounts";
13
+ D, [2014-03-03T10:28:40.539046 #33360] DEBUG -- :  (0.1ms) SELECT name FROM sqlite_master WHERE type='table' AND name='sqlite_sequence';
14
+ D, [2014-03-03T10:28:40.539193 #33360] DEBUG -- :  (0.1ms) DELETE FROM sqlite_sequence where name = 'accounts';
15
+ D, [2014-03-03T10:28:40.539314 #33360] DEBUG -- :  (0.0ms) DELETE FROM "invites";
16
+ D, [2014-03-03T10:28:40.539436 #33360] DEBUG -- :  (0.1ms) SELECT name FROM sqlite_master WHERE type='table' AND name='sqlite_sequence';
17
+ D, [2014-03-03T10:28:40.539596 #33360] DEBUG -- :  (0.0ms) DELETE FROM sqlite_sequence where name = 'invites';
18
+ D, [2014-03-03T10:28:40.542828 #33360] DEBUG -- :  (0.1ms) begin transaction
19
+ D, [2014-03-03T10:28:40.542960 #33360] DEBUG -- :  (0.0ms) commit transaction
20
+ D, [2014-03-03T10:28:40.543103 #33360] DEBUG -- :  (0.0ms) begin transaction
21
+ D, [2014-03-03T10:28:40.567289 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."identifier" = 'Doug.Butabi' LIMIT 1
22
+ D, [2014-03-03T10:28:40.573125 #33360] DEBUG -- : SQL (0.2ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "590aEF0I1mtYSSPR0V5iXw"], ["identifier", "Doug.Butabi"]]
23
+ D, [2014-03-03T10:28:40.577828 #33360] DEBUG -- :  (0.1ms) rollback transaction
24
+ D, [2014-03-03T10:28:40.578798 #33360] DEBUG -- :  (0.1ms) begin transaction
25
+ D, [2014-03-03T10:28:40.578932 #33360] DEBUG -- :  (0.0ms) commit transaction
26
+ D, [2014-03-03T10:28:40.579060 #33360] DEBUG -- :  (0.0ms) begin transaction
27
+ D, [2014-03-03T10:28:40.579875 #33360] DEBUG -- :  (0.0ms) rollback transaction
28
+ D, [2014-03-03T10:28:40.580533 #33360] DEBUG -- :  (0.0ms) begin transaction
29
+ D, [2014-03-03T10:28:40.580653 #33360] DEBUG -- :  (0.0ms) commit transaction
30
+ D, [2014-03-03T10:28:40.580774 #33360] DEBUG -- :  (0.0ms) begin transaction
31
+ D, [2014-03-03T10:28:40.581460 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "usercode"], ["identifier", "user@example.com"]]
32
+ D, [2014-03-03T10:28:40.581913 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2chanzcode"], ["identifier", "2chanz"]]
33
+ D, [2014-03-03T10:28:40.582356 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2paccode"], ["identifier", "2pac"]]
34
+ D, [2014-03-03T10:28:40.582775 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "bangbang"], ["identifier", "chiefkeef"]]
35
+ D, [2014-03-03T10:28:40.583214 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "kimk"], ["identifier", "yeezus"]]
36
+ D, [2014-03-03T10:28:40.586099 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'kimk' LIMIT 1
37
+ D, [2014-03-03T10:28:40.587108 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "accounts" ("username") VALUES (?) [["username", "yeezus"]]
38
+ D, [2014-03-03T10:28:40.587438 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'kimk' LIMIT 1
39
+ D, [2014-03-03T10:28:40.588429 #33360] DEBUG -- : SQL (0.1ms) UPDATE "invites" SET "is_used" = ? WHERE "invites"."id" = 5 [["is_used", true]]
40
+ D, [2014-03-03T10:28:40.589031 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'kimk' LIMIT 1
41
+ D, [2014-03-03T10:28:40.589435 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'kimk' LIMIT 1
42
+ D, [2014-03-03T10:28:40.589697 #33360] DEBUG -- :  (0.1ms) rollback transaction
43
+ D, [2014-03-03T10:28:40.590241 #33360] DEBUG -- :  (0.0ms) begin transaction
44
+ D, [2014-03-03T10:28:40.590359 #33360] DEBUG -- :  (0.0ms) commit transaction
45
+ D, [2014-03-03T10:28:40.590491 #33360] DEBUG -- :  (0.0ms) begin transaction
46
+ D, [2014-03-03T10:28:40.591011 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "usercode"], ["identifier", "user@example.com"]]
47
+ D, [2014-03-03T10:28:40.591418 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2chanzcode"], ["identifier", "2chanz"]]
48
+ D, [2014-03-03T10:28:40.591829 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2paccode"], ["identifier", "2pac"]]
49
+ D, [2014-03-03T10:28:40.592269 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "bangbang"], ["identifier", "chiefkeef"]]
50
+ D, [2014-03-03T10:28:40.592663 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "kimk"], ["identifier", "yeezus"]]
51
+ D, [2014-03-03T10:28:40.593173 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = '2paccode' LIMIT 1
52
+ D, [2014-03-03T10:28:40.593565 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = '2paccode' LIMIT 1
53
+ D, [2014-03-03T10:28:40.593829 #33360] DEBUG -- :  (0.1ms) rollback transaction
54
+ D, [2014-03-03T10:28:40.594398 #33360] DEBUG -- :  (0.1ms) begin transaction
55
+ D, [2014-03-03T10:28:40.594576 #33360] DEBUG -- :  (0.1ms) commit transaction
56
+ D, [2014-03-03T10:28:40.594789 #33360] DEBUG -- :  (0.1ms) begin transaction
57
+ D, [2014-03-03T10:28:40.595648 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "usercode"], ["identifier", "user@example.com"]]
58
+ D, [2014-03-03T10:28:40.596323 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2chanzcode"], ["identifier", "2chanz"]]
59
+ D, [2014-03-03T10:28:40.597022 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2paccode"], ["identifier", "2pac"]]
60
+ D, [2014-03-03T10:28:40.597682 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "bangbang"], ["identifier", "chiefkeef"]]
61
+ D, [2014-03-03T10:28:40.598287 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "kimk"], ["identifier", "yeezus"]]
62
+ D, [2014-03-03T10:28:40.598860 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'notbangbang' LIMIT 1
63
+ D, [2014-03-03T10:28:40.599240 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'notbangbang' LIMIT 1
64
+ D, [2014-03-03T10:28:40.599428 #33360] DEBUG -- :  (0.0ms) rollback transaction
65
+ D, [2014-03-03T10:28:40.599844 #33360] DEBUG -- :  (0.1ms) begin transaction
66
+ D, [2014-03-03T10:28:40.599948 #33360] DEBUG -- :  (0.0ms) commit transaction
67
+ D, [2014-03-03T10:28:40.600064 #33360] DEBUG -- :  (0.0ms) begin transaction
68
+ D, [2014-03-03T10:28:40.600539 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "usercode"], ["identifier", "user@example.com"]]
69
+ D, [2014-03-03T10:28:40.600941 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2chanzcode"], ["identifier", "2chanz"]]
70
+ D, [2014-03-03T10:28:40.601318 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2paccode"], ["identifier", "2pac"]]
71
+ D, [2014-03-03T10:28:40.601753 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "bangbang"], ["identifier", "chiefkeef"]]
72
+ D, [2014-03-03T10:28:40.602134 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "kimk"], ["identifier", "yeezus"]]
73
+ D, [2014-03-03T10:28:40.602922 #33360] DEBUG -- :  (0.0ms) rollback transaction
74
+ D, [2014-03-03T10:28:40.603271 #33360] DEBUG -- :  (0.0ms) begin transaction
75
+ D, [2014-03-03T10:28:40.603388 #33360] DEBUG -- :  (0.0ms) commit transaction
76
+ D, [2014-03-03T10:28:40.603505 #33360] DEBUG -- :  (0.0ms) begin transaction
77
+ D, [2014-03-03T10:28:40.603945 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "usercode"], ["identifier", "user@example.com"]]
78
+ D, [2014-03-03T10:28:40.604339 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2chanzcode"], ["identifier", "2chanz"]]
79
+ D, [2014-03-03T10:28:40.604730 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2paccode"], ["identifier", "2pac"]]
80
+ D, [2014-03-03T10:28:40.605116 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "bangbang"], ["identifier", "chiefkeef"]]
81
+ D, [2014-03-03T10:28:40.605485 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "kimk"], ["identifier", "yeezus"]]
82
+ D, [2014-03-03T10:28:40.608205 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'usercode' LIMIT 1
83
+ D, [2014-03-03T10:28:40.608549 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'usercode' LIMIT 1
84
+ D, [2014-03-03T10:28:40.609343 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "users" ("email") VALUES (?) [["email", "user@example.com"]]
85
+ D, [2014-03-03T10:28:40.609663 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'usercode' LIMIT 1
86
+ D, [2014-03-03T10:28:40.610134 #33360] DEBUG -- : SQL (0.1ms) UPDATE "invites" SET "is_used" = ? WHERE "invites"."id" = 1 [["is_used", true]]
87
+ D, [2014-03-03T10:28:40.610445 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'usercode' LIMIT 1
88
+ D, [2014-03-03T10:28:40.611155 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = '2chanzcode' LIMIT 1
89
+ D, [2014-03-03T10:28:40.611583 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "accounts" ("username") VALUES (?) [["username", "2chanz"]]
90
+ D, [2014-03-03T10:28:40.611929 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = '2chanzcode' LIMIT 1
91
+ D, [2014-03-03T10:28:40.612467 #33360] DEBUG -- : SQL (0.1ms) UPDATE "invites" SET "is_used" = ? WHERE "invites"."id" = 2 [["is_used", true]]
92
+ D, [2014-03-03T10:28:40.612784 #33360] DEBUG -- :  (0.1ms) rollback transaction
93
+ D, [2014-03-03T10:28:40.613499 #33360] DEBUG -- :  (0.1ms) begin transaction
94
+ D, [2014-03-03T10:28:40.613634 #33360] DEBUG -- :  (0.0ms) commit transaction
95
+ D, [2014-03-03T10:28:40.613756 #33360] DEBUG -- :  (0.0ms) begin transaction
96
+ D, [2014-03-03T10:28:40.614385 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "usercode"], ["identifier", "user@example.com"]]
97
+ D, [2014-03-03T10:28:40.614782 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2chanzcode"], ["identifier", "2chanz"]]
98
+ D, [2014-03-03T10:28:40.615178 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2paccode"], ["identifier", "2pac"]]
99
+ D, [2014-03-03T10:28:40.615568 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "bangbang"], ["identifier", "chiefkeef"]]
100
+ D, [2014-03-03T10:28:40.615951 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "kimk"], ["identifier", "yeezus"]]
101
+ D, [2014-03-03T10:28:40.616471 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'bar' LIMIT 1
102
+ D, [2014-03-03T10:28:40.626366 #33360] DEBUG -- :  (0.1ms) rollback transaction
103
+ D, [2014-03-03T10:28:40.626936 #33360] DEBUG -- :  (0.1ms) begin transaction
104
+ D, [2014-03-03T10:28:40.627110 #33360] DEBUG -- :  (0.1ms) commit transaction
105
+ D, [2014-03-03T10:28:40.627333 #33360] DEBUG -- :  (0.1ms) begin transaction
106
+ D, [2014-03-03T10:28:40.628208 #33360] DEBUG -- : SQL (0.1ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "usercode"], ["identifier", "user@example.com"]]
107
+ D, [2014-03-03T10:28:40.628705 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2chanzcode"], ["identifier", "2chanz"]]
108
+ D, [2014-03-03T10:28:40.629169 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "2paccode"], ["identifier", "2pac"]]
109
+ D, [2014-03-03T10:28:40.629549 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "bangbang"], ["identifier", "chiefkeef"]]
110
+ D, [2014-03-03T10:28:40.629943 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "invites" ("code", "identifier") VALUES (?, ?) [["code", "kimk"], ["identifier", "yeezus"]]
111
+ D, [2014-03-03T10:28:40.630736 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'kimk' LIMIT 1
112
+ D, [2014-03-03T10:28:40.631149 #33360] DEBUG -- : SQL (0.0ms) INSERT INTO "accounts" ("username") VALUES (?) [["username", "yeezus"]]
113
+ D, [2014-03-03T10:28:40.631446 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'kimk' LIMIT 1
114
+ D, [2014-03-03T10:28:40.631902 #33360] DEBUG -- : SQL (0.0ms) UPDATE "invites" SET "is_used" = ? WHERE "invites"."id" = 5 [["is_used", true]]
115
+ D, [2014-03-03T10:28:40.632197 #33360] DEBUG -- : Invite Load (0.1ms) SELECT "invites".* FROM "invites" WHERE "invites"."code" = 'kimk' LIMIT 1
116
+ D, [2014-03-03T10:28:40.632453 #33360] DEBUG -- :  (0.1ms) rollback transaction
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ class User < ActiveRecord::Base
4
+ invite_only(:email)
5
+ attr_accessor :invite_code
6
+ end
7
+
8
+ class RoxburyController < ActionController::Base
9
+ include Rails.application.routes.url_helpers
10
+ enable_invite_only
11
+ end
12
+
13
+ describe RoxburyController, type: :controller do
14
+
15
+ context 'when call the create_invite_code_for' do
16
+ controller do
17
+ def index
18
+ code = create_invite_code_for "Doug.Butabi"
19
+ render text:'Doug Butabi is finally making it into a club.'
20
+ end
21
+ end
22
+
23
+ it 'should be available as a method' do
24
+ expect { get :index }.not_to raise_error
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ #let's setup a test db
4
+ ActiveRecord::Schema.define(:version => 1) do
5
+ self.verbose = false
6
+
7
+ create_table :users, :force => true do |t|
8
+ t.column :email, :string
9
+ end
10
+
11
+ create_table :accounts, :force => true do |t|
12
+ t.column :username, :string
13
+ end
14
+
15
+ create_table :invites, :force => true do |t|
16
+ t.column :is_used, :boolean, default: false
17
+ t.column :code, :string
18
+ t.column :identifier, :string
19
+ end
20
+
21
+ end
22
+
23
+ # Setup the models
24
+ class User < ActiveRecord::Base
25
+ attr_accessor :invite_code
26
+ invite_only(:email)
27
+ end
28
+
29
+ class Account < ActiveRecord::Base
30
+ attr_accessor :invite_code
31
+ invite_only(:username)
32
+
33
+ protected
34
+ def code_blank_message
35
+ 'code is blank'
36
+ end
37
+ end
38
+
39
+ class Invite < ActiveRecord::Base
40
+ end
41
+
42
+ #let test a few things
43
+ describe InviteOnly do
44
+
45
+ describe 'model_extension' do
46
+ context 'when a new invite is created' do
47
+ let(:invite) { Invite.new }
48
+ it { expect(invite.is_used).to be false }
49
+ end
50
+
51
+ context 'when validating a model that used invite only' do
52
+ before do
53
+ Invite.create! code:'usercode', identifier:'user@example.com'
54
+ Invite.create! code:'2chanzcode', identifier:'2chanz'
55
+ Invite.create code:'2paccode', identifier:'2pac'
56
+ Invite.create code:'bangbang', identifier:'chiefkeef'
57
+ Invite.create code:'kimk', identifier:'yeezus'
58
+ end
59
+
60
+
61
+ it 'should use the identifier used to init invite_only' do
62
+ expect(User.create(email:'user@example.com', invite_code:'usercode')).to be_valid
63
+ expect(Account.create(username:'2chanz', invite_code:'2chanzcode')).to be_valid
64
+ end
65
+
66
+ it 'should not validate with correct invite_code but different identifier' do
67
+ #sorry 2chanz but this invite was for 2pac.
68
+ expect(Account.create(username:'2chanz', invite_code:'2paccode')).not_to be_valid
69
+ end
70
+
71
+ it 'should not validate with different invite_code but correct identifier' do
72
+ #sorry chiefkeef but you have wrong invite code
73
+ expect(Account.create(username:'chiefkeef', invite_code:'notbangbang')).not_to be_valid
74
+ end
75
+
76
+ it 'should only used once.' do
77
+ #yeezus should be good to go
78
+ expect(Account.create(username:'yeezus', invite_code:'kimk')).to be_valid
79
+ #not so fast ray j
80
+ expect(Account.create(username:'ray-j', invite_code:'kimk')).not_to be_valid
81
+ end
82
+
83
+ it 'should have errors when not valid' do
84
+ expect(Account.create(username:'foo', invite_code:'bar').errors.count).to eq(1)
85
+ end
86
+
87
+ it 'should show the correct error message on blank invite_code' do
88
+ #[:invite_code, ["code is blank"]] is the error message format
89
+ expect(Account.create(username:'chiefkeef', invite_code:'').errors.messages.first.last.first).to eq('code is blank')
90
+ end
91
+
92
+ it 'should set is_used to true after create' do
93
+ Account.create(username:'yeezus', invite_code:'kimk')
94
+ expect(Invite.find_by(code:'kimk').is_used).to be true
95
+ end
96
+ end
97
+ end
98
+ end
99
+
@@ -0,0 +1,48 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'database_cleaner'
5
+ require 'invite_only'
6
+ require 'rspec/rails'
7
+ require 'rails'
8
+
9
+ ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "debug.log"))
10
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',:database => ':memory:')
11
+
12
+ RSpec.configure do |config|
13
+ config.treat_symbols_as_metadata_keys_with_true_values = true
14
+ config.run_all_when_everything_filtered = true
15
+ config.filter_run :focus
16
+
17
+ # Run specs in random order to surface order dependencies. If you find an
18
+ # order dependency and want to debug it, you can fix the order by providing
19
+ # the seed, which is printed after each run.
20
+ # --seed 1234
21
+ config.order = 'random'
22
+
23
+ config.before(:suite) do
24
+ DatabaseCleaner.strategy = :transaction
25
+ DatabaseCleaner.clean_with(:truncation)
26
+ end
27
+
28
+ config.before(:each) do
29
+ DatabaseCleaner.start
30
+ end
31
+
32
+ config.after(:each) do
33
+ DatabaseCleaner.clean
34
+ end
35
+
36
+ config.infer_base_class_for_anonymous_controllers = true
37
+ config.expect_with :rspec do |c|
38
+ c.syntax = :expect
39
+ end
40
+ end
41
+
42
+ # Setup a test app
43
+ module NightAtTheRoxbury
44
+ class Application < Rails::Application; end
45
+ end
46
+
47
+ NightAtTheRoxbury::Application.config.secret_token = "KeUXs+xVS6fmtRe4TPw8sK5IC2T3ceL9DPa7S35Jb5+YzAqWREyoUA=="
48
+ NightAtTheRoxbury::Application.config.secret_key_base = "KeUXs+xVS6fmtRe4TPw8sK5IC2T3ceL9DPa7S35Jb5+YzAqWREyoUA=="
metadata ADDED
@@ -0,0 +1,170 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: invite_only
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mez Gebre
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-03 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: :development
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: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: database_cleaner
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: debugger
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.2'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.2'
111
+ description: |-
112
+ If you have a model (User, Account, etc..) and you only want invited people to be allowed creating those resource.
113
+ Good example is while in beta, invite only account creation.
114
+ email:
115
+ - mez@jetcode.io
116
+ executables: []
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - ".DS_Store"
121
+ - ".gitignore"
122
+ - ".rspec"
123
+ - Gemfile
124
+ - LICENSE.txt
125
+ - README.md
126
+ - Rakefile
127
+ - invite_only.gemspec
128
+ - lib/.DS_Store
129
+ - lib/generators/inviter/USAGE
130
+ - lib/generators/inviter/inviter_generator.rb
131
+ - lib/generators/inviter/templates/create_invites.rb
132
+ - lib/generators/inviter/templates/invite.rb
133
+ - lib/invite_only.rb
134
+ - lib/invite_only/controller_extensions.rb
135
+ - lib/invite_only/errors.rb
136
+ - lib/invite_only/model_extensions.rb
137
+ - lib/invite_only/version.rb
138
+ - spec/debug.log
139
+ - spec/invite_only/controller_extensions_spec.rb
140
+ - spec/invite_only/model_extensions_spec.rb
141
+ - spec/spec_helper.rb
142
+ homepage: https://github.com/mez/invite_only
143
+ licenses:
144
+ - MIT
145
+ metadata: {}
146
+ post_install_message:
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ required_ruby_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ requirements: []
161
+ rubyforge_project:
162
+ rubygems_version: 2.2.0
163
+ signing_key:
164
+ specification_version: 4
165
+ summary: Low level invite system.
166
+ test_files:
167
+ - spec/debug.log
168
+ - spec/invite_only/controller_extensions_spec.rb
169
+ - spec/invite_only/model_extensions_spec.rb
170
+ - spec/spec_helper.rb