goodmin 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.
Files changed (147) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +1359 -0
  4. data/Rakefile +56 -0
  5. data/app/assets/stylesheets/goodmin/application.css +75 -0
  6. data/app/controllers/goodmin/application_controller.rb +43 -0
  7. data/app/controllers/goodmin/resource_controller.rb +235 -0
  8. data/app/helpers/goodmin/application_helper.rb +45 -0
  9. data/app/javascript/goodmin/application.js +8 -0
  10. data/app/javascript/goodmin/controllers/batch_actions_controller.js +101 -0
  11. data/app/javascript/goodmin/controllers/datetimepicker_controller.js +24 -0
  12. data/app/javascript/goodmin/controllers/navigation_controller.js +30 -0
  13. data/app/jobs/goodmin/application_job.rb +4 -0
  14. data/app/mailers/goodmin/application_mailer.rb +6 -0
  15. data/app/models/goodmin/application_record.rb +5 -0
  16. data/app/views/goodmin/application/welcome.html.erb +17 -0
  17. data/app/views/goodmin/fields/association/_form.html.erb +19 -0
  18. data/app/views/goodmin/fields/association/_index.html.erb +6 -0
  19. data/app/views/goodmin/fields/association/_show.html.erb +6 -0
  20. data/app/views/goodmin/fields/boolean/_form.html.erb +7 -0
  21. data/app/views/goodmin/fields/boolean/_index.html.erb +1 -0
  22. data/app/views/goodmin/fields/boolean/_show.html.erb +1 -0
  23. data/app/views/goodmin/fields/date/_form.html.erb +6 -0
  24. data/app/views/goodmin/fields/date/_index.html.erb +1 -0
  25. data/app/views/goodmin/fields/date/_show.html.erb +1 -0
  26. data/app/views/goodmin/fields/date_time/_form.html.erb +6 -0
  27. data/app/views/goodmin/fields/date_time/_index.html.erb +1 -0
  28. data/app/views/goodmin/fields/date_time/_show.html.erb +1 -0
  29. data/app/views/goodmin/fields/enum/_index.html.erb +1 -0
  30. data/app/views/goodmin/fields/enum/_show.html.erb +1 -0
  31. data/app/views/goodmin/fields/nested_has_one/_form.html.erb +6 -0
  32. data/app/views/goodmin/fields/nested_has_one/_index.html.erb +1 -0
  33. data/app/views/goodmin/fields/nested_has_one/_show.html.erb +1 -0
  34. data/app/views/goodmin/fields/number/_form.html.erb +5 -0
  35. data/app/views/goodmin/fields/number/_index.html.erb +1 -0
  36. data/app/views/goodmin/fields/number/_show.html.erb +1 -0
  37. data/app/views/goodmin/fields/password/_form.html.erb +5 -0
  38. data/app/views/goodmin/fields/password/_index.html.erb +1 -0
  39. data/app/views/goodmin/fields/password/_show.html.erb +1 -0
  40. data/app/views/goodmin/fields/select/_form.html.erb +5 -0
  41. data/app/views/goodmin/fields/select/_index.html.erb +1 -0
  42. data/app/views/goodmin/fields/select/_show.html.erb +1 -0
  43. data/app/views/goodmin/fields/string/_form.html.erb +5 -0
  44. data/app/views/goodmin/fields/string/_index.html.erb +1 -0
  45. data/app/views/goodmin/fields/string/_show.html.erb +1 -0
  46. data/app/views/goodmin/fields/text/_form.html.erb +5 -0
  47. data/app/views/goodmin/fields/text/_index.html.erb +1 -0
  48. data/app/views/goodmin/fields/text/_show.html.erb +1 -0
  49. data/app/views/goodmin/resource/_actions.html.erb +9 -0
  50. data/app/views/goodmin/resource/_batch_actions.html.erb +12 -0
  51. data/app/views/goodmin/resource/_breadcrumb.html.erb +33 -0
  52. data/app/views/goodmin/resource/_breadcrumb_actions.html.erb +41 -0
  53. data/app/views/goodmin/resource/_button_actions.html.erb +3 -0
  54. data/app/views/goodmin/resource/_errors.html.erb +9 -0
  55. data/app/views/goodmin/resource/_export_actions.html.erb +15 -0
  56. data/app/views/goodmin/resource/_filters.html.erb +22 -0
  57. data/app/views/goodmin/resource/_form.html.erb +26 -0
  58. data/app/views/goodmin/resource/_pagination.html.erb +40 -0
  59. data/app/views/goodmin/resource/_scopes.html.erb +14 -0
  60. data/app/views/goodmin/resource/_table.html.erb +45 -0
  61. data/app/views/goodmin/resource/columns/_actions.html.erb +28 -0
  62. data/app/views/goodmin/resource/edit.html.erb +5 -0
  63. data/app/views/goodmin/resource/index.csv.csvbuilder +5 -0
  64. data/app/views/goodmin/resource/index.html.erb +10 -0
  65. data/app/views/goodmin/resource/index.json.jbuilder +3 -0
  66. data/app/views/goodmin/resource/new.html.erb +5 -0
  67. data/app/views/goodmin/resource/show.html.erb +11 -0
  68. data/app/views/goodmin/resource/show.json.jbuilder +1 -0
  69. data/app/views/goodmin/sessions/new.html.erb +11 -0
  70. data/app/views/goodmin/shared/_navigation.html.erb +0 -0
  71. data/app/views/goodmin/shared/_navigation_aside.html.erb +7 -0
  72. data/app/views/layouts/goodmin/_content.html.erb +13 -0
  73. data/app/views/layouts/goodmin/_layout.html.erb +22 -0
  74. data/app/views/layouts/goodmin/application.html.erb +28 -0
  75. data/app/views/layouts/goodmin/login.html.erb +18 -0
  76. data/config/importmap.rb +5 -0
  77. data/config/locales/en.yml +49 -0
  78. data/config/locales/pl-BR.yml +49 -0
  79. data/config/locales/pt-BR.yml +49 -0
  80. data/config/locales/sv.yml +49 -0
  81. data/config/routes.rb +3 -0
  82. data/lib/generators/goodmin/authentication/authentication_generator.rb +41 -0
  83. data/lib/generators/goodmin/authentication/templates/sessions_controller.rb +9 -0
  84. data/lib/generators/goodmin/install/install_generator.rb +41 -0
  85. data/lib/generators/goodmin/policy/policy_generator.rb +7 -0
  86. data/lib/generators/goodmin/policy/templates/policy.rb +23 -0
  87. data/lib/generators/goodmin/resource/resource_generator.rb +31 -0
  88. data/lib/generators/goodmin/resource/templates/resource.rb +25 -0
  89. data/lib/generators/goodmin/resource/templates/resource_controller.rb +9 -0
  90. data/lib/generators/goodmin/resource/templates/resource_model.rb +4 -0
  91. data/lib/generators/goodmin/resource/templates/resource_service.rb +23 -0
  92. data/lib/goodmin/authentication/sessions_controller.rb +46 -0
  93. data/lib/goodmin/authentication/user.rb +27 -0
  94. data/lib/goodmin/authentication.rb +35 -0
  95. data/lib/goodmin/authorization/policy.rb +41 -0
  96. data/lib/goodmin/authorization.rb +69 -0
  97. data/lib/goodmin/engine.rb +30 -0
  98. data/lib/goodmin/fields/association.rb +62 -0
  99. data/lib/goodmin/fields/base.rb +57 -0
  100. data/lib/goodmin/fields/boolean.rb +6 -0
  101. data/lib/goodmin/fields/date.rb +6 -0
  102. data/lib/goodmin/fields/date_time.rb +6 -0
  103. data/lib/goodmin/fields/enum.rb +15 -0
  104. data/lib/goodmin/fields/nested_has_one.rb +41 -0
  105. data/lib/goodmin/fields/number.rb +6 -0
  106. data/lib/goodmin/fields/password.rb +6 -0
  107. data/lib/goodmin/fields/select.rb +19 -0
  108. data/lib/goodmin/fields/string.rb +6 -0
  109. data/lib/goodmin/fields/text.rb +6 -0
  110. data/lib/goodmin/generators/base.rb +49 -0
  111. data/lib/goodmin/generators/named_base.rb +31 -0
  112. data/lib/goodmin/helpers/application.rb +47 -0
  113. data/lib/goodmin/helpers/batch_actions.rb +21 -0
  114. data/lib/goodmin/helpers/filters.rb +123 -0
  115. data/lib/goodmin/helpers/forms.rb +42 -0
  116. data/lib/goodmin/helpers/navigation.rb +52 -0
  117. data/lib/goodmin/helpers/tables.rb +25 -0
  118. data/lib/goodmin/helpers/translations.rb +19 -0
  119. data/lib/goodmin/paginator.rb +55 -0
  120. data/lib/goodmin/resolver.rb +141 -0
  121. data/lib/goodmin/resources/attribute.rb +46 -0
  122. data/lib/goodmin/resources/form_builder.rb +96 -0
  123. data/lib/goodmin/resources/form_component.rb +65 -0
  124. data/lib/goodmin/resources/form_components/col.rb +33 -0
  125. data/lib/goodmin/resources/form_components/row.rb +25 -0
  126. data/lib/goodmin/resources/form_components/section.rb +51 -0
  127. data/lib/goodmin/resources/form_components/tab.rb +49 -0
  128. data/lib/goodmin/resources/resource/associations.rb +23 -0
  129. data/lib/goodmin/resources/resource/batch_actions.rb +56 -0
  130. data/lib/goodmin/resources/resource/filters.rb +44 -0
  131. data/lib/goodmin/resources/resource/ordering.rb +41 -0
  132. data/lib/goodmin/resources/resource/pagination.rb +22 -0
  133. data/lib/goodmin/resources/resource/scopes.rb +61 -0
  134. data/lib/goodmin/resources/resource.rb +199 -0
  135. data/lib/goodmin/resources/resource_controller/batch_actions.rb +49 -0
  136. data/lib/goodmin/resources/resource_service/associations.rb +23 -0
  137. data/lib/goodmin/resources/resource_service/batch_actions.rb +52 -0
  138. data/lib/goodmin/resources/resource_service/filters.rb +44 -0
  139. data/lib/goodmin/resources/resource_service/ordering.rb +41 -0
  140. data/lib/goodmin/resources/resource_service/pagination.rb +22 -0
  141. data/lib/goodmin/resources/resource_service/scopes.rb +61 -0
  142. data/lib/goodmin/resources/resource_service.rb +199 -0
  143. data/lib/goodmin/service_locator.rb +25 -0
  144. data/lib/goodmin/version.rb +3 -0
  145. data/lib/goodmin.rb +44 -0
  146. data/lib/tasks/goodmin_tasks.rake +4 -0
  147. metadata +461 -0
@@ -0,0 +1,49 @@
1
+ en:
2
+ goodmin:
3
+ title: Goodmin
4
+ batch_actions:
5
+ buttons:
6
+ select_all: Select all
7
+ deselect_all: Deselect all
8
+ confirm_message: Are you sure?
9
+ filters:
10
+ select:
11
+ placeholder:
12
+ one: Select something
13
+ many: Select something
14
+ buttons:
15
+ apply: Filter
16
+ clear: Clear filter
17
+ actions:
18
+ label: Actions
19
+ show: Show
20
+ show_title: Show %{resource}
21
+ edit: Edit
22
+ edit_title: Edit %{resource}
23
+ destroy: Destroy
24
+ destroy_title: Destroy %{resource}
25
+ confirm_message: Are you sure?
26
+ export: Export
27
+ export_as: As
28
+ associations:
29
+ label: Nested resources
30
+ sessions:
31
+ sign_in: Sign in
32
+ sign_out: Sign out
33
+ signed_in: Signed in
34
+ signed_out: Signed out
35
+ failed_sign_in: Invalid credentials
36
+ flash:
37
+ create: "%{resource} was successfully created"
38
+ update: "%{resource} was successfully updated"
39
+ destroy: "%{resource} was successfully destroyed"
40
+ batch_action: "%{number_of_records} %{resource} were affected"
41
+ pagination:
42
+ first: "First"
43
+ last: "Last"
44
+ entries:
45
+ zero: "No %{resource} found"
46
+ other: "Showing %{count} out of %{total} %{resource}"
47
+ datetimepickers:
48
+ datepicker: ! "%d/%m/%Y"
49
+ datetimepicker: ! "%d/%m/%Y %H:%M"
@@ -0,0 +1,49 @@
1
+ pt-BR:
2
+ goodmin:
3
+ title: Goodmin
4
+ batch_actions:
5
+ buttons:
6
+ select_all: Selecionar todos
7
+ deselect_all: Remover seleção
8
+ confirm_message: Você tem certeza?
9
+ filters:
10
+ select:
11
+ placeholder:
12
+ one: Selecionar um
13
+ many: Selecionar vários
14
+ buttons:
15
+ apply: Filtrar
16
+ clear: Limpar filtro
17
+ actions:
18
+ label: Ações
19
+ show: Exibir
20
+ show_ttitle: Exibir %{resource}
21
+ edit: Editar
22
+ edit_title: Editar %{resource}
23
+ destroy: Remover
24
+ destroy_title: Remover %{resource}
25
+ confirm_message: Você tem certeza?
26
+ export: Exportar
27
+ export_as: Como
28
+ associations:
29
+ label: Nested resources
30
+ sessions:
31
+ sign_in: Entrar
32
+ sign_out: Sair
33
+ signed_in: Conectado
34
+ signed_out: Desconectado
35
+ failed_sign_in: Credenciais inválidas
36
+ flash:
37
+ create: "%{resource} foi criado com sucesso"
38
+ update: "%{resource} foi atualizado com sucesso"
39
+ destroy: "%{resource} foi removido com sucesso"
40
+ batch_action: "%{number_of_records} %{resource} foram modificados"
41
+ pagination:
42
+ first: "Primeiro"
43
+ last: "Último"
44
+ entries:
45
+ zero: "Nenhum %{resource} encontrado"
46
+ other: "Exibindo %{count} de %{total} %{resource}"
47
+ datetimepickers:
48
+ datepicker: ! "%d/%m/%Y"
49
+ datetimepicker: ! "%d/%m/%Y %H:%M"
@@ -0,0 +1,49 @@
1
+ pt-BR:
2
+ goodmin:
3
+ title: Goodmin
4
+ batch_actions:
5
+ buttons:
6
+ select_all: Selecionar todos
7
+ deselect_all: Remover seleção
8
+ confirm_message: Você tem certeza?
9
+ filters:
10
+ select:
11
+ placeholder:
12
+ one: Selecionar um
13
+ many: Selecionar vários
14
+ buttons:
15
+ apply: Filtrar
16
+ clear: Limpar filtro
17
+ actions:
18
+ label: Ações
19
+ show: Exibir
20
+ show_ttitle: Exibir %{resource}
21
+ edit: Editar
22
+ edit_title: Editar %{resource}
23
+ destroy: Remover
24
+ destroy_title: Remover %{resource}
25
+ confirm_message: Você tem certeza?
26
+ export: Exportar
27
+ export_as: Como
28
+ associations:
29
+ label: Nested resources
30
+ sessions:
31
+ sign_in: Entrar
32
+ sign_out: Sair
33
+ signed_in: Conectado
34
+ signed_out: Desconectado
35
+ failed_sign_in: Credenciais inválidas
36
+ flash:
37
+ create: "%{resource} foi criado com sucesso"
38
+ update: "%{resource} foi atualizado com sucesso"
39
+ destroy: "%{resource} foi removido com sucesso"
40
+ batch_action: "%{number_of_records} %{resource} foram modificados"
41
+ pagination:
42
+ first: "Primeiro"
43
+ last: "Último"
44
+ entries:
45
+ zero: "Nenhum %{resource} encontrado"
46
+ other: "Exibindo %{count} de %{total} %{resource}"
47
+ datetimepickers:
48
+ datepicker: ! "%d/%m/%Y"
49
+ datetimepicker: ! "%d/%m/%Y %H:%M"
@@ -0,0 +1,49 @@
1
+ sv:
2
+ goodmin:
3
+ title: Goodmin
4
+ batch_actions:
5
+ buttons:
6
+ select_all: Markera alla
7
+ deselect_all: Avmarkera alla
8
+ confirm_message: Är du säker?
9
+ filters:
10
+ select:
11
+ placeholder:
12
+ one: Välj någonting
13
+ many: Välj någonting
14
+ buttons:
15
+ apply: Filtrera
16
+ clear: Rensa filter
17
+ actions:
18
+ label: Alternativ
19
+ show: Visa
20
+ show_title: Visa %{resource}
21
+ edit: Ändra
22
+ edit_title: Ändra %{resource}
23
+ destroy: Ta bort
24
+ destroy_title: Ta bort %{resource}
25
+ confirm_message: Är du säker?
26
+ export: Exportera
27
+ export_as: Som
28
+ associations:
29
+ label: Nästlade resurser
30
+ sessions:
31
+ sign_in: Logga in
32
+ sign_out: Logga ut
33
+ signed_in: Loggade in
34
+ signed_out: Loggade ut
35
+ failed_sign_in: Fel inloggningsuppgifter
36
+ flash:
37
+ create: "%{resource} skapades"
38
+ update: "%{resource} uppdaterades"
39
+ destroy: "%{resource} togs bort"
40
+ batch_action: "%{number_of_records} %{resource} påverkades"
41
+ pagination:
42
+ first: "Första"
43
+ last: "Sista"
44
+ entries:
45
+ zero: "Inga %{resource} funna"
46
+ other: "Visar %{count} av %{total} %{resource}"
47
+ datetimepickers:
48
+ datepicker: ! "%Y-%m-%d"
49
+ datetimepicker: ! "%Y-%m-%d %H:%M"
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Goodmin::Engine.routes.draw do
2
+ root to: "application#welcome"
3
+ end
@@ -0,0 +1,41 @@
1
+ require "goodmin/generators/named_base"
2
+
3
+ class Goodmin::AuthenticationGenerator < Goodmin::Generators::NamedBase
4
+ argument :name, type: :string, default: "admin_user"
5
+
6
+ def create_model
7
+ generate "model", "#{name} email:string password_digest:text --no-test-framework"
8
+ end
9
+
10
+ def modify_model
11
+ inject_into_file File.join("app/models", class_path, "#{file_name}.rb"), after: "ActiveRecord::Base\n" do
12
+ <<-END.strip_heredoc.indent(namespace ? 4 : 2)
13
+ include Goodmin::Authentication::User
14
+
15
+ def self.login_column
16
+ :email
17
+ end
18
+ END
19
+ end
20
+ end
21
+
22
+ def create_route
23
+ route "resource :session, only: [:new, :create, :destroy]"
24
+ end
25
+
26
+ def create_sessions_controller
27
+ template "sessions_controller.rb", File.join("app/controllers", namespaced_path, "sessions_controller.rb")
28
+ end
29
+
30
+ def modify_application_controller
31
+ inject_into_file File.join("app/controllers", namespaced_path, "application_controller.rb"), after: "Goodmin::ApplicationController\n" do
32
+ <<-END.strip_heredoc.indent(namespace ? 4 : 2)
33
+ include Goodmin::Authentication
34
+
35
+ def admin_user_class
36
+ #{full_class_name}
37
+ end
38
+ END
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ <% if namespaced? -%>
2
+ require_dependency "<%= File.join(namespaced_path, "application_controller") %>"
3
+
4
+ <% end -%>
5
+ <% module_namespacing do -%>
6
+ class SessionsController < ApplicationController
7
+ include Goodmin::Authentication::SessionsController
8
+ end
9
+ <% end -%>
@@ -0,0 +1,41 @@
1
+ require "goodmin/generators/base"
2
+
3
+ class Goodmin::InstallGenerator < Goodmin::Generators::Base
4
+ def create_routes
5
+ if namespaced?
6
+ inject_into_file "config/routes.rb", before: /^end/ do
7
+ <<-END.strip_heredoc.indent(2)
8
+ root to: "application#welcome"
9
+ END
10
+ end
11
+ else
12
+ inject_into_file "config/routes.rb", before: /^end/ do
13
+ <<-END.strip_heredoc.indent(2)
14
+ mount Goodmin::Engine, at: "/admin"
15
+ END
16
+ end
17
+ end
18
+ end
19
+
20
+ def create_navigation
21
+ create_file "app/views/goodmin/shared/_navigation.html.erb"
22
+ end
23
+
24
+ def modify_application_controller
25
+ return if namespaced?
26
+
27
+ gsub_file "app/controllers/application_controller.rb",
28
+ /class ApplicationController < ActionController::Base/,
29
+ "class ApplicationController < Goodmin::ApplicationController"
30
+ end
31
+
32
+ def require_library_if_namespaced
33
+ return unless namespaced?
34
+
35
+ inject_into_file File.join("lib", namespaced_path) + ".rb", before: "require" do
36
+ <<-END.strip_heredoc
37
+ require "goodmin"
38
+ END
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,7 @@
1
+ require "goodmin/generators/named_base"
2
+
3
+ class Goodmin::PolicyGenerator < Goodmin::Generators::NamedBase
4
+ def create_policy
5
+ template "policy.rb", File.join("app/policies", class_path, "#{file_name}_policy.rb")
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Policy < Goodmin::Authorization::Policy
3
+ def index?
4
+ true
5
+ end
6
+
7
+ def show?
8
+ true
9
+ end
10
+
11
+ def create?
12
+ true
13
+ end
14
+
15
+ def update?
16
+ true
17
+ end
18
+
19
+ def destroy?
20
+ true
21
+ end
22
+ end
23
+ <% end -%>
@@ -0,0 +1,31 @@
1
+ require "goodmin/generators/named_base"
2
+
3
+ class Goodmin::ResourceGenerator < Goodmin::Generators::NamedBase
4
+ argument :attributes, type: :array, default: [], banner: "attribute attribute"
5
+
6
+ def add_route
7
+ invoke "resource_route"
8
+ end
9
+
10
+ def add_navigation
11
+ append_to_file "app/views/goodmin/shared/_navigation.html.erb" do
12
+ <<-END.strip_heredoc
13
+ <%= navbar_item #{class_name} %>
14
+ END
15
+ end
16
+ end
17
+
18
+ def create_model
19
+ if namespaced?
20
+ template "resource_model.rb", File.join("app/models", class_path, "#{file_name}.rb")
21
+ end
22
+ end
23
+
24
+ def create_controller
25
+ template "resource_controller.rb", File.join("app/controllers", class_path, "#{file_name.pluralize}_controller.rb")
26
+ end
27
+
28
+ def create_resource
29
+ template "resource.rb", File.join("app/goodmin/resources", "#{file_name}_resource.rb")
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ module Goodmin
2
+ module Resources
3
+ class <%= class_name %>Resource
4
+ include Goodmin::Resources::Resource
5
+
6
+ index do
7
+ <% @attributes.each do |x| -%>
8
+ attribute :<%= x %>
9
+ <% end -%>
10
+ end
11
+
12
+ show do
13
+ <% @attributes.each do |x| -%>
14
+ attribute :<%= x %>
15
+ <% end -%>
16
+ end
17
+
18
+ form do
19
+ <% @attributes.each do |x| -%>
20
+ attribute :<%= x %>
21
+ <% end -%>
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ <% if namespaced? -%>
2
+ require_dependency "<%= File.join(namespaced_path, "application_controller") %>"
3
+
4
+ <% end -%>
5
+ <% module_namespacing do -%>
6
+ class <%= class_name.pluralize %>Controller < ApplicationController
7
+ include Goodmin::Resources::ResourceController
8
+ end
9
+ <% end -%>
@@ -0,0 +1,4 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %> < ::<%= class_name %>
3
+ end
4
+ <% end -%>
@@ -0,0 +1,23 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Service
3
+ include Goodmin::Resources::ResourceService
4
+
5
+ index do
6
+ <% @attributes.each do |x| -%>
7
+ attribute :<%= x %>
8
+ <% end -%>
9
+ end
10
+
11
+ show do
12
+ <% @attributes.each do |x| -%>
13
+ attribute :<%= x %>
14
+ <% end -%>
15
+ end
16
+
17
+ form do
18
+ <% @attributes.each do |x| -%>
19
+ attribute :<%= x %>
20
+ <% end -%>
21
+ end
22
+ end
23
+ <% end -%>
@@ -0,0 +1,46 @@
1
+ module Goodmin
2
+ module Authentication
3
+ module SessionsController
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ layout "goodmin/login"
8
+ prepend_before_action :disable_authentication
9
+ end
10
+
11
+ def new
12
+ @admin_user = admin_user_class.new
13
+ end
14
+
15
+ def create
16
+ @admin_user = admin_user_class.find_by_login(admin_user_login)
17
+
18
+ if @admin_user && @admin_user.authenticate(admin_user_params[:password])
19
+ session[:admin_user_id] = @admin_user.id
20
+ redirect_to root_path, notice: t("goodmin.sessions.signed_in")
21
+ else
22
+ redirect_to new_session_path, alert: t("goodmin.sessions.failed_sign_in")
23
+ end
24
+ end
25
+
26
+ def destroy
27
+ session[:admin_user_id] = nil
28
+ redirect_to new_session_path, notice: t("goodmin.sessions.signed_out")
29
+ end
30
+
31
+ private
32
+
33
+ def admin_user_login
34
+ admin_user_params[admin_user_class.login_column]
35
+ end
36
+
37
+ def admin_user_params
38
+ params.require(admin_user_class.model_name.param_key.to_sym).permit(
39
+ admin_user_class.login_column,
40
+ :password,
41
+ :password_confirm
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,27 @@
1
+ module Goodmin
2
+ module Authentication
3
+ module User
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ has_secure_password
8
+
9
+ validates :password, length: { minimum: 8 }, allow_nil: true
10
+ end
11
+
12
+ def login
13
+ send(self.class.login_column)
14
+ end
15
+
16
+ module ClassMethods
17
+ def find_by_login(login)
18
+ find_by(login_column => login)
19
+ end
20
+
21
+ def login_column
22
+ raise NotImplementedError, "Must define the admin user login column"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ require "goodmin/authentication/sessions_controller"
2
+ require "goodmin/authentication/user"
3
+
4
+ module Goodmin
5
+ module Authentication
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_action :authenticate
10
+
11
+ helper_method :admin_user
12
+ helper_method :admin_user_signed_in?
13
+ end
14
+
15
+ def authenticate
16
+ return unless authentication_enabled?
17
+ return if admin_user_signed_in?
18
+
19
+ redirect_to new_session_path
20
+ end
21
+
22
+ def admin_user_class; end
23
+
24
+ def admin_user
25
+ return unless admin_user_class
26
+ return unless session[:admin_user_id]
27
+
28
+ @_admin_user ||= admin_user_class.find_by(id: session[:admin_user_id])
29
+ end
30
+
31
+ def admin_user_signed_in?
32
+ admin_user.present?
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ module Goodmin
2
+ module Authorization
3
+ class Policy
4
+ attr_reader :user, :record
5
+
6
+ def initialize(user, record, default: false)
7
+ @user = user
8
+ @record = record
9
+ @default = default
10
+ end
11
+
12
+ def index?
13
+ @default
14
+ end
15
+
16
+ def show?
17
+ @default
18
+ end
19
+
20
+ def new?
21
+ create?
22
+ end
23
+
24
+ def edit?
25
+ update?
26
+ end
27
+
28
+ def create?
29
+ @default
30
+ end
31
+
32
+ def update?
33
+ @default
34
+ end
35
+
36
+ def destroy?
37
+ @default
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,69 @@
1
+ require "pundit"
2
+ require "goodmin/authorization/policy"
3
+
4
+ module Goodmin
5
+ module Authorization
6
+ extend ActiveSupport::Concern
7
+
8
+ include Pundit::Authorization
9
+
10
+ included do
11
+ rescue_from Pundit::NotAuthorizedError do
12
+ render plain: "You are not authorized to do this", status: 403, layout: "goodmin/login"
13
+ end
14
+ end
15
+
16
+ def policy(record)
17
+ policies[record] ||= Pundit.policy!(pundit_user, namespaced_record(record))
18
+ end
19
+
20
+ def pundit_user
21
+ admin_user
22
+ end
23
+
24
+ def namespaced_record(record)
25
+ return record if controller_namespace_path.empty?
26
+
27
+ class_name = find_class_name(record)
28
+ if already_namespaced?(class_name)
29
+ record
30
+ else
31
+ controller_namespace_path.map(&:to_sym) << record
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # Borrowed from Pundit::PolicyFinder
38
+ def find_class_name(subject)
39
+ if subject.respond_to?(:model_name)
40
+ subject.model_name
41
+ elsif subject.class.respond_to?(:model_name)
42
+ subject.class.model_name
43
+ elsif subject.is_a?(Class)
44
+ subject
45
+ elsif subject.is_a?(Symbol)
46
+ subject.to_s.camelize
47
+ else
48
+ subject.class
49
+ end
50
+ end
51
+
52
+ def already_namespaced?(subject)
53
+ return false if controller_namespace_name.blank?
54
+
55
+ subject.to_s.start_with?("#{controller_namespace_name}::")
56
+ end
57
+
58
+ def controller_namespace_path
59
+ @_controller_namespace_path ||= begin
60
+ parts = controller_path.split("/")
61
+ parts.length > 1 ? parts.first(parts.length - 1) : []
62
+ end
63
+ end
64
+
65
+ def controller_namespace_name
66
+ @_controller_namespace_name ||= controller_namespace_path.map(&:camelize).join("::")
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,30 @@
1
+ module Goodmin
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Goodmin
4
+
5
+ initializer "goodmin.autoload_paths", before: :set_autoload_paths do |app|
6
+ goodmin_app_dir = app.root.join("app/goodmin")
7
+ if goodmin_app_dir.exist?
8
+ Rails.autoloaders.main.push_dir(goodmin_app_dir, namespace: Goodmin)
9
+ app.config.eager_load_paths << goodmin_app_dir.to_s
10
+ end
11
+ end
12
+
13
+ initializer "goodmin.assets" do |app|
14
+ if app.config.respond_to?(:assets)
15
+ app.config.assets.paths << root.join("app/assets/stylesheets")
16
+ app.config.assets.paths << root.join("app/javascript")
17
+ app.config.assets.paths << root.join("vendor/assets/javascripts")
18
+ end
19
+ end
20
+
21
+ initializer "goodmin.importmap", before: "importmap" do |app|
22
+ Goodmin.importmap.draw root.join("config/importmap.rb")
23
+ Goodmin.importmap.cache_sweeper watches: root.join("app/javascript")
24
+
25
+ ActiveSupport.on_load(:action_controller_base) do
26
+ before_action { Goodmin.importmap.cache_sweeper.execute_if_updated }
27
+ end
28
+ end
29
+ end
30
+ end