dscf-core 0.2.8 → 0.2.9
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.
- checksums.yaml +4 -4
- data/app/controllers/concerns/dscf/core/auditable_controller.rb +17 -17
- data/app/controllers/concerns/dscf/core/authenticatable.rb +3 -8
- data/app/controllers/concerns/dscf/core/authorizable.rb +66 -0
- data/app/controllers/concerns/dscf/core/common.rb +49 -19
- data/app/controllers/concerns/dscf/core/file_uploadable.rb +261 -0
- data/app/controllers/concerns/dscf/core/reviewable_controller.rb +31 -1
- data/app/controllers/dscf/core/addresses_controller.rb +0 -5
- data/app/controllers/dscf/core/application_controller.rb +3 -5
- data/app/controllers/dscf/core/auth_controller.rb +16 -11
- data/app/controllers/dscf/core/businesses_controller.rb +0 -5
- data/app/controllers/dscf/core/files_controller.rb +38 -0
- data/app/controllers/dscf/core/permissions_controller.rb +20 -0
- data/app/controllers/dscf/core/role_permissions_controller.rb +54 -0
- data/app/controllers/dscf/core/roles_controller.rb +30 -0
- data/app/controllers/dscf/core/user_roles_controller.rb +56 -0
- data/app/errors/dscf/core/file_upload_error.rb +9 -0
- data/app/jobs/dscf/core/audit_logger_job.rb +1 -3
- data/app/models/concerns/dscf/core/attachable.rb +403 -0
- data/app/models/dscf/core/file_attachment.rb +205 -0
- data/app/models/dscf/core/permission.rb +27 -0
- data/app/models/dscf/core/role.rb +8 -3
- data/app/models/dscf/core/role_permission.rb +18 -0
- data/app/models/dscf/core/user.rb +56 -0
- data/app/models/dscf/core/user_role.rb +23 -3
- data/app/policies/dscf/core/application_policy.rb +62 -0
- data/app/policies/dscf/core/business_policy.rb +29 -0
- data/app/policies/dscf/core/business_type_policy.rb +6 -0
- data/app/policies/dscf/core/permission_policy.rb +6 -0
- data/app/policies/dscf/core/role_policy.rb +25 -0
- data/app/serializers/dscf/core/attachment_serializer.rb +30 -0
- data/app/serializers/dscf/core/permission_serializer.rb +7 -0
- data/app/serializers/dscf/core/role_light_serializer.rb +7 -0
- data/app/serializers/dscf/core/role_permission_serializer.rb +9 -0
- data/app/serializers/dscf/core/role_serializer.rb +2 -2
- data/app/serializers/dscf/core/user_auth_serializer.rb +6 -2
- data/app/serializers/dscf/core/user_role_serializer.rb +2 -3
- data/app/services/dscf/core/file_storage/client.rb +210 -0
- data/app/services/dscf/core/file_storage/uploader.rb +127 -0
- data/app/services/dscf/core/file_storage.rb +44 -0
- data/app/services/dscf/core/token_service.rb +2 -1
- data/config/locales/en.yml +35 -2
- data/config/routes.rb +15 -0
- data/db/migrate/20250821185708_create_dscf_core_roles.rb +3 -1
- data/db/migrate/20250822054547_create_dscf_core_user_roles.rb +3 -1
- data/db/migrate/20260128000000_create_dscf_core_file_attachments.rb +48 -0
- data/db/migrate/20260304000001_create_dscf_core_permissions.rb +19 -0
- data/db/migrate/20260304000002_create_dscf_core_role_permissions.rb +11 -0
- data/lib/dscf/core/permission_registry.rb +58 -0
- data/lib/dscf/core/version.rb +1 -1
- data/lib/dscf/core.rb +12 -1
- data/spec/factories/dscf/core/permissions.rb +14 -0
- data/spec/factories/dscf/core/reviews.rb +0 -1
- data/spec/factories/dscf/core/role_permissions.rb +6 -0
- data/spec/factories/dscf/core/roles.rb +42 -2
- data/spec/factories/dscf/core/user_roles.rb +4 -2
- metadata +33 -3
|
@@ -4,22 +4,26 @@ module Dscf
|
|
|
4
4
|
skip_before_action :authenticate_user, only: %i[login signup refresh]
|
|
5
5
|
skip_before_action :validate_token_expiry, only: %i[login signup refresh]
|
|
6
6
|
skip_before_action :validate_device_consistency, only: %i[login signup refresh]
|
|
7
|
+
skip_before_action :authorize_action!, only: %i[login signup refresh]
|
|
7
8
|
|
|
8
9
|
def login
|
|
10
|
+
skip_authorization
|
|
9
11
|
user = AuthService.authenticate_user(params[:email_or_phone], params[:password])
|
|
10
12
|
|
|
11
13
|
if user&.valid_for_authentication?
|
|
12
14
|
tokens = sign_in(user, request)
|
|
15
|
+
user_with_includes = User.includes(roles: :permissions, user_profile: {}).find(user.id)
|
|
13
16
|
render_success(
|
|
14
17
|
"auth.success.login",
|
|
15
18
|
data: {
|
|
16
|
-
user:
|
|
19
|
+
user: user_with_includes,
|
|
17
20
|
access_token: tokens[:access_token],
|
|
18
21
|
refresh_token: tokens[:refresh_token].refresh_token
|
|
19
22
|
},
|
|
20
23
|
serializer_options: {
|
|
21
24
|
user: {
|
|
22
|
-
serializer: Dscf::Core::UserAuthSerializer
|
|
25
|
+
serializer: Dscf::Core::UserAuthSerializer,
|
|
26
|
+
include: [:user_profile, roles: [:permissions]]
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
)
|
|
@@ -29,6 +33,7 @@ module Dscf
|
|
|
29
33
|
end
|
|
30
34
|
|
|
31
35
|
def signup
|
|
36
|
+
skip_authorization
|
|
32
37
|
user = User.new(user_params)
|
|
33
38
|
|
|
34
39
|
return render_error("auth.errors.missing_email_or_phone") unless user.email.present? || user.phone.present?
|
|
@@ -36,15 +41,17 @@ module Dscf
|
|
|
36
41
|
ActiveRecord::Base.transaction do
|
|
37
42
|
if user.save
|
|
38
43
|
assign_default_role(user)
|
|
44
|
+
user_with_includes = User.includes(roles: :permissions, user_profile: {}).find(user.id)
|
|
39
45
|
render_success(
|
|
40
46
|
"auth.success.signup",
|
|
41
47
|
data: {
|
|
42
|
-
user:
|
|
48
|
+
user: user_with_includes
|
|
43
49
|
},
|
|
44
50
|
status: :created,
|
|
45
51
|
serializer_options: {
|
|
46
52
|
user: {
|
|
47
|
-
serializer: Dscf::Core::UserAuthSerializer
|
|
53
|
+
serializer: Dscf::Core::UserAuthSerializer,
|
|
54
|
+
include: [:user_profile, roles: [:permissions]]
|
|
48
55
|
}
|
|
49
56
|
}
|
|
50
57
|
)
|
|
@@ -64,20 +71,23 @@ module Dscf
|
|
|
64
71
|
end
|
|
65
72
|
|
|
66
73
|
def me
|
|
74
|
+
user = User.includes(roles: :permissions, user_profile: {}).find(current_user.id)
|
|
67
75
|
render_success(
|
|
68
76
|
"auth.success.me",
|
|
69
77
|
data: {
|
|
70
|
-
user:
|
|
78
|
+
user: user
|
|
71
79
|
},
|
|
72
80
|
serializer_options: {
|
|
73
81
|
user: {
|
|
74
|
-
serializer: Dscf::Core::UserAuthSerializer
|
|
82
|
+
serializer: Dscf::Core::UserAuthSerializer,
|
|
83
|
+
include: [:user_profile, roles: [:permissions]]
|
|
75
84
|
}
|
|
76
85
|
}
|
|
77
86
|
)
|
|
78
87
|
end
|
|
79
88
|
|
|
80
89
|
def refresh
|
|
90
|
+
skip_authorization
|
|
81
91
|
new_tokens = refresh_token
|
|
82
92
|
if new_tokens
|
|
83
93
|
render_success(
|
|
@@ -115,11 +125,6 @@ module Dscf
|
|
|
115
125
|
|
|
116
126
|
UserRole.create!(user: user, role: role)
|
|
117
127
|
end
|
|
118
|
-
|
|
119
|
-
def authentication_required?
|
|
120
|
-
# Skip authentication for login, signup, and refresh endpoints
|
|
121
|
-
%w[login signup refresh].exclude?(action_name)
|
|
122
|
-
end
|
|
123
128
|
end
|
|
124
129
|
end
|
|
125
130
|
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dscf
|
|
4
|
+
module Core
|
|
5
|
+
# Controller for serving file attachments from MinIO storage
|
|
6
|
+
# Provides download endpoints for files uploaded via the Attachable concern
|
|
7
|
+
#
|
|
8
|
+
# @example Download a file
|
|
9
|
+
# GET /dscf/core/files/:file_key
|
|
10
|
+
# GET /dscf/core/files/:file_key?download=true # Force download
|
|
11
|
+
#
|
|
12
|
+
class FilesController < ApplicationController
|
|
13
|
+
include Dscf::Core::FileUploadable
|
|
14
|
+
|
|
15
|
+
# Skip authentication for file downloads (files are accessed by file_key which acts as a token)
|
|
16
|
+
# Override this in your app if you need authenticated file access
|
|
17
|
+
skip_before_action :authenticate_request!, only: [:show], raise: false
|
|
18
|
+
|
|
19
|
+
# GET /dscf/core/files/:file_key
|
|
20
|
+
# Serves a file from MinIO storage
|
|
21
|
+
def show
|
|
22
|
+
attachment = FileAttachment.find_by(file_key: params[:file_key])
|
|
23
|
+
|
|
24
|
+
unless attachment
|
|
25
|
+
render json: {success: false, error: "File not found"}, status: :not_found
|
|
26
|
+
return
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
disposition = params[:download].present? ? "attachment" : "inline"
|
|
30
|
+
|
|
31
|
+
send_attachment(
|
|
32
|
+
attachment,
|
|
33
|
+
disposition: disposition
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Core
|
|
3
|
+
class PermissionsController < ApplicationController
|
|
4
|
+
include Dscf::Core::Common
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def allowed_order_columns
|
|
9
|
+
%w[id code resource action engine active created_at updated_at]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def default_serializer_includes
|
|
13
|
+
{
|
|
14
|
+
index: [],
|
|
15
|
+
show: []
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Core
|
|
3
|
+
class RolePermissionsController < ApplicationController
|
|
4
|
+
before_action :set_role
|
|
5
|
+
before_action :require_permissions_manage!
|
|
6
|
+
before_action :set_role_permission, only: [:destroy]
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
@clazz = Dscf::Core::RolePermission
|
|
10
|
+
render_success(data: @role.permissions)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def create
|
|
14
|
+
@clazz = Dscf::Core::RolePermission
|
|
15
|
+
role_permission = Dscf::Core::RolePermission.new(
|
|
16
|
+
role: @role,
|
|
17
|
+
permission_id: params[:permission_id]
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
if role_permission.save
|
|
21
|
+
render_success(data: role_permission, status: :created)
|
|
22
|
+
else
|
|
23
|
+
render_error(errors: role_permission.errors.full_messages[0],
|
|
24
|
+
status: :unprocessable_entity)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def destroy
|
|
29
|
+
@clazz = Dscf::Core::RolePermission
|
|
30
|
+
@role_permission.destroy
|
|
31
|
+
render_success
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def set_role
|
|
37
|
+
@role = Dscf::Core::Role.find(params[:role_id])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def set_role_permission
|
|
41
|
+
@role_permission = Dscf::Core::RolePermission.find_by!(
|
|
42
|
+
role: @role,
|
|
43
|
+
permission_id: params[:id]
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def require_permissions_manage!
|
|
48
|
+
return if current_user.super_admin? || current_user.has_permission?("permissions.manage")
|
|
49
|
+
|
|
50
|
+
render_error("errors.unauthorized", status: :forbidden)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Core
|
|
3
|
+
class RolesController < ApplicationController
|
|
4
|
+
include Dscf::Core::Common
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def model_params
|
|
9
|
+
params.require(:role).permit(:code, :name, :description, :active)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def eager_loaded_associations
|
|
13
|
+
[:permissions]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def allowed_order_columns
|
|
17
|
+
%w[id code name active created_at updated_at]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def default_serializer_includes
|
|
21
|
+
{
|
|
22
|
+
index: [:permissions],
|
|
23
|
+
show: [:permissions],
|
|
24
|
+
create: [:permissions],
|
|
25
|
+
update: [:permissions]
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Core
|
|
3
|
+
class UserRolesController < ApplicationController
|
|
4
|
+
before_action :set_target_user
|
|
5
|
+
before_action :require_roles_assign!
|
|
6
|
+
before_action :set_user_role, only: [:destroy]
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
@clazz = Dscf::Core::UserRole
|
|
10
|
+
user_roles = @target_user.user_roles.includes(:role)
|
|
11
|
+
render_success(data: user_roles)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def create
|
|
15
|
+
@clazz = Dscf::Core::UserRole
|
|
16
|
+
user_role = Dscf::Core::UserRole.new(
|
|
17
|
+
user: @target_user,
|
|
18
|
+
role_id: params[:role_id],
|
|
19
|
+
assigned_by: current_user
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
if user_role.save
|
|
23
|
+
render_success(data: user_role, status: :created)
|
|
24
|
+
else
|
|
25
|
+
render_error(errors: user_role.errors.full_messages[0],
|
|
26
|
+
status: :unprocessable_entity)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def destroy
|
|
31
|
+
@clazz = Dscf::Core::UserRole
|
|
32
|
+
@user_role.destroy
|
|
33
|
+
render_success
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def set_target_user
|
|
39
|
+
@target_user = Dscf::Core::User.find(params[:user_id])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def set_user_role
|
|
43
|
+
@user_role = Dscf::Core::UserRole.find_by!(
|
|
44
|
+
user: @target_user,
|
|
45
|
+
role_id: params[:id]
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def require_roles_assign!
|
|
50
|
+
return if current_user.super_admin? || current_user.has_permission?("roles.assign")
|
|
51
|
+
|
|
52
|
+
render_error("errors.unauthorized", status: :forbidden)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -226,10 +226,8 @@ module Dscf
|
|
|
226
226
|
action: "updated",
|
|
227
227
|
changes: record_changes
|
|
228
228
|
}
|
|
229
|
-
end
|
|
230
229
|
|
|
231
|
-
|
|
232
|
-
before_map.each do |id, before_rec|
|
|
230
|
+
# Detect deleted records (in before but not in after)
|
|
233
231
|
next if after_map[id]
|
|
234
232
|
|
|
235
233
|
# Convert attributes to change format (old: value, new: nil)
|