accounts 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.rvmrc +53 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +167 -0
- data/README.mkd +105 -0
- data/Rakefile +24 -0
- data/accounts.gemspec +52 -0
- data/demo/views/change_email.haml +14 -0
- data/demo/views/change_password.haml +36 -0
- data/demo/views/forgot_password.haml +21 -0
- data/demo/views/logon.haml +24 -0
- data/demo/views/register.haml +15 -0
- data/demo/web_app.rb +99 -0
- data/features/change-email.feature +51 -0
- data/features/change-password.feature +89 -0
- data/features/register.feature +42 -0
- data/features/step_definitions/steps.rb +102 -0
- data/features/step_definitions/web_steps.rb +228 -0
- data/features/support/env.rb +18 -0
- data/features/support/paths.rb +29 -0
- data/features/support/unused.rb +29 -0
- data/lib/accounts.rb +79 -0
- data/lib/accounts/configure.rb +122 -0
- data/lib/accounts/helpers.rb +90 -0
- data/lib/accounts/model.rb +126 -0
- data/lib/accounts/version.rb +5 -0
- data/spec/user_model_spec.rb +105 -0
- metadata +263 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
# Copyright Westside Consulting LLC, Ann Arbor, MI, USA, 2012
|
2
|
+
|
3
|
+
module Accounts
|
4
|
+
module Helpers
|
5
|
+
class ::Accounts::AccountsError < Exception
|
6
|
+
attr_accessor :code
|
7
|
+
attr_accessor :message
|
8
|
+
|
9
|
+
def initialize(code, message)
|
10
|
+
@code = code
|
11
|
+
@message = message
|
12
|
+
end
|
13
|
+
|
14
|
+
def return_error_page
|
15
|
+
[ @code, @message ]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def site
|
20
|
+
scheme = request.env['rack.url_scheme']
|
21
|
+
host = request.env['HTTP_HOST'] # includes port number
|
22
|
+
"#{scheme}://#{host}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def send_change_password_link(account)
|
26
|
+
tok = ::Accounts::ActionToken.create({ :account => account, :action => 'reset password' })
|
27
|
+
link = "#{site}/response-token/#{tok.id}"
|
28
|
+
Accounts.deliver_change_password_link[account.email, link]
|
29
|
+
end
|
30
|
+
|
31
|
+
def send_change_email_confirmation(account, new_email)
|
32
|
+
tok = ::Accounts::ActionToken.create({
|
33
|
+
:account => account,
|
34
|
+
:action => 'change email',
|
35
|
+
:params => {:new_email => new_email}
|
36
|
+
})
|
37
|
+
link = "#{site}/response-token/#{tok.id}"
|
38
|
+
Accounts.deliver_change_email_confirmation[account.email, new_email, link]
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_email_confirmed(account)
|
42
|
+
account.status << :email_confirmed
|
43
|
+
account.taint! :status # taint!() defined in model.rb
|
44
|
+
account.save
|
45
|
+
Accounts.deliver_new_account_admin_notification[account.email]
|
46
|
+
end
|
47
|
+
|
48
|
+
def respond_to_token(id)
|
49
|
+
token = ::Accounts::ActionToken.get(id)
|
50
|
+
|
51
|
+
raise ::Accounts::AccountsError.new 404, %Q{Page not found. Go to <a href="/">home page</a>.} \
|
52
|
+
unless token
|
53
|
+
|
54
|
+
begin
|
55
|
+
on_email_confirmed token.account \
|
56
|
+
unless token.account.status.include? :email_confirmed
|
57
|
+
|
58
|
+
case token.action
|
59
|
+
when 'change email' then
|
60
|
+
token.account.email = token.params[:new_email]
|
61
|
+
token.account.save or return "We are unable to change your e-mail right now. Try again later."
|
62
|
+
session[:account_id] = token.account.id # this visitor is authenticated
|
63
|
+
redirect to("/logon?email=#{token.params[:new_email]}")
|
64
|
+
when 'reset password' then
|
65
|
+
session[:account_id] = token.account.id # this visitor is authenticated
|
66
|
+
redirect '/change-password'
|
67
|
+
else
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
ensure
|
71
|
+
token.destroy or raise "Failed to destroy token #{token.id}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def authenticate!(email, password)
|
76
|
+
account = ::Accounts::Account.first(:email => email) \
|
77
|
+
or return false
|
78
|
+
account.confirm_password(password) or return false
|
79
|
+
session[:account_id] = account.id
|
80
|
+
end
|
81
|
+
|
82
|
+
def register_new_account(email)
|
83
|
+
account = ::Accounts::Account.create ({ :email => email })
|
84
|
+
account.saved? or return "We are unable to register you at this time. Please try again later."
|
85
|
+
tok = ::Accounts::ActionToken.create({ :account => account, :action => 'reset password' })
|
86
|
+
link = "#{site}/response-token/#{tok.id}"
|
87
|
+
Accounts.deliver_registration_confirmation[account.email, link]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# Copyright Westside Consulting LLC, Ann Arbor, MI, USA, 2012
|
2
|
+
|
3
|
+
require 'data_mapper'
|
4
|
+
require 'dm-types/enum'
|
5
|
+
require 'dm-types/flag'
|
6
|
+
require 'digest/sha2'
|
7
|
+
|
8
|
+
DataMapper.setup(:default, ENV['DATABASE_URL'] || 'postgres:accounts')
|
9
|
+
DataMapper::Property::String.length(255)
|
10
|
+
DataMapper::Property::Boolean.allow_nil(false)
|
11
|
+
DataMapper::Property::Boolean.default(false)
|
12
|
+
|
13
|
+
#DataMapper::Model.raise_on_save_failure = true
|
14
|
+
|
15
|
+
#=begin
|
16
|
+
# Override definition in dm-core / lib / dm-core / resource.rb
|
17
|
+
# http://github.com/datamapper/dm-core/blob/master/lib/dm-core/resource.rb
|
18
|
+
# Get it to log messages when there is a problem saving.
|
19
|
+
module DataMapper
|
20
|
+
module Resource
|
21
|
+
|
22
|
+
#@@logger = Logger.new(STDOUT)
|
23
|
+
|
24
|
+
# override .save
|
25
|
+
# @see http://blog.jayfields.com/2006/12/ruby-alias-method-alternative.html
|
26
|
+
base_save = self.instance_method(:save)
|
27
|
+
|
28
|
+
define_method(:save) do |*a|
|
29
|
+
result = base_save.bind(self).call(*a)
|
30
|
+
|
31
|
+
if !result then
|
32
|
+
STDERR.puts "Cannot save #{self.class.to_s}"
|
33
|
+
STDERR.puts self.pretty_inspect
|
34
|
+
self.errors.each {|e| STDERR.puts e.to_s}
|
35
|
+
end
|
36
|
+
result
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
#=end
|
41
|
+
|
42
|
+
# modified from https://gist.github.com/763374
|
43
|
+
module DataMapper
|
44
|
+
module Resource
|
45
|
+
def taint! property
|
46
|
+
self.persistence_state = PersistenceState::Dirty.new(self) \
|
47
|
+
unless self.persistence_state.kind_of?(PersistenceState::Dirty)
|
48
|
+
self.persistence_state.original_attributes[properties[property]] = Object.new
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Example:
|
54
|
+
# my_resource.array_prop << 123
|
55
|
+
# my_resource.taint! :array_prop
|
56
|
+
# my_resource.save
|
57
|
+
|
58
|
+
module Accounts
|
59
|
+
|
60
|
+
class Account
|
61
|
+
include DataMapper::Resource
|
62
|
+
property :id, Serial
|
63
|
+
property :email, String, :unique => true
|
64
|
+
property :password, String, :required => false # a hash
|
65
|
+
property :status, Flag[:suspended, :email_confirmed]
|
66
|
+
property :last_logon, DateTime, :required => false
|
67
|
+
timestamps :created_at
|
68
|
+
timestamps :updated_at
|
69
|
+
|
70
|
+
def set_password(arg)
|
71
|
+
self.update :password => self.class.hashpasswd(arg)
|
72
|
+
end
|
73
|
+
|
74
|
+
def confirm_password(arg)
|
75
|
+
self.class.hashpasswd(arg) == self.password
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
@@digest = Digest::SHA2.new
|
81
|
+
SALT = 'b593b7bf01cd29d9cc15d11f9d81f586e255fd252fab264129e6046934876c23' # random
|
82
|
+
|
83
|
+
# Can't name this "hash". Name already taken.
|
84
|
+
def self.hashpasswd(arg)
|
85
|
+
@@digest.hexdigest(SALT + arg)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# An action-token represents permission for the agent to perform an action on behalf of a user.
|
90
|
+
class ActionToken
|
91
|
+
include DataMapper::Resource
|
92
|
+
|
93
|
+
@@digest = Digest::SHA2.new
|
94
|
+
|
95
|
+
property :id, String, :key => true, :default => lambda { |res, tok| @@digest.hexdigest(rand.to_s) }
|
96
|
+
property :action, String, :unique => :account
|
97
|
+
property :params, Object, :allow_nil => true # a hash of key => value
|
98
|
+
belongs_to :account
|
99
|
+
property :expires, DateTime, :default => Time.new + 24 * 3600 # one day
|
100
|
+
|
101
|
+
# override .save
|
102
|
+
# @see http://blog.jayfields.com/2006/12/ruby-alias-method-alternative.html
|
103
|
+
base_save = self.instance_method(:save)
|
104
|
+
|
105
|
+
define_method(:save) do |*args|
|
106
|
+
# If there is a previous instance, delete it
|
107
|
+
if self.class.count(:action => self.action, :account => self.account) then
|
108
|
+
self.class.destroy
|
109
|
+
end
|
110
|
+
result = base_save.bind(self).call(*args)
|
111
|
+
#STDERR.puts "#{self.inspect}.save returned #{result}"
|
112
|
+
end
|
113
|
+
|
114
|
+
base_destroy = self.instance_method(:destroy)
|
115
|
+
|
116
|
+
define_method(:destroy) do |*args|
|
117
|
+
# If there is a previous instance, delete it
|
118
|
+
result = base_destroy.bind(self).call(*args)
|
119
|
+
#STDERR.puts "#{self.inspect}.destroy returned #{result}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
DataMapper.finalize
|
126
|
+
DataMapper.auto_upgrade! # preserve existing database
|
@@ -0,0 +1,105 @@
|
|
1
|
+
$: << '../lib'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rspec'
|
5
|
+
|
6
|
+
# suppress excessive warnings from DataMapper libraries
|
7
|
+
$VERBOSE=nil
|
8
|
+
require 'accounts/model'
|
9
|
+
$VERBOSE=false
|
10
|
+
|
11
|
+
# Make sure we're still seeing warnings about our own code
|
12
|
+
FOO=:bar
|
13
|
+
FOO=:baz
|
14
|
+
|
15
|
+
begin
|
16
|
+
DataMapper.auto_migrate! # empty database
|
17
|
+
STDERR.puts "called DataMapper.auto_migrate!"
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Accounts::Account do
|
21
|
+
|
22
|
+
it 'contains e-mails and passwords and flags' do
|
23
|
+
account = Accounts::Account.create :email => "stewie@family.guy"
|
24
|
+
account.should be_saved
|
25
|
+
account.password.should be_nil
|
26
|
+
account.status.should have(0).flags
|
27
|
+
account.last_logon.should be_nil
|
28
|
+
account.created_at.should_not be_nil
|
29
|
+
account.updated_at.should_not be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'cannot create account with duplicate e-mail' do
|
33
|
+
account = Accounts::Account.create :email => "stewie@family.guy"
|
34
|
+
account.should_not be_saved
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'new user e-mail is initially invalid' do
|
38
|
+
account = Accounts::Account.create :email => "lois@family.guy"
|
39
|
+
#puts account.status.inspect
|
40
|
+
account.status.include?(:email_confirmed).should be_false
|
41
|
+
account.status.include?(:suspended).should be_false
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'responds to .set_password' do
|
45
|
+
account = Accounts::Account.create :email => "brian@family.guy"
|
46
|
+
account.should respond_to :set_password
|
47
|
+
account.set_password('hotforlois').should be_true
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'can confirm password' do
|
51
|
+
account = Accounts::Account.create :email => "peter@family.guy"
|
52
|
+
account.set_password('notsosmart').should be_true
|
53
|
+
account.confirm_password('notsosmart').should be_true
|
54
|
+
account.confirm_password('notsobright').should be_false
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'stores passwords as hashes' do
|
58
|
+
Accounts::Account.all.each do |acct|
|
59
|
+
if !acct.password.nil?
|
60
|
+
acct.password.should be_instance_of String
|
61
|
+
acct.password.length.should be == 64
|
62
|
+
acct.password.should_not match(/[^0-9a-f]/)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe Accounts::ActionToken do
|
69
|
+
before :all do
|
70
|
+
@meg = Accounts::Account.create :email => 'meg@familyguy.com'
|
71
|
+
@chris = Accounts::Account.create :email => 'chris@familyguy.com'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'can create a token for a user to perform a specific action' do
|
75
|
+
tok = Accounts::ActionToken.create :account => @meg, :action => 'party'
|
76
|
+
tok.should be_saved
|
77
|
+
tok.id.should be_instance_of String
|
78
|
+
tok.id.length.should be == 64
|
79
|
+
tok.id.should_not match(/[^0-9a-f]/)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'creating a new TokenAction for an action replaces any previous token' do
|
83
|
+
tas = Accounts::ActionToken.all(:account => @meg, :action => 'party')
|
84
|
+
tas.should_not be_nil
|
85
|
+
tas.should have(1).item
|
86
|
+
|
87
|
+
tok = Accounts::ActionToken.create :account => @meg, :action => 'party'
|
88
|
+
tok.should be_saved
|
89
|
+
tok.id.should_not be == tas[0].id
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'can return account and action given token' do
|
93
|
+
tok = Accounts::ActionToken.create :account => @chris, :action => 'act stupid'
|
94
|
+
ta_found = Accounts::ActionToken.get(tok.id)
|
95
|
+
ta_found.account.should be == @chris
|
96
|
+
ta_found.action.should be == 'act stupid'
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'has an expire date' do
|
100
|
+
Accounts::ActionToken.all.each do |tok|
|
101
|
+
tok.expires.should be_kind_of DateTime
|
102
|
+
tok.expires.should > DateTime.new
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
metadata
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: accounts
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Larry Siden, Westside Consulting LLC
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-02 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: capybara
|
16
|
+
requirement: &83116690 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *83116690
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: cucumber
|
27
|
+
requirement: &83116290 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *83116290
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &83115900 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *83115900
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rdoc
|
49
|
+
requirement: &83115290 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *83115290
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: sinatra-contrib
|
60
|
+
requirement: &83048450 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *83048450
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mail-store-agent
|
71
|
+
requirement: &83047670 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *83047670
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: mail-single_file_delivery
|
82
|
+
requirement: &83043620 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *83043620
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: haml
|
93
|
+
requirement: &83042990 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *83042990
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: rack
|
104
|
+
requirement: &83041620 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.3.6
|
110
|
+
type: :runtime
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *83041620
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: sinatra
|
115
|
+
requirement: &83041110 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :runtime
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *83041110
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: thin
|
126
|
+
requirement: &83028320 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *83028320
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: data_mapper
|
137
|
+
requirement: &83027720 !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
type: :runtime
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: *83027720
|
146
|
+
- !ruby/object:Gem::Dependency
|
147
|
+
name: dm-types
|
148
|
+
requirement: &83027240 !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
type: :runtime
|
155
|
+
prerelease: false
|
156
|
+
version_requirements: *83027240
|
157
|
+
- !ruby/object:Gem::Dependency
|
158
|
+
name: dm-timestamps
|
159
|
+
requirement: &83026620 !ruby/object:Gem::Requirement
|
160
|
+
none: false
|
161
|
+
requirements:
|
162
|
+
- - ! '>='
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
type: :runtime
|
166
|
+
prerelease: false
|
167
|
+
version_requirements: *83026620
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: dm-postgres-adapter
|
170
|
+
requirement: &83026060 !ruby/object:Gem::Requirement
|
171
|
+
none: false
|
172
|
+
requirements:
|
173
|
+
- - ! '>='
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
type: :runtime
|
177
|
+
prerelease: false
|
178
|
+
version_requirements: *83026060
|
179
|
+
- !ruby/object:Gem::Dependency
|
180
|
+
name: mail
|
181
|
+
requirement: &83025360 !ruby/object:Gem::Requirement
|
182
|
+
none: false
|
183
|
+
requirements:
|
184
|
+
- - ! '>='
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
type: :runtime
|
188
|
+
prerelease: false
|
189
|
+
version_requirements: *83025360
|
190
|
+
- !ruby/object:Gem::Dependency
|
191
|
+
name: logger
|
192
|
+
requirement: &83024820 !ruby/object:Gem::Requirement
|
193
|
+
none: false
|
194
|
+
requirements:
|
195
|
+
- - ! '>='
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0'
|
198
|
+
type: :runtime
|
199
|
+
prerelease: false
|
200
|
+
version_requirements: *83024820
|
201
|
+
description: ! "\nAccounts::Server defines the following paths for your web-app:\n\n*
|
202
|
+
POST '/logon'\n* POST '/register'\n* POST '/forgot-password'\n* POST '/change-password'\n*
|
203
|
+
POST '/change-email'\n\nYour app must provide the pages and forms that will post
|
204
|
+
to these paths.\n "
|
205
|
+
email:
|
206
|
+
- lsiden@westside-consulting.com
|
207
|
+
executables: []
|
208
|
+
extensions: []
|
209
|
+
extra_rdoc_files: []
|
210
|
+
files:
|
211
|
+
- .gitignore
|
212
|
+
- .rvmrc
|
213
|
+
- Gemfile
|
214
|
+
- Gemfile.lock
|
215
|
+
- README.mkd
|
216
|
+
- Rakefile
|
217
|
+
- accounts.gemspec
|
218
|
+
- demo/views/change_email.haml
|
219
|
+
- demo/views/change_password.haml
|
220
|
+
- demo/views/forgot_password.haml
|
221
|
+
- demo/views/logon.haml
|
222
|
+
- demo/views/register.haml
|
223
|
+
- demo/web_app.rb
|
224
|
+
- features/change-email.feature
|
225
|
+
- features/change-password.feature
|
226
|
+
- features/register.feature
|
227
|
+
- features/step_definitions/steps.rb
|
228
|
+
- features/step_definitions/web_steps.rb
|
229
|
+
- features/support/env.rb
|
230
|
+
- features/support/paths.rb
|
231
|
+
- features/support/unused.rb
|
232
|
+
- lib/accounts.rb
|
233
|
+
- lib/accounts/configure.rb
|
234
|
+
- lib/accounts/helpers.rb
|
235
|
+
- lib/accounts/model.rb
|
236
|
+
- lib/accounts/version.rb
|
237
|
+
- spec/user_model_spec.rb
|
238
|
+
homepage: https://github.com/lsiden/accounts
|
239
|
+
licenses: []
|
240
|
+
post_install_message:
|
241
|
+
rdoc_options: []
|
242
|
+
require_paths:
|
243
|
+
- lib
|
244
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
245
|
+
none: false
|
246
|
+
requirements:
|
247
|
+
- - ! '>='
|
248
|
+
- !ruby/object:Gem::Version
|
249
|
+
version: '0'
|
250
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
251
|
+
none: false
|
252
|
+
requirements:
|
253
|
+
- - ! '>='
|
254
|
+
- !ruby/object:Gem::Version
|
255
|
+
version: '0'
|
256
|
+
requirements: []
|
257
|
+
rubyforge_project: accounts
|
258
|
+
rubygems_version: 1.8.10
|
259
|
+
signing_key:
|
260
|
+
specification_version: 3
|
261
|
+
summary: ! '*accounts* is a website plug-in that offers than the basic user-account
|
262
|
+
management and authentication features that many sites need.'
|
263
|
+
test_files: []
|