lesli_shield 1.0.2 → 1.0.4

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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/lesli_shield/confirmations.css +18763 -0
  3. data/app/assets/stylesheets/lesli_shield/devise/oauth.css +32 -0
  4. data/app/assets/stylesheets/lesli_shield/passwords.css +18717 -1
  5. data/app/assets/stylesheets/lesli_shield/registrations.css +18804 -1
  6. data/app/assets/stylesheets/lesli_shield/sessions.css +18804 -1
  7. data/app/assets/stylesheets/lesli_shield/users.css +30 -0
  8. data/app/controllers/lesli_shield/dashboards_controller.rb +1 -8
  9. data/app/controllers/lesli_shield/invites_controller.rb +80 -0
  10. data/app/controllers/lesli_shield/role/actions_controller.rb +32 -20
  11. data/app/controllers/lesli_shield/roles_controller.rb +16 -8
  12. data/app/controllers/lesli_shield/sessions_controller.rb +5 -8
  13. data/app/controllers/lesli_shield/user/roles_controller.rb +62 -0
  14. data/app/controllers/lesli_shield/users_controller.rb +57 -20
  15. data/app/controllers/users/confirmations_controller.rb +42 -8
  16. data/app/controllers/users/passwords_controller.rb +52 -37
  17. data/app/controllers/users/registrations_controller.rb +2 -8
  18. data/app/controllers/users/sessions_controller.rb +57 -50
  19. data/app/helpers/lesli_shield/invites_helper.rb +4 -0
  20. data/app/helpers/lesli_shield/user/roles_helper.rb +4 -0
  21. data/app/interfaces/lesli_shield/authorization_interface.rb +8 -2
  22. data/app/mailers/lesli_shield/devise_mailer.rb +98 -0
  23. data/app/mailers/lesli_shield/invitation.html.erb +23 -0
  24. data/app/models/concerns/lesli_shield/user_security.rb +222 -0
  25. data/app/models/lesli_shield/account.rb +1 -1
  26. data/app/models/lesli_shield/dashboard.rb +1 -4
  27. data/app/models/lesli_shield/invite.rb +24 -0
  28. data/{lib/vue/confirmations.js → app/models/lesli_shield/role/action.rb} +17 -10
  29. data/{db/migrate/v1/0801003010_create_lesli_shield_dashboards.rb → app/models/lesli_shield/role/privilege.rb} +5 -4
  30. data/app/models/lesli_shield/user/role.rb +8 -0
  31. data/app/models/lesli_shield/user/session.rb +80 -0
  32. data/app/services/lesli_shield/invite_service.rb +43 -0
  33. data/app/services/lesli_shield/role_action_service.rb +118 -0
  34. data/app/services/lesli_shield/role_privilege_service.rb +112 -0
  35. data/app/{operators/lesli_shield/user_registration_operator.rb → services/lesli_shield/user_registration_service.rb} +26 -29
  36. data/app/services/lesli_shield/user_session_service.rb +78 -0
  37. data/app/services/lesli_shield/user_validator_service.rb +221 -0
  38. data/app/views/devise/confirmations/show.html.erb +4 -6
  39. data/app/views/devise/passwords/edit.html.erb +1 -2
  40. data/app/views/devise/passwords/new.html.erb +1 -1
  41. data/app/views/devise/registrations/new.html.erb +5 -4
  42. data/app/views/devise/sessions/new.html.erb +3 -2
  43. data/app/views/devise/shared/_application-devise-simple.erb +59 -0
  44. data/app/views/devise/shared/_application-devise.html.erb +76 -0
  45. data/app/views/lesli_shield/dashboards/_component-calendar.html.erb +1 -0
  46. data/app/views/lesli_shield/dashboards/_component-chart-bar.html.erb +6 -0
  47. data/app/views/lesli_shield/dashboards/_component-chart-line.html.erb +8 -0
  48. data/app/views/lesli_shield/dashboards/_component-count.html.erb +1 -0
  49. data/app/views/lesli_shield/dashboards/_component-date.html.erb +1 -0
  50. data/app/views/lesli_shield/dashboards/_component-weather.html.erb +1 -0
  51. data/app/views/lesli_shield/invites/_form.html.erb +10 -0
  52. data/app/views/lesli_shield/invites/_invite.html.erb +2 -0
  53. data/app/views/lesli_shield/invites/edit.html.erb +12 -0
  54. data/app/views/lesli_shield/invites/index.html.erb +66 -0
  55. data/{db/migrate/v1/0801001710_create_lesli_shield_settings.rb → app/views/lesli_shield/invites/new.html.erb} +9 -10
  56. data/{lib/vue/apps/dashboards/components/engine-version.vue → app/views/lesli_shield/invites/show.html.erb} +26 -43
  57. data/app/views/lesli_shield/partials/_navigation.html.erb +2 -4
  58. data/app/views/lesli_shield/{roles/_form-privileges.html.erb → role/actions/_form.html.erb} +5 -30
  59. data/app/views/lesli_shield/role/actions/index.html.erb +14 -0
  60. data/app/views/lesli_shield/roles/index.html.erb +2 -6
  61. data/app/views/lesli_shield/roles/new.html.erb +0 -11
  62. data/app/views/lesli_shield/roles/show.html.erb +5 -8
  63. data/app/views/lesli_shield/user/roles/_form.html.erb +17 -0
  64. data/app/views/lesli_shield/user/roles/_role.html.erb +2 -0
  65. data/app/views/lesli_shield/user/roles/edit.html.erb +12 -0
  66. data/app/views/lesli_shield/user/roles/index.html.erb +16 -0
  67. data/app/views/lesli_shield/user/roles/new.html.erb +11 -0
  68. data/app/views/lesli_shield/user/roles/show.html.erb +10 -0
  69. data/app/views/lesli_shield/users/{_viewer-activities.html.erb → _activities-viewer.html.erb} +2 -4
  70. data/app/views/lesli_shield/users/_information-card.html.erb +3 -3
  71. data/app/views/lesli_shield/users/_management-privileges.html.erb +74 -0
  72. data/app/views/lesli_shield/users/_management-security.html.erb +5 -0
  73. data/app/views/lesli_shield/users/index.html.erb +3 -7
  74. data/app/views/lesli_shield/users/new.html.erb +5 -11
  75. data/app/views/lesli_shield/users/show.html.erb +7 -5
  76. data/config/initializers/devise.rb +305 -304
  77. data/config/locales/translations.en.yml +4 -1
  78. data/config/locales/translations.es.yml +4 -1
  79. data/config/locales/translations.it.yml +4 -1
  80. data/config/routes.rb +7 -8
  81. data/db/migrate/v1/0801100210_create_lesli_shield_role_actions.rb +48 -0
  82. data/db/migrate/v1/0801100410_create_lesli_shield_role_privileges.rb +45 -0
  83. data/db/migrate/v1/0801110110_create_lesli_shield_user_roles.rb +43 -0
  84. data/db/migrate/v1/0801111210_create_lesli_shield_user_sessions.rb +56 -0
  85. data/db/migrate/v1/0801120110_create_lesli_shield_invites.rb +49 -0
  86. data/lib/lesli_shield/engine.rb +3 -3
  87. data/lib/lesli_shield/router.rb +21 -0
  88. data/lib/lesli_shield/version.rb +2 -2
  89. data/lib/lesli_shield.rb +1 -1
  90. data/lib/scss/_devise.scss +10 -0
  91. data/lib/scss/confirmations.scss +24 -24
  92. data/lib/tasks/lesli_shield_tasks.rake +1 -1
  93. data/readme.md +59 -20
  94. metadata +69 -44
  95. data/app/controllers/lesli_shield/dashboard/components_controller.rb +0 -60
  96. data/app/models/lesli_shield/dashboard/component.rb +0 -18
  97. data/app/views/lesli_shield/dashboards/edit.html.erb +0 -1
  98. data/app/views/lesli_shield/dashboards/index.html.erb +0 -9
  99. data/app/views/lesli_shield/dashboards/new.html.erb +0 -1
  100. data/app/views/lesli_shield/dashboards/show.html.erb +0 -1
  101. data/app/views/lesli_shield/roles/_session.html.erb +0 -2
  102. data/app/views/lesli_shield/roles/edit.html.erb +0 -12
  103. data/app/views/lesli_shield/roles/update.turbo_stream.erb +0 -3
  104. data/app/views/lesli_shield/users/update.turbo_stream.erb +0 -3
  105. data/lib/lesli_shield/routing.rb +0 -23
  106. data/lib/vue/application.js +0 -83
  107. data/lib/vue/apps/sessions/index.vue +0 -50
  108. data/lib/vue/passwords.js +0 -137
  109. data/lib/vue/registrations.js +0 -144
  110. data/lib/vue/sessions.js +0 -148
  111. data/lib/vue/stores/sessions.js +0 -43
  112. data/lib/vue/stores/translations.json +0 -162
  113. /data/app/views/lesli_shield/roles/{_form-information.html.erb → _form.html.erb} +0 -0
  114. /data/db/migrate/v1/{0801120310_create_lesli_shield_user_shortcuts.rb → 0801111010_create_lesli_shield_user_shortcuts.rb} +0 -0
  115. /data/db/migrate/v1/{0801120410_create_lesli_shield_user_tokens.rb → 0801111110_create_lesli_shield_user_tokens.rb} +0 -0
@@ -1,5 +1,4 @@
1
- <%
2
- =begin
1
+ <%#
3
2
 
4
3
  Lesli
5
4
 
@@ -29,11 +28,10 @@ Building a better future, one line of code at a time.
29
28
 
30
29
  // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
31
30
  // ·
32
- =end
33
31
  %>
34
32
 
35
33
  <%= navigation_item(lesli_shield.dashboard_path, "Dashboard", "ri-dashboard-3-line"); %>
36
34
  <%= navigation_item(lesli_shield.users_path, "Users", "ri-user-line"); %>
37
35
  <%= navigation_item(lesli_shield.sessions_path, "Sessions", "ri-lock-line") %>
38
36
  <%= navigation_item(lesli_shield.roles_path, "Roles", "ri-shield-user-line") %>
39
- <%= navigation_item(lesli_shield.settings_path, "Settings", "ri-settings-3-line") %>
37
+ <%= navigation_item(lesli_shield.invites_path, "Invites", "ri-user-add-line") %>
@@ -55,7 +55,8 @@ columns = [{
55
55
  }
56
56
  </style>
57
57
 
58
- <%= render LesliView::Elements::Table.new(:columns => columns) do |table| %>
58
+ <section id="shield-role-actions-form">
59
+ <%= render(LesliView::Elements::Table.new(:columns => columns)) do |table| %>
59
60
  <% @role_actions.each do |controller_name, actions| %>
60
61
  <% table.with_row do |row| %>
61
62
  <% row.with_cell do %>
@@ -65,9 +66,8 @@ columns = [{
65
66
  <% row.with_cell do %>
66
67
  <% if action %>
67
68
  <%= button_to role_action_path(action),
68
- method: (action[:active] == 1 ? :delete : :patch),
69
- class: "mini-toggle #{action[:active] == 1 ? 'active' : ''}",
70
- form: { "x-data" => "toggleForm", "x-on:submit.prevent" => "submit($el)" } do %>
69
+ class: "mini-toggle #{'active' if action[:active] == 1}",
70
+ method: (action[:active] == 1 ? :delete : :patch) do %>
71
71
  <span class="mini-toggle-slider"></span>
72
72
  <% end %>
73
73
  <% end %>
@@ -76,29 +76,4 @@ columns = [{
76
76
  <% end %>
77
77
  <% end %>
78
78
  <% end %>
79
- <script>
80
- document.addEventListener('alpine:init', () => {
81
- Alpine.data('toggleForm', () => ({
82
- submit(form) {
83
- const method = form.querySelector('input[name="_method"]')?.value?.toUpperCase() || form.method.toUpperCase();
84
- fetch(form.action, {
85
- method: method,
86
- headers: {
87
- 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content,
88
- 'Accept': 'text/vnd.turbo-stream.html' // or 'application/json'
89
- },
90
- //body: new URLSearchParams(new FormData(form))
91
- }).then(response => {
92
- if (!response.ok) throw new Error("Request failed");
93
- return response.text();
94
- }).then(() => {
95
- // Success! Toggle the class
96
- form.querySelector('button')?.classList.toggle('active');
97
- }).catch(err => {
98
- console.error("Error:", err);
99
- alert("Something went wrong");
100
- });
101
- }
102
- }))
103
- });
104
- </script>
79
+ </section>
@@ -0,0 +1,14 @@
1
+ <%= render LesliView::Layout::Container.new("shield-role-actions") do %>
2
+ <%= render LesliView::Components::Header.new("#{@role.name} privileges", :back => role_path(@role)) do %>
3
+ <%= render(LesliView::Elements::Button.new('Deploy privileges',
4
+ solid:true,
5
+ danger:true,
6
+ icon: 'shield',
7
+ css_class: 'is-light is-hovered',
8
+ url: deploy_role_path(@role.id),
9
+ method: :post
10
+
11
+ )) %>
12
+ <% end %>
13
+ <%= render "form" %>
14
+ <% end %>
@@ -29,12 +29,8 @@ columns = [{
29
29
  %>
30
30
  <%= render LesliView::Layout::Container.new("shield-roles") do %>
31
31
  <%= render LesliView::Components::Header.new("Roles") do %>
32
- <%= render(LesliView::Elements::Button.new(icon: "add", solid:true)) do %>
33
- Add new
34
- <% end %>
35
- <%= render(LesliView::Elements::Button.new(icon: "refresh")) do %>
36
- Reload
37
- <% end %>
32
+ <%= render(LesliView::Elements::Button.new('Add new', icon: "add", solid:true)) %>
33
+ <%= render(LesliView::Elements::Button.new('Reload', icon: "refresh")) %>
38
34
  <% end %>
39
35
  <%= render LesliView::Components::Toolbar.new() %>
40
36
  <%= render(LesliView::Elements::Table.new(
@@ -1,11 +0,0 @@
1
- <% content_for :title, "New session" %>
2
-
3
- <h1>New session</h1>
4
-
5
- <%= render "form", session: @session %>
6
-
7
- <br>
8
-
9
- <div>
10
- <%= link_to "Back to sessions", sessions_path %>
11
- </div>
@@ -1,13 +1,10 @@
1
1
  <%= render LesliView::Layout::Container.new("shield-roles-show") do %>
2
2
  <%= render LesliView::Components::Header.new(@role.name) do %>
3
+ <%= render(LesliView::Elements::Button.new('Privileges',
4
+ url: role_actions_path(@role),
5
+ icon: 'security'
6
+ )) %>
3
7
  <% end %>
4
8
 
5
- <%= render LesliView::Components::Tabs.new() do |tabs| %>
6
- <% tabs.with_tab(title:"privileges", icon:"security") do %>
7
- <%= render "form-privileges" %>
8
- <% end %>
9
- <% tabs.with_tab(title:"information", icon:"info_outline") do %>
10
- <%= render "form-information" %>
11
- <% end %>
12
- <% end %>
9
+ <%= render "form" %>
13
10
  <% end %>
@@ -0,0 +1,17 @@
1
+ <%= form_with(model: user_role) do |form| %>
2
+ <% if user_role.errors.any? %>
3
+ <div style="color: red">
4
+ <h2><%= pluralize(user_role.errors.count, "error") %> prohibited this user_role from being saved:</h2>
5
+
6
+ <ul>
7
+ <% user_role.errors.each do |error| %>
8
+ <li><%= error.full_message %></li>
9
+ <% end %>
10
+ </ul>
11
+ </div>
12
+ <% end %>
13
+
14
+ <div>
15
+ <%= form.submit %>
16
+ </div>
17
+ <% end %>
@@ -0,0 +1,2 @@
1
+ <div id="<%= dom_id role %>">
2
+ </div>
@@ -0,0 +1,12 @@
1
+ <% content_for :title, "Editing role" %>
2
+
3
+ <h1>Editing role</h1>
4
+
5
+ <%= render "form", user_role: @user_role %>
6
+
7
+ <br>
8
+
9
+ <div>
10
+ <%= link_to "Show this role", @user_role %> |
11
+ <%= link_to "Back to roles", user_roles_path %>
12
+ </div>
@@ -0,0 +1,16 @@
1
+ <p style="color: green"><%= notice %></p>
2
+
3
+ <% content_for :title, "Roles" %>
4
+
5
+ <h1>Roles</h1>
6
+
7
+ <div id="user_roles">
8
+ <% @user_roles.each do |user_role| %>
9
+ <%= render user_role %>
10
+ <p>
11
+ <%= link_to "Show this role", user_role %>
12
+ </p>
13
+ <% end %>
14
+ </div>
15
+
16
+ <%= link_to "New role", new_user_role_path %>
@@ -0,0 +1,11 @@
1
+ <% content_for :title, "New role" %>
2
+
3
+ <h1>New role</h1>
4
+
5
+ <%= render "form", user_role: @user_role %>
6
+
7
+ <br>
8
+
9
+ <div>
10
+ <%= link_to "Back to roles", user_roles_path %>
11
+ </div>
@@ -0,0 +1,10 @@
1
+ <p style="color: green"><%= notice %></p>
2
+
3
+ <%= render @user_role %>
4
+
5
+ <div>
6
+ <%= link_to "Edit this role", edit_user_role_path(@user_role) %> |
7
+ <%= link_to "Back to roles", user_roles_path %>
8
+
9
+ <%= button_to "Destroy this role", @user_role, method: :delete %>
10
+ </div>
@@ -1,5 +1,3 @@
1
-
2
-
3
-
4
- <%#= dd @activities %>
1
+ <div class="box">
5
2
  <%= render(LesliView::Components::Timeline.new(:activities => @activities)) %>
3
+ </div>
@@ -10,11 +10,11 @@
10
10
  <h5 class="title is-size-5 mb-0">
11
11
  <%= @user.full_name %>
12
12
  </h5>
13
- <p><%= @user.title %></p>
13
+ <p class="mb-1"><%= @user.title %></p>
14
14
  <div class="level is-mobile">
15
15
  <div class="level-left">
16
16
  <a class="level-item"
17
- href="'mailto:'+storeUser.user.email">
17
+ href="mailto:<%= @user.email %>">
18
18
  <span class="icon is-small mr-2">
19
19
  <span class="material-symbols">
20
20
  email
@@ -23,7 +23,7 @@
23
23
  <%= @user.email %>
24
24
  </a>
25
25
  <a class="level-item mx-2"
26
- href="'tel:'+storeUser.user.telephone">
26
+ href="tel:<%= @user.telephone %>">
27
27
  <span class="icon is-small mr-2">
28
28
  <span class="material-symbols">
29
29
  phone
@@ -0,0 +1,74 @@
1
+ <%
2
+ columns = [{
3
+ label: "ID"
4
+ }, {
5
+ label: "Name"
6
+ }, {
7
+ label: "status"
8
+ }]
9
+ %>
10
+
11
+ <% roles = @user.account.roles.joins("
12
+ LEFT JOIN lesli_shield_user_roles
13
+ ON lesli_shield_user_roles.role_id = lesli_roles.id
14
+ AND lesli_shield_user_roles.user_id = #{@user.id}
15
+ ").select(
16
+ "lesli_roles.*",
17
+ "lesli_shield_user_roles.id AS user_role_id"
18
+ )
19
+ %>
20
+
21
+ <%= render(LesliView::Elements::Table.new(:columns => columns)) do |table| %>
22
+ <% roles.each do |role| %>
23
+ <% table.with_row do |row| %>
24
+ <% row.with_cell do %>
25
+ <%= role[:id] %>
26
+ <% end %>
27
+ <% row.with_cell do %>
28
+ <%= role[:name] %>
29
+ <% end %>
30
+ <% row.with_cell do %>
31
+ <%= button_to user_role_path(role),
32
+ class: "mini-toggle #{'active' if role[:user_role_id].present?}",
33
+ method: (role[:user_role_id].present? ? :delete : :patch) do %>
34
+ <span class="mini-toggle-slider"></span>
35
+ <% end %>
36
+ <% end %>
37
+ <% end %>
38
+ <% end %>
39
+ <% end %>
40
+
41
+ <style>
42
+ .mini-toggle {
43
+ position: relative;
44
+ width: 40px;
45
+ height: 20px;
46
+ background: #ccc;
47
+ border-radius: 9999px;
48
+ border: none;
49
+ cursor: pointer;
50
+ padding: 0;
51
+ transition: background 0.25s ease;
52
+ display: inline-block;
53
+ }
54
+
55
+ .mini-toggle.active {
56
+ background: #22c55e; /* green */
57
+ background: var(--lesli-color-primary)
58
+ }
59
+
60
+ .mini-toggle-slider {
61
+ position: absolute;
62
+ top: 2px;
63
+ left: 2px;
64
+ width: 16px;
65
+ height: 16px;
66
+ background: white;
67
+ border-radius: 50%;
68
+ transition: transform 0.25s ease;
69
+ }
70
+
71
+ .mini-toggle.active .mini-toggle-slider {
72
+ transform: translateX(20px);
73
+ }
74
+ </style>
@@ -0,0 +1,5 @@
1
+ <div class="box">
2
+ <%= render(LesliView::Elements::Button.new('Revoke access')) %>
3
+ <%= render(LesliView::Elements::Button.new('Set password as expired')) %>
4
+ <%= render(LesliView::Elements::Button.new('Force password update')) %>
5
+ </div>
@@ -17,7 +17,7 @@ columns = [{
17
17
  label: "roles",
18
18
  sort: true
19
19
  }, {
20
- field: "active",
20
+ field: "status",
21
21
  label: "status",
22
22
  sort: true,
23
23
  custom: true
@@ -29,12 +29,8 @@ columns = [{
29
29
  %>
30
30
  <%= render LesliView::Layout::Container.new("shield-sessions") do %>
31
31
  <%= render LesliView::Components::Header.new("Users") do %>
32
- <%= render(LesliView::Elements::Button.new(icon: "add", solid:true)) do %>
33
- Add new
34
- <% end %>
35
- <%= render(LesliView::Elements::Button.new(icon: "refresh")) do %>
36
- Reload
37
- <% end %>
32
+ <%= render(LesliView::Elements::Button.new('Add user', url: new_user_path, icon: "add", solid:true)) %>
33
+ <%= render(LesliView::Elements::Button.new('Refresh', icon: 'refresh')) %>
38
34
  <% end %>
39
35
  <%= render LesliView::Components::Toolbar.new() %>
40
36
  <%= render(LesliView::Elements::Table.new(
@@ -1,11 +1,5 @@
1
- <% content_for :title, "New user" %>
2
-
3
- <h1>New user</h1>
4
-
5
- <%= render "form", user: @user %>
6
-
7
- <br>
8
-
9
- <div>
10
- <%= link_to "Back to users", users_path %>
11
- </div>
1
+ <%= render LesliView::Layout::Container.new("shield-users-show") do %>
2
+ <%= render LesliView::Components::Header.new('Add new user') do %>
3
+ <% end %>
4
+ <%= render "information-form" %>
5
+ <% end %>
@@ -2,26 +2,28 @@
2
2
 
3
3
  <%= render "information-card" %>
4
4
 
5
- <%= render LesliView::Components::Tabs.new() do |tabs| %>
5
+ <%= render LesliView::Components::Tabs.new(active_tab: 'information') do |tabs| %>
6
6
 
7
7
  <% tabs.with_tab(title:"information", icon:"info") do %>
8
- <%= render "information-form" %>
8
+ <%= render("information-form") %>
9
9
  <% end %>
10
10
  <% tabs.with_tab(title:"Privileges", icon:"security") do %>
11
+ <%= render("management-privileges") %>
11
12
  <% end %>
12
13
 
13
14
  <% tabs.with_tab(title:"Security", icon:"lock_outline") do %>
15
+ <%= render("management-security") %>
14
16
  <% end %>
15
17
 
16
18
  <% tabs.with_tab(title:"Sessions", icon:"devices") do %>
17
- <%= render "management-sessions" %>
19
+ <%= render("management-sessions") %>
18
20
  <% end %>
19
21
 
20
22
  <% tabs.with_tab(title:"Settings", icon:"settings") do %>
21
23
  <% end %>
22
24
 
23
- <% tabs.with_tab(title:"Activities", icon:"history") do %>
24
- <%= render "viewer-activities" %>
25
+ <% tabs.with_tab(title:"Audit logs", icon:"history") do %>
26
+ <%= render("activities-viewer") %>
25
27
  <% end %>
26
28
  <% end %>
27
29
  <% end %>