rubynas 0.1.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +23 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +196 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +7 -0
- data/Procfile +2 -0
- data/README.md +151 -0
- data/Rakefile +14 -0
- data/Vagrantfile +99 -0
- data/bin/rubynas +63 -0
- data/config.ru +5 -0
- data/doc/README_FOR_APP +2 -0
- data/doc/macosx_shares.png +0 -0
- data/doc/shares_overview.png +0 -0
- data/lib/rubynas.rb +35 -0
- data/lib/rubynas/apis/group_api.rb +51 -0
- data/lib/rubynas/apis/system_information_api.rb +13 -0
- data/lib/rubynas/apis/user_api.rb +85 -0
- data/lib/rubynas/apis/volume_api.rb +50 -0
- data/lib/rubynas/config.rb +63 -0
- data/lib/rubynas/db/migrate/20130302164415_devise_create_users.rb +46 -0
- data/lib/rubynas/db/migrate/20130322143040_create_volumes.rb +10 -0
- data/lib/rubynas/db/migrate/20130331102556_create_shared_folders.rb +10 -0
- data/lib/rubynas/db/migrate/20130331103034_create_shared_folder_services.rb +11 -0
- data/lib/rubynas/installers/base_installer.rb +70 -0
- data/lib/rubynas/installers/debian_installer.rb +199 -0
- data/lib/rubynas/installers/ubuntu_installer.rb +2 -0
- data/lib/rubynas/installers/ubuntu_precise_installer.rb +2 -0
- data/lib/rubynas/models/.gitkeep +0 -0
- data/lib/rubynas/models/ldap_group.rb +21 -0
- data/lib/rubynas/models/ldap_org_unit.rb +13 -0
- data/lib/rubynas/models/ldap_user.rb +31 -0
- data/lib/rubynas/models/shared_folder.rb +32 -0
- data/lib/rubynas/models/shared_folder_service.rb +15 -0
- data/lib/rubynas/models/volume.rb +16 -0
- data/lib/rubynas/services/afp_share_service.rb +9 -0
- data/lib/rubynas/services/service.rb +4 -0
- data/lib/rubynas/services/share_service.rb +3 -0
- data/lib/rubynas/version.rb +3 -0
- data/rubynas.gemspec +69 -0
- data/rubynas.ini +24 -0
- data/sandbox/ldap/base.ldif +50 -0
- data/sandbox/ldap/data/.gitkeep +0 -0
- data/sandbox/ldap/data/dc=rubynas,dc=com.ldif +14 -0
- data/sandbox/ldap/local.schema +6 -0
- data/sandbox/ldap/schema/README +80 -0
- data/sandbox/ldap/schema/apple.schema +1727 -0
- data/sandbox/ldap/schema/apple_auxillary.schema +20 -0
- data/sandbox/ldap/schema/collective.ldif +48 -0
- data/sandbox/ldap/schema/collective.schema +190 -0
- data/sandbox/ldap/schema/corba.ldif +42 -0
- data/sandbox/ldap/schema/corba.schema +239 -0
- data/sandbox/ldap/schema/core.ldif +591 -0
- data/sandbox/ldap/schema/core.schema +610 -0
- data/sandbox/ldap/schema/cosine.ldif +200 -0
- data/sandbox/ldap/schema/cosine.schema +2571 -0
- data/sandbox/ldap/schema/duaconf.ldif +83 -0
- data/sandbox/ldap/schema/duaconf.schema +261 -0
- data/sandbox/ldap/schema/dyngroup.ldif +71 -0
- data/sandbox/ldap/schema/dyngroup.schema +91 -0
- data/sandbox/ldap/schema/fmserver.schema +60 -0
- data/sandbox/ldap/schema/inetorgperson.ldif +69 -0
- data/sandbox/ldap/schema/inetorgperson.schema +155 -0
- data/sandbox/ldap/schema/java.ldif +59 -0
- data/sandbox/ldap/schema/java.schema +403 -0
- data/sandbox/ldap/schema/krb5-kdc.schema +134 -0
- data/sandbox/ldap/schema/microsoft.ext.schema +5383 -0
- data/sandbox/ldap/schema/microsoft.schema +4835 -0
- data/sandbox/ldap/schema/microsoft.std.schema +480 -0
- data/sandbox/ldap/schema/misc.ldif +45 -0
- data/sandbox/ldap/schema/misc.schema +75 -0
- data/sandbox/ldap/schema/netinfo.schema +240 -0
- data/sandbox/ldap/schema/nis.ldif +120 -0
- data/sandbox/ldap/schema/nis.schema +241 -0
- data/sandbox/ldap/schema/openldap.ldif +88 -0
- data/sandbox/ldap/schema/openldap.schema +54 -0
- data/sandbox/ldap/schema/pmi.ldif +123 -0
- data/sandbox/ldap/schema/pmi.schema +464 -0
- data/sandbox/ldap/schema/ppolicy.ldif +75 -0
- data/sandbox/ldap/schema/ppolicy.schema +531 -0
- data/sandbox/ldap/schema/samba.schema +179 -0
- data/sandbox/ldap/slapd.conf +99 -0
- data/spec/apis/group_api_spec.rb +97 -0
- data/spec/apis/system_information_api_spec.rb +27 -0
- data/spec/apis/user_api_spec.rb +113 -0
- data/spec/apis/volume_api_spec.rb +98 -0
- data/spec/factories/ldap_group.rb +16 -0
- data/spec/factories/ldap_users.rb +24 -0
- data/spec/factories/shared_folder_services.rb +9 -0
- data/spec/factories/shared_folders.rb +15 -0
- data/spec/factories/users.rb +8 -0
- data/spec/factories/volumes.rb +10 -0
- data/spec/installer/base_installer_spec.rb +35 -0
- data/spec/installer/debian_installer_spec.rb +86 -0
- data/spec/models/ldap_group_spec.rb +21 -0
- data/spec/models/ldap_org_unit_spec.rb +19 -0
- data/spec/models/ldap_user_spec.rb +19 -0
- data/spec/models/shared_folder_service_spec.rb +25 -0
- data/spec/models/shared_folder_spec.rb +27 -0
- data/spec/models/volume_spec.rb +5 -0
- data/spec/services/afp_share_service_spec.rb +5 -0
- data/spec/services/service_spec.rb +5 -0
- data/spec/services/share_service_spec.rb +5 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/db_cleaner.rb +16 -0
- data/spec/support/factory_girl.rb +7 -0
- data/spec/support/logger.rb +1 -0
- data/spec/support/rack-test.rb +6 -0
- metadata +633 -0
data/bin/rubynas
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
4
|
+
require 'rubynas'
|
5
|
+
require 'rubynas/version'
|
6
|
+
|
7
|
+
case ARGV.first
|
8
|
+
when 'migrate'
|
9
|
+
puts 'Migration of the database'
|
10
|
+
path = File.expand_path('../../lib/rubynas/db/migrate', __FILE__)
|
11
|
+
ActiveRecord::Migrator.migrate path
|
12
|
+
|
13
|
+
# In the production environment should the root volume always be available
|
14
|
+
unless Volume.find_by_name_and_path("System Volume", "/")
|
15
|
+
Volume.create(name: "System Volume", path: "/")
|
16
|
+
end
|
17
|
+
|
18
|
+
# Setup default account and structure if they don't exist in the repository
|
19
|
+
LdapOrgUnit.find_or_create('users')
|
20
|
+
LdapOrgUnit.find_or_create('groups')
|
21
|
+
LdapUser.find_or_create_admin
|
22
|
+
LdapGroup.find_or_create_administrators
|
23
|
+
when 'server'
|
24
|
+
require 'rack'
|
25
|
+
require 'puma'
|
26
|
+
require 'rack/handler/puma'
|
27
|
+
require 'dnssd'
|
28
|
+
require 'rubynas/version'
|
29
|
+
$0 = 'rubynas'
|
30
|
+
|
31
|
+
options = {
|
32
|
+
:Host => '0.0.0.0',
|
33
|
+
:Port => (ENV['PORT'] || 5100).to_i,
|
34
|
+
:Threads => '0:16',
|
35
|
+
:Verbose => false
|
36
|
+
}
|
37
|
+
|
38
|
+
text_record = DNSSD::TextRecord.new 'Version' => Rubynas::VERSION,
|
39
|
+
'Path' => '/api'
|
40
|
+
name = 'rubynas'
|
41
|
+
type = '_rubynas._tcp'
|
42
|
+
domain = host = nil
|
43
|
+
port = options[:Port]
|
44
|
+
DNSSD.register name, type, domain, port, text_record
|
45
|
+
|
46
|
+
Rack::Handler::Puma.run(Rubynas::Application, options) do |server|
|
47
|
+
[:INT, :TERM].each { |sig| trap(sig) { server.stop } }
|
48
|
+
end
|
49
|
+
when 'install'
|
50
|
+
if File.exist?('/etc/lsb-release')
|
51
|
+
data = Hash[File.read('/etc/lsb-release').lines.map do |line|
|
52
|
+
line.chomp.split("=")
|
53
|
+
end]
|
54
|
+
klass_name = data['DISTRIB_ID'].capitalize
|
55
|
+
klass_name << data['DISTRIB_CODENAME'].capitalize
|
56
|
+
klass_name << "Installer"
|
57
|
+
Kernel.const_get(klass_name).new('rubynas.com', 'admin', 'secret').run
|
58
|
+
else
|
59
|
+
puts "System unknown! Can't install"
|
60
|
+
end
|
61
|
+
else
|
62
|
+
puts "usage: #{$0} <migrate|server|install>"
|
63
|
+
end
|
data/config.ru
ADDED
data/doc/README_FOR_APP
ADDED
Binary file
|
Binary file
|
data/lib/rubynas.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'inifile'
|
3
|
+
require 'active_ldap'
|
4
|
+
require 'active_record'
|
5
|
+
require 'active_record/errors'
|
6
|
+
require 'lumberjack'
|
7
|
+
require 'lumberjack_syslog_device'
|
8
|
+
require 'netatalk-config'
|
9
|
+
require 'grape'
|
10
|
+
require 'grape-entity'
|
11
|
+
require 'active_support'
|
12
|
+
require 'active_support/dependencies'
|
13
|
+
require 'vmstat'
|
14
|
+
|
15
|
+
%w(apis models services installers).each do |dir|
|
16
|
+
path = File.expand_path("../rubynas/#{dir}", __FILE__)
|
17
|
+
ActiveSupport::Dependencies.autoload_paths.unshift(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
module Rubynas
|
21
|
+
class <<self
|
22
|
+
attr_accessor :logger
|
23
|
+
end
|
24
|
+
|
25
|
+
Application = Rack::Builder.new do
|
26
|
+
map "/api" do
|
27
|
+
map("/users") { run ::UserApi }
|
28
|
+
map("/groups") { run ::GroupApi }
|
29
|
+
map("/volumes") { run ::VolumeApi }
|
30
|
+
map("/system") { run ::SystemInformationApi }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rubynas/config'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class GroupApi < Grape::API
|
2
|
+
format :json
|
3
|
+
|
4
|
+
rescue_from ActiveLdap::EntryNotFound do |e|
|
5
|
+
Rack::Response.new([e.inspect], 404)
|
6
|
+
end
|
7
|
+
|
8
|
+
class Group < Grape::Entity
|
9
|
+
expose :common_name, documentation: { type: String, desc: 'Group name' }
|
10
|
+
expose :gid_number,
|
11
|
+
documentation: { type: Integer, desc: 'ID of the group' }
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'Returns the list of groups in the ldap', {
|
15
|
+
:object_fields => GroupApi::Group.documentation
|
16
|
+
}
|
17
|
+
get '/' do
|
18
|
+
present LdapGroup.all, with: GroupApi::Group
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Return a single group'
|
22
|
+
get '/:cn' do
|
23
|
+
present LdapGroup.find(params[:cn]), with: GroupApi::Group
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Delete the passed group'
|
27
|
+
delete '/:cn' do
|
28
|
+
LdapGroup.find(params.delete(:cn)).destroy
|
29
|
+
''
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Add a new group'
|
33
|
+
params do
|
34
|
+
requires :common_name, type: String
|
35
|
+
requires :gid_number, type: Fixnum
|
36
|
+
end
|
37
|
+
post '/' do
|
38
|
+
LdapGroup.create(params)
|
39
|
+
''
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'Update a group completely'
|
43
|
+
params do
|
44
|
+
requires :common_name, type: String
|
45
|
+
requires :gid_number, type: Fixnum
|
46
|
+
end
|
47
|
+
put '/:cn' do
|
48
|
+
LdapGroup.find(params.delete(:cn)).update_attributes(params)
|
49
|
+
''
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class SystemInformationApi < Grape::API
|
2
|
+
format :json
|
3
|
+
|
4
|
+
desc 'resturns vmstat data'
|
5
|
+
get '/vmstat' do
|
6
|
+
present Vmstat.snapshot
|
7
|
+
end
|
8
|
+
|
9
|
+
desc 'returns disk related information'
|
10
|
+
get '/disk' do
|
11
|
+
present Vmstat.disk('/' + params[:path].to_s)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class UserApi < Grape::API
|
2
|
+
format :json
|
3
|
+
|
4
|
+
rescue_from ActiveLdap::EntryNotFound do |error|
|
5
|
+
Rack::Response.new({
|
6
|
+
'status' => 404,
|
7
|
+
'message' => error.message
|
8
|
+
}.to_json, 404)
|
9
|
+
end
|
10
|
+
|
11
|
+
class User < Grape::Entity
|
12
|
+
expose :common_name, documentation: { type: String, desc: 'Full name' }
|
13
|
+
expose :given_name, documentation: { type: String, desc: 'Firstname' }
|
14
|
+
expose :surname, documentation: { type: String, desc: 'Lastname' }
|
15
|
+
expose :uid, documentation: { type: String, desc: 'Login name' }
|
16
|
+
expose :home_directory,
|
17
|
+
documentation: { type: String, desc: 'Path to the user home' }
|
18
|
+
expose :gid_number,
|
19
|
+
documentation: { type: Integer, desc: 'ID of the group' }
|
20
|
+
expose :uid_number, documentation: { type: Integer, desc: 'ID of the user' }
|
21
|
+
expose :mail, documentation: { type: String, desc: 'E-Mail address' }
|
22
|
+
expose :login_shell, documentation: { type: String, desc: 'The shell used for ssh login' }
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Returns the list of users in the ldap', {
|
26
|
+
:object_fields => UserApi::User.documentation
|
27
|
+
}
|
28
|
+
get '/' do
|
29
|
+
present LdapUser.all, with: UserApi::User
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Returns a template for new users', {
|
33
|
+
:object_fields => UserApi::User.documentation
|
34
|
+
}
|
35
|
+
get '/template' do
|
36
|
+
next_uid_number = LdapUser.all.map(&:uid_number).max.to_i + 1
|
37
|
+
next_uid_number = 1000 if next_uid_number < 1000
|
38
|
+
{ uid_number: next_uid_number,
|
39
|
+
gid_number: 1000,
|
40
|
+
home_directory: '/home/' }
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Adds new user to the ldap'
|
44
|
+
params do
|
45
|
+
requires :common_name
|
46
|
+
requires :given_name
|
47
|
+
requires :surname
|
48
|
+
requires :uid
|
49
|
+
requires :home_directory
|
50
|
+
requires :gid_number
|
51
|
+
requires :uid_number
|
52
|
+
requires :password
|
53
|
+
requires :mail
|
54
|
+
requires :login_shell
|
55
|
+
end
|
56
|
+
post '/' do
|
57
|
+
password = ActiveLdap::UserPassword.sha(params.delete(:password))
|
58
|
+
user = LdapUser.create(params.merge(:userPassword => password))
|
59
|
+
present user, with: UserAPI::User
|
60
|
+
end
|
61
|
+
|
62
|
+
desc 'Request single user', {
|
63
|
+
:object_fields => UserApi::User.documentation
|
64
|
+
}
|
65
|
+
get '/:cn' do
|
66
|
+
present LdapUser.find(params[:cn]), with: UserApi::User
|
67
|
+
end
|
68
|
+
|
69
|
+
desc 'Update the user data in the ldap'
|
70
|
+
put '/:cn' do
|
71
|
+
user = LdapUser.find(params.delete(:cn))
|
72
|
+
if params[:password]
|
73
|
+
password = ActiveLdap::UserPassword.sha(params.delete(:password))
|
74
|
+
params.merge!(:userPassword => password)
|
75
|
+
end
|
76
|
+
user.update_attributes(params)
|
77
|
+
present user, with: UserAPI::User
|
78
|
+
end
|
79
|
+
|
80
|
+
desc 'Delete user'
|
81
|
+
delete '/:cn' do
|
82
|
+
LdapUser.find(params.delete(:cn)).destroy
|
83
|
+
Rack::Response.new([], 204)
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class VolumeApi < Grape::API
|
2
|
+
format :json
|
3
|
+
|
4
|
+
rescue_from ActiveRecord::RecordNotFound do |e|
|
5
|
+
Rack::Response.new([e.inspect], 404)
|
6
|
+
end
|
7
|
+
|
8
|
+
class Volume < Grape::Entity
|
9
|
+
expose :id, documentation: { type: String, desc: 'volume unique id' }
|
10
|
+
expose :name, documentation: { type: String, desc: 'name of the volume' }
|
11
|
+
expose :path, documentation: { type: String, desc: 'path of the volume' }
|
12
|
+
expose :capacity, documentation: { type: String, desc: 'capacity in bytes' }
|
13
|
+
expose :usage, documentation: { type: Float, desc: 'usage in percent' }
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Returns the list of volumes', {
|
17
|
+
:object_fields => ::VolumeApi::Volume.documentation
|
18
|
+
}
|
19
|
+
get '/' do
|
20
|
+
present ::Volume.all, with: ::VolumeApi::Volume
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Return the requested volume', {
|
24
|
+
:object_fields => ::VolumeApi::Volume.documentation
|
25
|
+
}
|
26
|
+
params do
|
27
|
+
requires :id, type: Fixnum
|
28
|
+
end
|
29
|
+
get '/:id' do
|
30
|
+
present ::Volume.find(params[:id]), with: ::VolumeApi::Volume
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Update the volume with the passed id'
|
34
|
+
put '/:id' do
|
35
|
+
data = { name: params[:name], path: params[:path] }
|
36
|
+
::Volume.find(params.delete(:id)).update_attributes!(data)
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'Create new volume', {
|
40
|
+
:object_fields => ::VolumeApi::Volume.documentation
|
41
|
+
}
|
42
|
+
post '/' do
|
43
|
+
::Volume.create name: params[:name], path: params[:path]
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'Delete a volume'
|
47
|
+
delete '/:id' do
|
48
|
+
::Volume.find(params.delete(:id)).destroy
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Rubynas
|
2
|
+
class Config
|
3
|
+
# @param [String] path the path to the configuration
|
4
|
+
def self.use(path)
|
5
|
+
new(path).configure
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(path)
|
9
|
+
@path = path
|
10
|
+
@ini = IniFile.load(path, :encoding => 'utf-8')
|
11
|
+
end
|
12
|
+
|
13
|
+
def configure
|
14
|
+
configure_logger
|
15
|
+
configure_active_ldap
|
16
|
+
configure_active_record
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure_logger
|
20
|
+
section = @ini['Server']
|
21
|
+
if section['syslog'] == 'true'
|
22
|
+
facility = Syslog::LOG_LOCAL0 | Syslog::LOG_CONS
|
23
|
+
device = Lumberjack::SyslogDevice.new facility: facility
|
24
|
+
Rubynas.logger = Lumberjack::Logger.new device, progname: "rubynas"
|
25
|
+
else
|
26
|
+
Rubynas.logger = Logger.new(STDOUT)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def configure_active_record
|
31
|
+
section = @ini['Database']
|
32
|
+
ActiveRecord::Base.establish_connection(
|
33
|
+
:adapter => 'sqlite3',
|
34
|
+
:database => section['path'],
|
35
|
+
:timeout => (section['timeout'] || 5000).to_i,
|
36
|
+
:pool => (section['pool'] || 5).to_i
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def configure_active_ldap
|
41
|
+
section = @ini['Ldap']
|
42
|
+
ActiveLdap::Base.setup_connection(
|
43
|
+
:host => section['host'],
|
44
|
+
:port => section['port'],
|
45
|
+
:base => section['base'],
|
46
|
+
:logger => Rubynas.logger,
|
47
|
+
:bind_dn => section['bind_dn'],
|
48
|
+
:password_block => Proc.new { section['password'] },
|
49
|
+
:allow_anonymous => false,
|
50
|
+
:try_sasl => false
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Regular usage
|
57
|
+
if File.exist?('/etc/rubynas.ini')
|
58
|
+
Rubynas::Config.use('/etc/rubynas.ini')
|
59
|
+
|
60
|
+
# Local testing usage
|
61
|
+
elsif File.exist?('rubynas.ini')
|
62
|
+
Rubynas::Config.use('rubynas.ini')
|
63
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class DeviseCreateUsers < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table(:users) do |t|
|
4
|
+
## Database authenticatable
|
5
|
+
t.string :email, :null => false, :default => ""
|
6
|
+
t.string :encrypted_password, :null => false, :default => ""
|
7
|
+
|
8
|
+
## Recoverable
|
9
|
+
t.string :reset_password_token
|
10
|
+
t.datetime :reset_password_sent_at
|
11
|
+
|
12
|
+
## Rememberable
|
13
|
+
t.datetime :remember_created_at
|
14
|
+
|
15
|
+
## Trackable
|
16
|
+
t.integer :sign_in_count, :default => 0
|
17
|
+
t.datetime :current_sign_in_at
|
18
|
+
t.datetime :last_sign_in_at
|
19
|
+
t.string :current_sign_in_ip
|
20
|
+
t.string :last_sign_in_ip
|
21
|
+
|
22
|
+
## Confirmable
|
23
|
+
# t.string :confirmation_token
|
24
|
+
# t.datetime :confirmed_at
|
25
|
+
# t.datetime :confirmation_sent_at
|
26
|
+
# t.string :unconfirmed_email # Only if using reconfirmable
|
27
|
+
|
28
|
+
## Lockable
|
29
|
+
# t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
|
30
|
+
# t.string :unlock_token # Only if unlock strategy is :email or :both
|
31
|
+
# t.datetime :locked_at
|
32
|
+
|
33
|
+
## Token authenticatable
|
34
|
+
# t.string :authentication_token
|
35
|
+
|
36
|
+
|
37
|
+
t.timestamps
|
38
|
+
end
|
39
|
+
|
40
|
+
add_index :users, :email, :unique => true
|
41
|
+
add_index :users, :reset_password_token, :unique => true
|
42
|
+
# add_index :users, :confirmation_token, :unique => true
|
43
|
+
# add_index :users, :unlock_token, :unique => true
|
44
|
+
# add_index :users, :authentication_token, :unique => true
|
45
|
+
end
|
46
|
+
end
|