anadea-identity 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +174 -0
- data/Rakefile +10 -0
- data/app/assets/images/facebook.png +0 -0
- data/app/assets/images/google_oauth2.png +0 -0
- data/app/assets/images/twitter.png +0 -0
- data/app/controllers/identity/base_controller.rb +5 -0
- data/app/controllers/identity/omniauth_callbacks_controller.rb +24 -0
- data/app/controllers/identity/users_controller.rb +58 -0
- data/app/models/identity/role.rb +16 -0
- data/app/models/identity/user.rb +47 -0
- data/app/views/devise/confirmations/new.html.erb +23 -0
- data/app/views/devise/mailer/confirmation_instructions.html.erb +6 -0
- data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
- data/app/views/devise/passwords/edit.html.erb +28 -0
- data/app/views/devise/passwords/new.html.erb +21 -0
- data/app/views/devise/registrations/edit.html.erb +34 -0
- data/app/views/devise/registrations/new.html.erb +28 -0
- data/app/views/devise/sessions/new.html.erb +31 -0
- data/app/views/devise/shared/_links.erb +25 -0
- data/app/views/devise/unlocks/new.html.erb +20 -0
- data/app/views/identity/users/edit.html.erb +70 -0
- data/app/views/identity/users/index.html.erb +55 -0
- data/config/locales/ca.yml +59 -0
- data/config/locales/de.yml +110 -0
- data/config/locales/en.yml +111 -0
- data/config/locales/es-AR.yml +51 -0
- data/config/locales/es-ES.yml +59 -0
- data/config/locales/es.yml +51 -0
- data/config/locales/fr.yml +51 -0
- data/config/locales/hu.yml +59 -0
- data/config/locales/it.yml +51 -0
- data/config/locales/nl.yml +59 -0
- data/config/locales/pl.yml +57 -0
- data/config/locales/pt-BR.yml +51 -0
- data/config/locales/ru.yml +56 -0
- data/config/locales/tr.yml +51 -0
- data/config/locales/zh-CN.yml +57 -0
- data/config/locales/zh-TW.yml +57 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20150402142437_devise_create_identity_users.rb +42 -0
- data/db/migrate/20150402152859_rolify_create_identity_roles.rb +19 -0
- data/lib/anadea/identity.rb +1 -0
- data/lib/generators/identity/locales_generator.rb +8 -0
- data/lib/generators/identity/views_generator.rb +8 -0
- data/lib/identity.rb +50 -0
- data/lib/identity/admin/user.rb +89 -0
- data/lib/identity/devise_config.rb +31 -0
- data/lib/identity/engine.rb +21 -0
- data/lib/identity/version.rb +3 -0
- data/lib/identity/view_helper.rb +22 -0
- data/lib/tasks/whoami_tasks.rake +4 -0
- metadata +157 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b90fe456fe3459656452c7191052e3cf7b9e72bd
|
4
|
+
data.tar.gz: 7942ef52f965589850dc1e2d9b1be489aaf96fac
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 351d14c0435915e9e1324bbca2b9e53dbcda6764044e16b8138de4d24e2ca44bbf7525e343623104243ab18a0145b38028e2d62a0cd27a7718373bd413f46b8a
|
7
|
+
data.tar.gz: d072c2f56d804f4174305d38f4bc1bb3a412359b66a0d739e92742bd7f1a917a8f9d392e7d4c9c190eaa501c74cd81d60f3ed3ceeffe61e19571795de94ca112
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2015 Anadea
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
# Identity
|
2
|
+
|
3
|
+
Аутентификация и авторизация для Rails приложения.
|
4
|
+
|
5
|
+
## Установка
|
6
|
+
|
7
|
+
Добавьте строчку в Gemfile приложения:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'anadea-identity'
|
11
|
+
```
|
12
|
+
|
13
|
+
и запустите в консоли:
|
14
|
+
|
15
|
+
```console
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Сгенерируйте миграции:
|
20
|
+
|
21
|
+
```console
|
22
|
+
$ rake identity_engine:install:migrations
|
23
|
+
```
|
24
|
+
|
25
|
+
проверьте их и запустите:
|
26
|
+
|
27
|
+
```console
|
28
|
+
$ rake db:migrate
|
29
|
+
```
|
30
|
+
|
31
|
+
## Использование
|
32
|
+
|
33
|
+
### Аутентификация
|
34
|
+
|
35
|
+
Проверьте маршруты: `rake routes`. Вы увидите набор маршрутов, подобных тем, что
|
36
|
+
даёт [Devise](https://github.com/plataformatec/devise). Собственно, Identity и
|
37
|
+
есть не слишком толстая обёртка поверх Devise.
|
38
|
+
|
39
|
+
У вас работает логин (через форму email/пароль), регистрация (через форму
|
40
|
+
email/пароль/подтверждение пароля), восстановление пароля и многое другое.
|
41
|
+
|
42
|
+
### Модель User
|
43
|
+
|
44
|
+
Вызов `current_user` в контроллере вернёт `Identity::User`, соответствующий
|
45
|
+
таблице `identity_users`. Не нужно добавлять в эту модель методы и не нужно
|
46
|
+
добавлять в эту таблицу колонки, кроме тех, которые используются Devise или
|
47
|
+
Identity. Эту модель следует считать публичным интерфейсом, предоставляеым гемом.
|
48
|
+
|
49
|
+
Рекомендуется заводить модели типа `Profile` или `Account` которые будут
|
50
|
+
"принадлежать" (`belong_to :user, class_name: "Identity::User"`) этой модели
|
51
|
+
и ссылаться на неё с помощью внешнего ключа.
|
52
|
+
|
53
|
+
### Авторизация
|
54
|
+
|
55
|
+
Модель `Identity::User` расширена ролями с помощью
|
56
|
+
[Rolify](https://github.com/RolifyCommunity/rolify). В частности, у вас есть
|
57
|
+
говорящие за себя методы:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
user.add_role :manager
|
61
|
+
user.remove_role :manager
|
62
|
+
user.has_role? :manager
|
63
|
+
|
64
|
+
Identity::User.with_role :manager
|
65
|
+
```
|
66
|
+
|
67
|
+
У вас есть многое другое – смотрите документацию Rolify.
|
68
|
+
|
69
|
+
Используйте эти методы в вызовах вашего авторизационного фреймворка, такого, как
|
70
|
+
[CanCanCan](https://github.com/CanCanCommunity/cancancan).
|
71
|
+
|
72
|
+
### Админка
|
73
|
+
|
74
|
+
Чтобы получить админку по пользователям, подключите
|
75
|
+
[ActiveAdmin](https://github.com/activeadmin/activeadmin) и сгенерируйте
|
76
|
+
конфигурационный файл без генерации пользователей (`--skip-users`).
|
77
|
+
|
78
|
+
### Конфигурация
|
79
|
+
|
80
|
+
Создайте руби-файл в `config/initializers` со следующим содержимым:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
Identity.setup do |config|
|
84
|
+
config.devise_modules += [:confirmable]
|
85
|
+
# и много других конфигурационных опций
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
#### Доступные опции
|
90
|
+
|
91
|
+
Вы всегда можете узнать полный список конфигурацинных опций и их значения по
|
92
|
+
умолчанию, ознакомившись [с исходным кодом](lib/identity.rb).
|
93
|
+
|
94
|
+
* `config.devise_modules` – модули Devise, которые вы используете. Например,
|
95
|
+
выключение `registerable` приведёт к невозможности зарегистрироваться, в том
|
96
|
+
числе, исчезнет соответствующая ссылка, а включение `confirmable` приведёт к
|
97
|
+
тому, что приложение станет требовать подтверждение адреса электронной почты,
|
98
|
+
при условии, что в таблице `identity_users` есть соответствующие колонки
|
99
|
+
(по умолчанию нет).
|
100
|
+
|
101
|
+
Вы можете как модифицировать этот массив, так и полностью его переопределить:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
config.devise_modules += [:confirmable]
|
105
|
+
config.devise_modules = [:database_authenticatable, :omniauthable, ...]
|
106
|
+
```
|
107
|
+
|
108
|
+
По умолчанию включены модули database_authenticatable, registerable,
|
109
|
+
recoverable, rememberable, trackable и validatable. Если включить хотя бы один
|
110
|
+
omniauth provider, автоматически подключится omniauthable. За подробным их
|
111
|
+
описанием обратитесь в документацию Devise.
|
112
|
+
|
113
|
+
* `config.layout` – макет (layout), используемый формами логина, регистрации и
|
114
|
+
прочего. По умолчанию используется главный макет вашего приложения –
|
115
|
+
`"application"`.
|
116
|
+
|
117
|
+
* `config.auth_routes` – если задать `false`, маршруты подключены не будут и вы
|
118
|
+
можете сами подключить их.
|
119
|
+
|
120
|
+
* `config.admin_role` – "главная" роль в приложении. Роль, которой можно
|
121
|
+
управлять из предлаемой гемом админки, и роль, которая по умолчанию является
|
122
|
+
допуском в эту админку.
|
123
|
+
|
124
|
+
Вы также можете использовать любые конфигурационные опции самого Devise.
|
125
|
+
Они будут переданы Devise в точности. Например:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
config.parent_controller = "ApplicationController"
|
129
|
+
```
|
130
|
+
|
131
|
+
За подробным списком того, что можно сконфигурировать в Devise, обратитесь к его
|
132
|
+
документации.
|
133
|
+
|
134
|
+
#### Сделанные кастомизации в конфигурации Devise.
|
135
|
+
|
136
|
+
Мы делаем небольшие изменения в конфигурации Devise по умолчанию. Вы можете это
|
137
|
+
увидеть в [исходном коде гема](lib/identity/devise_config.rb).
|
138
|
+
|
139
|
+
* `config.mailer_sender` – мы достаём это из переменной окружения MAIL_FROM.
|
140
|
+
* `config.sign_out_via` – GET и только GET. Это должно работать без джаваскрипта.
|
141
|
+
* `config.parent_controller` – мы не наследуемся от `ApplicationController` вашего
|
142
|
+
приложения. Devise предлагает для этого определять методы в
|
143
|
+
`ApplicationController`.Если вам нужно переопределить поведение аутентификационных
|
144
|
+
контроллеров, мы рекомендуем создать специальный базовый контроллер в
|
145
|
+
приложении и указать его в качестве `parent_controller`. Затем определять в
|
146
|
+
нём методы типа `after_sign_in_path_for`, как и предлагает Devise.
|
147
|
+
|
148
|
+
### Логин через Facebook.
|
149
|
+
|
150
|
+
Для того, чтобы включить в приложении логин через Facebook нужно:
|
151
|
+
|
152
|
+
* подключить `gem 'omniauth-facebook'` в своем Gemfile.
|
153
|
+
* указать `config.omniauth :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']`
|
154
|
+
в `config/initializers/identity.rb`.
|
155
|
+
* создать приложение в Facebook можно с помощью [инструкции](https://getsocio.com/Help/How_to_set_up_Facebook_Application).
|
156
|
+
|
157
|
+
### Логин через Twitter.
|
158
|
+
|
159
|
+
Для того, чтобы включить в приложении логин через Twitter нужно:
|
160
|
+
|
161
|
+
* подключить `gem 'omniauth-twitter'` в своем Gemfile.
|
162
|
+
* указать `config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']`
|
163
|
+
в `config/initializers/identity.rb`.
|
164
|
+
* создать приложение в Twitter можно [здесь](https://apps.twitter.com/).
|
165
|
+
|
166
|
+
### Логин через Google.
|
167
|
+
|
168
|
+
Для того, чтобы включить в приложении логин через Google нужно:
|
169
|
+
|
170
|
+
* подключить `gem 'omniauth-google-oauth2'` в своем Gemfile.
|
171
|
+
* указать `config.omniauth :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET']`
|
172
|
+
в `config/initializers/identity.rb`.
|
173
|
+
* создать приложение в Google можно [здесь](https://console.developers.google.com/project).
|
174
|
+
* для создания приложения можно воспользоваться [инструкцией](https://developers.google.com/identity/protocols/OpenIDConnect#appsetup)
|
data/Rakefile
ADDED
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Identity
|
2
|
+
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
3
|
+
def facebook
|
4
|
+
omniauth_login('Facebook')
|
5
|
+
end
|
6
|
+
|
7
|
+
def twitter
|
8
|
+
omniauth_login('Twitter')
|
9
|
+
end
|
10
|
+
|
11
|
+
def google_oauth2
|
12
|
+
omniauth_login('Google')
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def omniauth_login(title)
|
18
|
+
@user = Identity::User.from_omniauth!(request.env["omniauth.auth"])
|
19
|
+
|
20
|
+
set_flash_message(:notice, :success, :kind => title) if is_navigational_format?
|
21
|
+
sign_in_and_redirect @user, :event => :authentication
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Identity
|
2
|
+
class UsersController < ActionController::Base
|
3
|
+
layout Identity.admin_layout
|
4
|
+
before_action :ensure_allowed!
|
5
|
+
helper_method :resource, :resources
|
6
|
+
|
7
|
+
def index
|
8
|
+
@resources = User.search_and_order(params[:search], params[:page])
|
9
|
+
end
|
10
|
+
|
11
|
+
def show
|
12
|
+
redirect_to edit_identity_user_path(params[:id])
|
13
|
+
end
|
14
|
+
|
15
|
+
def edit
|
16
|
+
@resource = find_user
|
17
|
+
end
|
18
|
+
|
19
|
+
def update
|
20
|
+
@resource = find_user
|
21
|
+
if @resource.admin_update(user_params, current?(@resource))
|
22
|
+
@resource.skip_reconfirmation! if @resource.respond_to?(:skip_reconfirmation!)
|
23
|
+
@resource.save
|
24
|
+
redirect_to [Identity.admin_namespace, :users], notice: "#{@resource.email} updated."
|
25
|
+
else
|
26
|
+
render :edit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :resource, :resources
|
33
|
+
|
34
|
+
def ensure_allowed!
|
35
|
+
unless Identity.admin_guard[current_user, self]
|
36
|
+
raise ActionController::RoutingError.new('Nothing here, move around')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def devise_mapping
|
41
|
+
request.env["devise.mapping"]
|
42
|
+
end
|
43
|
+
|
44
|
+
def current?(user)
|
45
|
+
user.id == current_user.id
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_user
|
49
|
+
User.find params[:id]
|
50
|
+
end
|
51
|
+
|
52
|
+
def user_params
|
53
|
+
params.require(:identity_user).permit(
|
54
|
+
:email, :password, :password_confirmation, :active, Identity.admin_role
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "rolify"
|
2
|
+
|
3
|
+
module Identity
|
4
|
+
class Role < ActiveRecord::Base
|
5
|
+
self.table_name = 'identity_roles'
|
6
|
+
|
7
|
+
has_and_belongs_to_many :users, :join_table => :identity_users_identity_roles
|
8
|
+
belongs_to :resource, :polymorphic => true
|
9
|
+
|
10
|
+
validates :resource_type,
|
11
|
+
:inclusion => { :in => Rolify.resource_types },
|
12
|
+
:allow_nil => true
|
13
|
+
|
14
|
+
scopify
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "devise"
|
2
|
+
require "rolify"
|
3
|
+
require "kaminari"
|
4
|
+
|
5
|
+
module Identity
|
6
|
+
class User < ActiveRecord::Base
|
7
|
+
self.table_name = 'identity_users'
|
8
|
+
devise *Identity.devise_modules
|
9
|
+
|
10
|
+
if Devise.omniauth_providers.any?
|
11
|
+
devise :omniauthable, omniauth_providers: Devise.omniauth_providers
|
12
|
+
end
|
13
|
+
|
14
|
+
rolify role_cname: 'Identity::Role'
|
15
|
+
|
16
|
+
def self.from_omniauth!(auth)
|
17
|
+
where(provider: auth.provider, uid: auth.uid).first_or_create! do |user|
|
18
|
+
user.email = auth.provider == "twitter" ? "#{auth.info.nickname}_email@example.com" : auth.info.email
|
19
|
+
user.password = Devise.friendly_token[0,20]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
define_singleton_method Identity.admins_method do
|
24
|
+
with_role(Identity.admin_role)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.find_first_by_auth_conditions(tainted_conditions, opts={active: true})
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.active
|
32
|
+
result = where(active: true)
|
33
|
+
result = result.where.not(confirmed_at: nil) if devise_modules.include?(:confirmable)
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
def role_names
|
38
|
+
roles.pluck(:name).sort.join(', ')
|
39
|
+
end
|
40
|
+
|
41
|
+
define_method Identity.admin_role do
|
42
|
+
has_role?(Identity.admin_role)
|
43
|
+
end
|
44
|
+
alias_method Identity.admin_predicate, Identity.admin_role
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<div class="row">
|
2
|
+
<div class="col-sm-6">
|
3
|
+
|
4
|
+
<%= bootstrap_devise_error_messages! %>
|
5
|
+
<div class="panel panel-default">
|
6
|
+
<div class="panel-heading">
|
7
|
+
<h4><%= t('.resend_confirmation_instructions', :default => 'Resend confirmation instructions') %></h4>
|
8
|
+
</div>
|
9
|
+
<div class="panel-body">
|
10
|
+
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post, role: "form" }) do |f| %>
|
11
|
+
<div class="form-group">
|
12
|
+
<%= f.label :email %>
|
13
|
+
<%= f.email_field :email, autofocus: true, class: "form-control" %>
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<%= f.submit t('.resend_confirmation_instructions', :default => 'Resend confirmation instructions'), class: "btn btn-primary" %>
|
17
|
+
<% end %>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<%= render "devise/shared/links" %>
|
22
|
+
</div>
|
23
|
+
</div>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<p><%= t('.greeting', :recipient => @resource.email, :default => "Welcome #{@resource.email}!") %></p>
|
2
|
+
|
3
|
+
<p><%= t('.instruction', :default => "You can confirm your account email through the link below:") %></p>
|
4
|
+
|
5
|
+
<p><%= link_to t('.action', :default => "Confirm my account"),
|
6
|
+
confirmation_url(@resource, :confirmation_token => @token, locale: I18n.locale) %></p>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<p><%= t('.greeting', :recipient => @resource.email, :default => "Hello #{@resource.email}!") %></p>
|
2
|
+
|
3
|
+
<p><%= t('.instruction', :default => "Someone has requested a link to change your password, and you can do this through the link below.") %></p>
|
4
|
+
|
5
|
+
<p><%= link_to t('.action', :default => "Change my password"), edit_password_url(@resource, :reset_password_token => @token, locale: I18n.locale) %></p>
|
6
|
+
|
7
|
+
<p><%= t('.instruction_2', :default => "If you didn't request this, please ignore this email.") %></p>
|
8
|
+
<p><%= t('.instruction_3', :default => "Your password won't change until you access the link above and create a new one.") %></p>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<p><%= t('.greeting', :recipient => @resource.email, :default => "Hello #{@resource.email}!") %></p>
|
2
|
+
|
3
|
+
<p><%= t('.message', :default => "Your account has been locked due to an excessive amount of unsuccessful sign in attempts.") %></p>
|
4
|
+
|
5
|
+
<p><%= t('.instruction', :default => "Click the link below to unlock your account:") %></p>
|
6
|
+
|
7
|
+
<p><%= link_to t('.action', :default => "Unlock my account"), unlock_url(@resource, :unlock_token => @resource.unlock_token, locale: I18n.locale) %></p>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<div class="row">
|
2
|
+
<div class="col-sm-6">
|
3
|
+
<%= bootstrap_devise_error_messages! %>
|
4
|
+
<div class="panel panel-default">
|
5
|
+
<div class="panel-heading">
|
6
|
+
<h4><%= t('.change_your_password', :default => 'Change your password') %></h4>
|
7
|
+
</div>
|
8
|
+
<div class="panel-body">
|
9
|
+
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, role: "form" }) do |f| %>
|
10
|
+
<%= f.hidden_field :reset_password_token %>
|
11
|
+
|
12
|
+
<div class="form-group">
|
13
|
+
<%= f.label :password, t('.new_password', :default => 'New password') %>
|
14
|
+
<%= f.password_field :password, autofocus: true, class: "form-control" %>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<div class="form-group">
|
18
|
+
<%= f.label :password_confirmation, t('.confirm_new_password', :default => 'Confirm new password') %>
|
19
|
+
<%= f.password_field :password_confirmation, class: "form-control" %>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<%= f.submit t('.change_my_password', :default => 'Change my password'), class: "btn btn-primary" %>
|
23
|
+
<% end %>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
<%= render "devise/shared/links" %>
|
27
|
+
</div>
|
28
|
+
</div>
|