decidim-core 0.27.0 → 0.27.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of decidim-core might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/cells/decidim/amendable/announcement_cell.rb +1 -1
- data/app/cells/decidim/card_m_cell.rb +1 -1
- data/app/cells/decidim/newsletter_templates/base_cell.rb +8 -0
- data/app/cells/decidim/newsletter_templates/basic_only_text/show.erb +4 -4
- data/app/cells/decidim/newsletter_templates/image_text_cta/show.erb +4 -4
- data/app/cells/decidim/upload_modal_cell.rb +12 -7
- data/app/commands/decidim/unendorse_resource.rb +1 -1
- data/app/controllers/decidim/devise/invitations_controller.rb +9 -2
- data/app/controllers/decidim/groups_controller.rb +5 -0
- data/app/controllers/decidim/last_activities_controller.rb +5 -2
- data/app/controllers/decidim/links_controller.rb +4 -2
- data/app/controllers/decidim/profiles_controller.rb +1 -1
- data/app/forms/decidim/account_form.rb +2 -2
- data/app/forms/decidim/amendable/form.rb +2 -1
- data/app/forms/decidim/registration_form.rb +2 -2
- data/app/forms/decidim/upload_validation_form.rb +51 -7
- data/app/helpers/decidim/icon_helper.rb +3 -3
- data/app/helpers/decidim/layout_helper.rb +12 -4
- data/app/helpers/decidim/newsletters_helper.rb +1 -0
- data/app/helpers/decidim/sanitize_helper.rb +1 -1
- data/app/mailers/decidim/newsletter_mailer.rb +10 -3
- data/app/mailers/decidim/notification_mailer.rb +1 -0
- data/app/mailers/decidim/notifications_digest_mailer.rb +1 -0
- data/app/models/decidim/newsletter.rb +28 -0
- data/app/models/decidim/user.rb +0 -2
- data/app/models/decidim/user_base_entity.rb +2 -0
- data/app/models/decidim/user_block.rb +2 -2
- data/app/models/decidim/user_group.rb +1 -1
- data/app/packs/src/decidim/editor/clipboard_override.js +143 -0
- data/app/packs/src/decidim/editor/clipboard_utilities.js +119 -0
- data/app/packs/src/decidim/editor/linebreak_module.js +0 -8
- data/app/packs/src/decidim/editor.js +9 -2
- data/app/packs/src/decidim/form_filter.component.test.js +148 -5
- data/app/packs/src/decidim/form_filter.js +26 -4
- data/app/packs/stylesheets/decidim/_editor.scss +129 -0
- data/app/packs/stylesheets/decidim/email.scss +7 -0
- data/app/packs/stylesheets/decidim/extras/_quill.scss +0 -6
- data/app/presenters/decidim/admin_log/user_group_presenter.rb +1 -1
- data/app/presenters/decidim/admin_log/user_moderation_presenter.rb +1 -1
- data/app/presenters/decidim/home_stats_presenter.rb +11 -4
- data/app/presenters/decidim/push_notification_presenter.rb +1 -1
- data/app/presenters/decidim/stats_presenter.rb +7 -8
- data/app/presenters/decidim/user_presenter.rb +9 -4
- data/app/queries/decidim/public_activities.rb +1 -0
- data/app/uploaders/decidim/application_uploader.rb +1 -1
- data/app/uploaders/decidim/avatar_uploader.rb +2 -2
- data/app/validators/etiquette_validator.rb +7 -3
- data/app/validators/file_content_type_validator.rb +103 -0
- data/app/validators/passthru_validator.rb +11 -0
- data/app/validators/uploader_content_type_validator.rb +22 -0
- data/app/views/decidim/messaging/conversations/_conversation.html.erb +1 -1
- data/app/views/decidim/newsletter_mailer/newsletter.html.erb +3 -3
- data/app/views/decidim/newsletters/show.html.erb +1 -1
- data/app/views/decidim/notification_mailer/event_received.html.erb +1 -1
- data/app/views/decidim/notifications_digest_mailer/_email_content.html.erb +1 -1
- data/app/views/layouts/decidim/_mailer_logo.html.erb +2 -2
- data/app/views/layouts/decidim/newsletter_base.html.erb +2 -2
- data/config/locales/ar.yml +5 -17
- data/config/locales/bg.yml +5 -17
- data/config/locales/ca.yml +20 -24
- data/config/locales/cs.yml +12 -17
- data/config/locales/de.yml +2 -18
- data/config/locales/el.yml +4 -18
- data/config/locales/en.yml +11 -15
- data/config/locales/es-MX.yml +13 -17
- data/config/locales/es-PY.yml +13 -17
- data/config/locales/es.yml +22 -26
- data/config/locales/eu.yml +28 -35
- data/config/locales/fi-plain.yml +11 -15
- data/config/locales/fi.yml +12 -16
- data/config/locales/fr-CA.yml +11 -18
- data/config/locales/fr.yml +11 -18
- data/config/locales/ga-IE.yml +0 -2
- data/config/locales/gl.yml +2 -17
- data/config/locales/gn-PY.yml +1 -0
- data/config/locales/hu.yml +4 -18
- data/config/locales/id-ID.yml +5 -17
- data/config/locales/is-IS.yml +0 -1
- data/config/locales/it.yml +1 -18
- data/config/locales/ja.yml +25 -29
- data/config/locales/ka-GE.yml +1 -0
- data/config/locales/lb.yml +0 -17
- data/config/locales/lo-LA.yml +1 -0
- data/config/locales/lt.yml +0 -17
- data/config/locales/lv.yml +5 -17
- data/config/locales/nl.yml +0 -17
- data/config/locales/no.yml +2 -19
- data/config/locales/pl.yml +4 -18
- data/config/locales/pt-BR.yml +0 -17
- data/config/locales/pt.yml +0 -17
- data/config/locales/ro-RO.yml +49 -16
- data/config/locales/ru.yml +5 -3
- data/config/locales/sk.yml +5 -17
- data/config/locales/sv.yml +22 -18
- data/config/locales/tr-TR.yml +4 -18
- data/config/locales/uk.yml +5 -1
- data/config/locales/zh-CN.yml +3 -17
- data/lib/decidim/api/types/localized_string_type.rb +9 -0
- data/lib/decidim/api/types/translated_field_type.rb +20 -5
- data/lib/decidim/asset_router/pipeline.rb +93 -0
- data/lib/decidim/asset_router/storage.rb +82 -0
- data/lib/decidim/asset_router.rb +3 -75
- data/lib/decidim/attribute_object/form.rb +9 -0
- data/lib/decidim/attributes/localized_date.rb +1 -1
- data/lib/decidim/attributes/time_with_zone.rb +5 -2
- data/lib/decidim/core/engine.rb +7 -5
- data/lib/decidim/core/test/factories.rb +13 -6
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/editor_shared_examples.rb +30 -0
- data/lib/decidim/core/test/shared_examples/mcell_examples.rb +17 -0
- data/lib/decidim/core/test.rb +2 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/dependency_resolver.rb +14 -8
- data/lib/decidim/file_validator_humanizer.rb +1 -1
- data/lib/decidim/form_builder.rb +11 -4
- data/lib/decidim/participatory_space_resourceable.rb +7 -1
- data/lib/decidim/resourceable.rb +5 -4
- data/lib/decidim/settings_manifest.rb +1 -1
- metadata +17 -8
- data/app/packs/images/decidim/gamification/badges/decidim_gamification_badges_invitations.svg +0 -1
@@ -10,4 +10,133 @@
|
|
10
10
|
margin-bottom: $paragraph-margin-bottom;
|
11
11
|
text-rendering: $paragraph-text-rendering;
|
12
12
|
}
|
13
|
+
|
14
|
+
ul,
|
15
|
+
ol{
|
16
|
+
margin-bottom: $paragraph-margin-bottom;
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
.ql-editor-display{
|
21
|
+
ul,
|
22
|
+
ol{
|
23
|
+
li{
|
24
|
+
list-style-type: none;
|
25
|
+
margin-bottom: .5rem;
|
26
|
+
|
27
|
+
&::before{
|
28
|
+
content: "\2022";
|
29
|
+
display: inline-block;
|
30
|
+
white-space: nowrap;
|
31
|
+
width: 1.2em;
|
32
|
+
}
|
33
|
+
|
34
|
+
&.ql-indent-1{
|
35
|
+
padding-left: 3em;
|
36
|
+
}
|
37
|
+
|
38
|
+
&.ql-indent-2{
|
39
|
+
padding-left: 6em;
|
40
|
+
}
|
41
|
+
|
42
|
+
&.ql-indent-3{
|
43
|
+
padding-left: 9em;
|
44
|
+
}
|
45
|
+
|
46
|
+
&.ql-indent-4{
|
47
|
+
padding-left: 12em;
|
48
|
+
}
|
49
|
+
|
50
|
+
&.ql-indent-5{
|
51
|
+
padding-left: 15em;
|
52
|
+
}
|
53
|
+
|
54
|
+
&.ql-indent-6{
|
55
|
+
padding-left: 18em;
|
56
|
+
}
|
57
|
+
|
58
|
+
&.ql-indent-7{
|
59
|
+
padding-left: 21em;
|
60
|
+
}
|
61
|
+
|
62
|
+
&.ql-indent-8{
|
63
|
+
padding-left: 24em;
|
64
|
+
}
|
65
|
+
|
66
|
+
&.ql-indent-9{
|
67
|
+
padding-left: 27em;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
ol{
|
73
|
+
li{
|
74
|
+
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
|
75
|
+
counter-increment: list-0;
|
76
|
+
|
77
|
+
&::before{ content: counter(list-0, decimal) ". "; }
|
78
|
+
|
79
|
+
&.ql-indent-1{
|
80
|
+
counter-increment: list-1;
|
81
|
+
counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
|
82
|
+
|
83
|
+
&::before{ content: counter(list-1, lower-alpha) ". "; }
|
84
|
+
}
|
85
|
+
|
86
|
+
&.ql-indent-2{
|
87
|
+
counter-increment: list-2;
|
88
|
+
counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
|
89
|
+
|
90
|
+
&::before{ content: counter(list-2, lower-roman) ". "; }
|
91
|
+
}
|
92
|
+
|
93
|
+
&.ql-indent-3{
|
94
|
+
counter-increment: list-3;
|
95
|
+
counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
|
96
|
+
|
97
|
+
&::before{ content: counter(list-3, decimal) ". "; }
|
98
|
+
}
|
99
|
+
|
100
|
+
&.ql-indent-4{
|
101
|
+
counter-increment: list-4;
|
102
|
+
counter-reset: list-5 list-6 list-7 list-8 list-9;
|
103
|
+
|
104
|
+
&::before{ content: counter(list-4, lower-alpha) ". "; }
|
105
|
+
}
|
106
|
+
|
107
|
+
&.ql-indent-5{
|
108
|
+
counter-increment: list-5;
|
109
|
+
counter-reset: list-6 list-7 list-8 list-9;
|
110
|
+
|
111
|
+
&::before{ content: counter(list-5, lower-roman) ". "; }
|
112
|
+
}
|
113
|
+
|
114
|
+
&.ql-indent-6{
|
115
|
+
counter-increment: list-6;
|
116
|
+
counter-reset: list-7 list-8 list-9;
|
117
|
+
|
118
|
+
&::before{ content: counter(list-6, decimal) ". "; }
|
119
|
+
}
|
120
|
+
|
121
|
+
&.ql-indent-7{
|
122
|
+
counter-increment: list-7;
|
123
|
+
counter-reset: list-8 list-9;
|
124
|
+
|
125
|
+
&::before{ content: counter(list-7, lower-alpha) ". "; }
|
126
|
+
}
|
127
|
+
|
128
|
+
&.ql-indent-8{
|
129
|
+
counter-increment: list-8;
|
130
|
+
counter-reset: list-9;
|
131
|
+
|
132
|
+
&::before{ content: counter(list-8, lower-roman) ". "; }
|
133
|
+
}
|
134
|
+
|
135
|
+
&.ql-indent-9{
|
136
|
+
counter-increment: list-9;
|
137
|
+
|
138
|
+
&::before{ content: counter(list-9, decimal) ". "; }
|
139
|
+
}
|
140
|
+
}
|
141
|
+
}
|
13
142
|
}
|
@@ -52,7 +52,7 @@ module Decidim
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def unreported_user
|
55
|
-
@unreported_user ||= Decidim::
|
55
|
+
@unreported_user ||= Decidim::UserBaseEntity.find_by(id: action_log.extra.dig("extra", "user_id"))
|
56
56
|
end
|
57
57
|
|
58
58
|
def has_diff?
|
@@ -42,12 +42,19 @@ module Decidim
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def component_stats(conditions)
|
45
|
+
stats = {}
|
45
46
|
Decidim.component_manifests.flat_map do |component|
|
46
|
-
component
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
component
|
48
|
+
.stats.except([:supports_count])
|
49
|
+
.filter(conditions)
|
50
|
+
.with_context(published_components)
|
51
|
+
.each do |name, data|
|
52
|
+
stats[name] ||= 0
|
53
|
+
stats[name] += data
|
54
|
+
end
|
50
55
|
end
|
56
|
+
|
57
|
+
stats.to_a
|
51
58
|
end
|
52
59
|
|
53
60
|
def published_components
|
@@ -15,18 +15,17 @@ module Decidim
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def statistics(grouped_stats)
|
18
|
-
statistics =
|
18
|
+
statistics = {}
|
19
|
+
|
19
20
|
grouped_stats.each do |_manifest_name, stats|
|
20
|
-
stats.
|
21
|
-
|
22
|
-
next unless (subindex % 3).zero?
|
23
|
-
next if stat[subindex + 2].zero?
|
21
|
+
stats.each do |_space_manifest, component_manifest, count|
|
22
|
+
next if count.zero?
|
24
23
|
|
25
|
-
|
26
|
-
|
24
|
+
statistics[component_manifest] ||= 0
|
25
|
+
statistics[component_manifest] += count
|
27
26
|
end
|
28
27
|
end
|
29
|
-
statistics
|
28
|
+
statistics.map { |key, number| { stat_title: key, stat_number: number } }
|
30
29
|
end
|
31
30
|
end
|
32
31
|
end
|
@@ -5,7 +5,6 @@ module Decidim
|
|
5
5
|
# Decorator for users
|
6
6
|
#
|
7
7
|
class UserPresenter < SimpleDelegator
|
8
|
-
include Rails.application.routes.mounted_helpers
|
9
8
|
include ActionView::Helpers::UrlHelper
|
10
9
|
include Decidim::TranslatableAttributes
|
11
10
|
|
@@ -27,7 +26,7 @@ module Decidim
|
|
27
26
|
def profile_url
|
28
27
|
return "" if respond_to?(:deleted?) && deleted?
|
29
28
|
|
30
|
-
decidim.profile_url(__getobj__.nickname
|
29
|
+
decidim.profile_url(__getobj__.nickname)
|
31
30
|
end
|
32
31
|
|
33
32
|
def avatar
|
@@ -36,13 +35,13 @@ module Decidim
|
|
36
35
|
|
37
36
|
def avatar_url(variant = nil)
|
38
37
|
return default_avatar_url if __getobj__.blocked?
|
39
|
-
return
|
38
|
+
return default_avatar_url unless avatar.attached?
|
40
39
|
|
41
40
|
avatar.path(variant: variant)
|
42
41
|
end
|
43
42
|
|
44
43
|
def default_avatar_url
|
45
|
-
|
44
|
+
avatar.default_url
|
46
45
|
end
|
47
46
|
|
48
47
|
def profile_path
|
@@ -77,5 +76,11 @@ module Decidim
|
|
77
76
|
def has_tooltip?
|
78
77
|
true
|
79
78
|
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def decidim
|
83
|
+
@decidim ||= Decidim::EngineRouter.new("decidim", { host: __getobj__.organization.host })
|
84
|
+
end
|
80
85
|
end
|
81
86
|
end
|
@@ -107,6 +107,7 @@ module Decidim
|
|
107
107
|
LEFT JOIN decidim_participatory_space_private_users AS #{manifest.name}_private_users
|
108
108
|
ON #{manifest.name}_private_users.privatable_to_type = '#{manifest.model_class_name}'
|
109
109
|
AND #{table}.id = #{manifest.name}_private_users.privatable_to_id
|
110
|
+
AND #{table}.private_space = 't'
|
110
111
|
SQL
|
111
112
|
).to_s
|
112
113
|
).where(
|
@@ -12,11 +12,11 @@ module Decidim
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def default_url(*)
|
15
|
-
|
15
|
+
AssetRouter::Pipeline.new("media/images/default-avatar.svg", model: model).url
|
16
16
|
end
|
17
17
|
|
18
18
|
def default_multiuser_url(*)
|
19
|
-
|
19
|
+
AssetRouter::Pipeline.new("media/images/avatar-multiuser.png", model: model).url
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -3,12 +3,16 @@
|
|
3
3
|
# This validator takes care of ensuring the validated content is
|
4
4
|
# respectful, doesn't use caps, and overall is meaningful.
|
5
5
|
class EtiquetteValidator < ActiveModel::EachValidator
|
6
|
+
include ActionView::Helpers::SanitizeHelper
|
7
|
+
|
6
8
|
def validate_each(record, attribute, value)
|
7
9
|
return if value.blank?
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
text_value = strip_tags(value)
|
12
|
+
|
13
|
+
validate_caps(record, attribute, text_value)
|
14
|
+
validate_marks(record, attribute, text_value)
|
15
|
+
validate_caps_first(record, attribute, text_value)
|
12
16
|
end
|
13
17
|
|
14
18
|
private
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# We need to define the validator in the `ActiveModel::Validations` namespace as
|
4
|
+
# this is what the `file_validators` uses and this is what gets priority over
|
5
|
+
# the root namespace class.
|
6
|
+
module ActiveModel
|
7
|
+
module Validations
|
8
|
+
# This validator provides content type validation for uploaded files. Extends
|
9
|
+
# the validator provided by the `file_validators` gem by fixing some weird
|
10
|
+
# messages in that validator.
|
11
|
+
class FileContentTypeValidator
|
12
|
+
private
|
13
|
+
|
14
|
+
alias mark_invalid_original mark_invalid unless private_method_defined?(:mark_invalid_original)
|
15
|
+
|
16
|
+
# This fixes the "weird" error messages such as "(?-mix:image\\/.*)" because
|
17
|
+
# this is the notation Regexp#to_s will return. Instead, we want to show the
|
18
|
+
# inner contents of the regular expressions.
|
19
|
+
#
|
20
|
+
# @see ActiveModel::Validations::FileContentTypeValidator#mark_invalid
|
21
|
+
def mark_invalid(record, attribute, error, option_types)
|
22
|
+
mark_invalid_original(record, attribute, error, invalid_types(option_types))
|
23
|
+
end
|
24
|
+
|
25
|
+
# Converts the configured content type matches to extensions if extensions are
|
26
|
+
# recognized for the specified content type and if not, the content type
|
27
|
+
# string itself.
|
28
|
+
#
|
29
|
+
# @param option_types [Array<Regexp, String>] Array of configured types.
|
30
|
+
# @param allowed_extensions [Array<String>, nil] Array of allowed extensions
|
31
|
+
# or nil if all extensions are "allowed" (in case we want to show the
|
32
|
+
# denylist error or hard code the types).
|
33
|
+
# @return [Array<String>] The invalid types as strings.
|
34
|
+
def invalid_types(option_types, allowed_extensions = nil)
|
35
|
+
extensions = []
|
36
|
+
content_types = []
|
37
|
+
option_types.each do |type|
|
38
|
+
# Since the original content types may have endings such as image/.*?, we
|
39
|
+
# want to replace the regexp pattern just with a star with the fallback
|
40
|
+
# option.
|
41
|
+
content_type = (type.try(:source) || type.to_s).gsub(".*?", "*")
|
42
|
+
if (exts = content_type_extensions(content_type, allowed_extensions))
|
43
|
+
extensions += exts
|
44
|
+
else
|
45
|
+
content_types << content_type
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
extensions.sort + content_types.sort
|
50
|
+
end
|
51
|
+
|
52
|
+
# Resolves the content type extensions through MiniMime or looks up all the
|
53
|
+
# possible extensions for wildcard content types such as `image/*`. For the
|
54
|
+
# wildcard extension types only those listed in the `allowed_extensions` will
|
55
|
+
# be returned.
|
56
|
+
#
|
57
|
+
# @param content_type [String] The content type, such as application/pdf or
|
58
|
+
# image/*.
|
59
|
+
# @param allowed_extensions [Array, nil] Array of allowed extensions
|
60
|
+
# or nil if all extensions are "allowed" (in case we want to show the
|
61
|
+
# denylist error or hard code the types).
|
62
|
+
# @return [Array<String>, nil] An array of the allowed extensions or nil when
|
63
|
+
# no extensions could be found.
|
64
|
+
def content_type_extensions(content_type, allowed_extensions = nil)
|
65
|
+
extensions =
|
66
|
+
if content_type.ends_with?("/*")
|
67
|
+
main_type = content_type.split("/")[0]
|
68
|
+
extensions_matching(%r{#{main_type}/.*})
|
69
|
+
else
|
70
|
+
extensions_matching(content_type)
|
71
|
+
end
|
72
|
+
return if extensions.count.zero?
|
73
|
+
return extensions unless allowed_extensions
|
74
|
+
|
75
|
+
extensions & allowed_extensions
|
76
|
+
end
|
77
|
+
|
78
|
+
# Looks up the extensions matching the content type lookup based on the
|
79
|
+
# MiniMime content types.
|
80
|
+
#
|
81
|
+
# @param content_type_lookup [String, Regexp] The lookup to be matched
|
82
|
+
# against.
|
83
|
+
# @return [Array<String>] The array of extensions.
|
84
|
+
def extensions_matching(content_type_lookup)
|
85
|
+
extensions = []
|
86
|
+
File.open(MiniMime::Configuration.ext_db_path).each do |line|
|
87
|
+
info = line.split(/\s+/)
|
88
|
+
next unless info[1].match?(content_type_lookup)
|
89
|
+
|
90
|
+
extensions << info[0]
|
91
|
+
end
|
92
|
+
|
93
|
+
extensions
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# This is just to make Zeitwerk happy. The actual validator that gets priority
|
100
|
+
# is the class above as all validators in the `ActiveModel::Validations`
|
101
|
+
# namespace will be used primarily and only if a matching validator is not found
|
102
|
+
# in that namespace, the ones at the root level are used.
|
103
|
+
class FileContentTypeValidator < ActiveModel::Validations::FileContentTypeValidator; end
|
@@ -62,9 +62,20 @@ class PassthruValidator < ActiveModel::EachValidator
|
|
62
62
|
elsif dummy.respond_to?(:organization=) && record.respond_to?(:organization)
|
63
63
|
dummy.organization = record.organization
|
64
64
|
end
|
65
|
+
validation_record_context(dummy, record)
|
65
66
|
dummy
|
66
67
|
end
|
67
68
|
|
69
|
+
def validation_record_context(dummy, record)
|
70
|
+
if dummy.is_a?(Decidim::Form)
|
71
|
+
dummy.with_context(
|
72
|
+
current_organization: record.try(:current_organization) || record.try(:ganization),
|
73
|
+
current_participatory_space: record.try(:current_participatory_space) || record.try(:participatory_space),
|
74
|
+
current_component: record.try(:current_component) || record.try(:component)
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
68
79
|
def target_validators(attribute)
|
69
80
|
target_class.validators_on(target_attribute(attribute))
|
70
81
|
end
|
@@ -41,4 +41,26 @@ class UploaderContentTypeValidator < ActiveModel::Validations::FileContentTypeVa
|
|
41
41
|
# rubocop: enable Metrics/CyclomaticComplexity
|
42
42
|
|
43
43
|
def check_validity!; end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# This fixes the "weird" error messages such as "(?-mix:image\\/.*)" because
|
48
|
+
# this is the notation Regexp#to_s will return. Instead, we want to show the
|
49
|
+
# inner contents of the regular expressions.
|
50
|
+
#
|
51
|
+
# @see ActiveModel::Validations::FileContentTypeValidator#mark_invalid
|
52
|
+
def mark_invalid(record, attribute, error, option_types)
|
53
|
+
allowed_extensions = nil
|
54
|
+
if error == :allowed_file_content_types
|
55
|
+
uploader = record.attached_uploader(attribute) if record.respond_to?(:attached_uploader)
|
56
|
+
allowed_extensions =
|
57
|
+
# Note that this may be a private method in some uploaders.
|
58
|
+
if uploader && uploader.respond_to?(:extension_allowlist, true)
|
59
|
+
uploader.send(:extension_allowlist)
|
60
|
+
else
|
61
|
+
Decidim.organization_settings(record).upload_allowed_file_extensions
|
62
|
+
end
|
63
|
+
end
|
64
|
+
mark_invalid_original(record, attribute, error, invalid_types(option_types, allowed_extensions))
|
65
|
+
end
|
44
66
|
end
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<%= image_tag present(current_user).avatar.default_multiuser_url, alt: t("decidim.author.avatar_multiuser") %>
|
10
10
|
<% end %>
|
11
11
|
</div>
|
12
|
-
<span class="text-medium mt-xs"><%= Date::ABBR_DAYNAMES[conversation.created_at.wday] %> <%= conversation.created_at
|
12
|
+
<span class="text-medium mt-xs"><%= Date::ABBR_DAYNAMES[conversation.created_at.wday] %> <%= l conversation.created_at, format: :decidim_short %></span>
|
13
13
|
</div>
|
14
14
|
</li>
|
15
15
|
<li class="card-data__item card--list__item card-data__item--expand absolutes">
|
@@ -1,16 +1,16 @@
|
|
1
1
|
<%= decidim_sanitize_newsletter cell.to_s %>
|
2
2
|
|
3
3
|
<% content_for :note do %>
|
4
|
-
<%== t ".note", organization_name: h(@organization.name), link:
|
4
|
+
<%== t ".note", organization_name: h(@organization.name), link: @newsletter.notifications_settings_url %>
|
5
5
|
<% end %>
|
6
6
|
|
7
7
|
<% content_for :unsubscribe do %>
|
8
|
-
<%== t ".unsubscribe", link:
|
8
|
+
<%== t ".unsubscribe", link: @newsletter.unsubscribe_newsletters_url(u: @encrypted_token) %>
|
9
9
|
<% end %>
|
10
10
|
|
11
11
|
<% content_for :see_on_website do %>
|
12
12
|
<center style="display: none">
|
13
13
|
<%== CGI.unescapeHTML truncate(cell.body, max_length: 50) %>
|
14
14
|
</center>
|
15
|
-
<%== t ".see_on_website", link:
|
15
|
+
<%== t ".see_on_website", link: @newsletter.url %>
|
16
16
|
<% end %>
|
@@ -5,7 +5,7 @@
|
|
5
5
|
newsletter: newsletter,
|
6
6
|
recipient_user: @user
|
7
7
|
) %>
|
8
|
-
<%=
|
8
|
+
<%= decidim_sanitize_newsletter @cell.to_s %>
|
9
9
|
|
10
10
|
<% content_for :note do %>
|
11
11
|
<%== t "note", scope: "decidim.newsletter_mailer.newsletter", organization_name: h(@organization.name), link: decidim.notifications_settings_url(host: @organization.host) %>
|
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
<% if @event_instance.resource_path.present? && @event_instance.resource_title.present? %>
|
6
6
|
<p class="email-button email-button__cta">
|
7
|
-
<%= link_to @event_instance.resource_title, @event_instance.resource_url %>
|
7
|
+
<%= link_to decidim_sanitize(@event_instance.resource_title, strip_tags: true), @event_instance.resource_url %>
|
8
8
|
</p>
|
9
9
|
<% end %>
|
10
10
|
|
@@ -5,7 +5,7 @@
|
|
5
5
|
</p>
|
6
6
|
<% if notification.resource_path.present? && notification.resource_title.present? %>
|
7
7
|
<p class="email-button email-button__cta">
|
8
|
-
<%= link_to notification.resource_title, notification.resource_url %>
|
8
|
+
<%= link_to decidim_sanitize(notification.resource_title, strip_tags: true), notification.resource_url %>
|
9
9
|
</p>
|
10
10
|
<% end %>
|
11
11
|
</div>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<% if organization %>
|
2
|
-
<% if
|
3
|
-
<% url =
|
2
|
+
<% if defined?(custom_url_for_mail_root) && custom_url_for_mail_root.present? %>
|
3
|
+
<% url = custom_url_for_mail_root %>
|
4
4
|
<% else %>
|
5
5
|
<% url = decidim.root_url(host: organization.host) %>
|
6
6
|
<% end %>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<%= stylesheet_pack_tag "decidim_email" %>
|
7
7
|
</head>
|
8
8
|
|
9
|
-
|
9
|
+
<%= content_tag :body, class: @preview ? "preview" : nil do %>
|
10
10
|
<!-- <style> -->
|
11
11
|
<table class="body">
|
12
12
|
<% if content_for?(:see_on_website) %>
|
@@ -42,5 +42,5 @@
|
|
42
42
|
</td>
|
43
43
|
</tr>
|
44
44
|
</table>
|
45
|
-
|
45
|
+
<% end %>
|
46
46
|
</html>
|
data/config/locales/ar.yml
CHANGED
@@ -305,6 +305,8 @@ ar:
|
|
305
305
|
title: غير مخوّل
|
306
306
|
unconfirmed:
|
307
307
|
title: تأكيد البريد الإلكتروني
|
308
|
+
show:
|
309
|
+
close_modal: إغلاق مشروط
|
308
310
|
block_user_mailer:
|
309
311
|
notify:
|
310
312
|
hello: مرحبًا،
|
@@ -654,18 +656,6 @@ ar:
|
|
654
656
|
how: كيف يمكنك كسب ذلك
|
655
657
|
page_description: الشارات عبارة عن اعتراف بإجراءات المشارك والتقدم في المنصة. عند البدء في الاكتشاف والمشاركة والتفاعل في المنصة ، ستربح شارات مختلفة. فيما يلي قائمة بالشارات وبعض الطرق التي يمكنك من خلالها كسبها.
|
656
658
|
title: شارات
|
657
|
-
invitations:
|
658
|
-
conditions:
|
659
|
-
- استخدم رابط "دعوة الأصدقاء" في صفحة المستخدم الخاصة بك لدعوة أصدقائك
|
660
|
-
- تخصيص ، إذا كنت تريد ، الرسالة التي ترسلها
|
661
|
-
- ستصل إلى أعلى مستوى عن طريق إرسال الدعوات وتسجيلها.
|
662
|
-
description: تُمنح هذه الشارة عند قيامك بدعوة بعض الأشخاص وقضاء بعض الوقت للتسجيل في %{organization_name} وتصبح مشاركًا. شكرًا لك على تعريف شخص %{organization_name} للآخرين والمساعدة في توسيع نطاق المجتمع!
|
663
|
-
description_another: قام هذا المشارك بدعوة %{score} شخصًا.
|
664
|
-
description_own: لقد قمت بدعوة %{score} شخصًا.
|
665
|
-
name: دعوات
|
666
|
-
next_level_in: دعوة %{score} أشخاص آخرين للوصول إلى المستوى التالي!
|
667
|
-
unearned_another: هذا المشارك لم يدع أي شخص حتى الآن
|
668
|
-
unearned_own: لم تقم بدعوة أي شخص حتى الآن.
|
669
659
|
description: الشارات عبارة عن اعتراف بإجراءات المشارك والتقدم في المنصة. عند البدء في الاكتشاف والمشاركة والتفاعل في المنصة ، ستربح شارات مختلفة.
|
670
660
|
level: المستوى %{level}
|
671
661
|
reached_top: لقد وصلت إلى المستوى الأعلى لهذه الشارة.
|
@@ -769,6 +759,7 @@ ar:
|
|
769
759
|
links:
|
770
760
|
warning:
|
771
761
|
cancel: إلغاء
|
762
|
+
close_modal: إغلاق مشروط
|
772
763
|
log:
|
773
764
|
base_presenter:
|
774
765
|
create: "%{user_name} تم الإنشاء %{resource_name}"
|
@@ -844,7 +835,6 @@ ar:
|
|
844
835
|
newsletter_mailer:
|
845
836
|
newsletter:
|
846
837
|
note: لقد تلقيت هذه الرسالة الإلكترونية لأنك مشترك في الرسائل الإخبارية على %{organization_name}. يمكنك تغيير الإعدادات الخاصة بك على هاتفك <a href="%{link}">الصفحة إخطارات</a>.
|
847
|
-
see_on_website: لا يمكن عرض هذا البريد الإلكتروني بشكل صحيح؟ اطلع عليه على <a href="%{link}" target="_blank">الموقع</a>.
|
848
838
|
unsubscribe: لإلغاء الاشتراك في تلقي هذا النوع من البريد الإلكتروني ، <a href="%{link}" target="_blank" class="unsubscribe">إلغاء الاشتراك</a>.
|
849
839
|
newsletter_templates:
|
850
840
|
image_text_cta_settings_form:
|
@@ -988,7 +978,9 @@ ar:
|
|
988
978
|
report:
|
989
979
|
content_original_language: لغة المحتوى الأصلية
|
990
980
|
hello: مرحبا %{name}،
|
981
|
+
reason: السبب
|
991
982
|
report_html: <p>تم الإبلاغ عن المحتوى <a href="%{url}">التالي</a> .</p>
|
983
|
+
see_report: معاينة التقرير
|
992
984
|
subject: تم الإبلاغ عن مورد
|
993
985
|
reports:
|
994
986
|
create:
|
@@ -1078,9 +1070,6 @@ ar:
|
|
1078
1070
|
pages_count: صفحات
|
1079
1071
|
participants_count: المشاركون
|
1080
1072
|
users_count: المشاركون
|
1081
|
-
user_activity:
|
1082
|
-
index:
|
1083
|
-
no_activities_warning: هذا المشارك لم يقم بأي نشاط حتى الآن.
|
1084
1073
|
user_conversations:
|
1085
1074
|
index:
|
1086
1075
|
add_users_placeholder: البحث…
|
@@ -1268,7 +1257,6 @@ ar:
|
|
1268
1257
|
not_locked: لم يكن مغلقا
|
1269
1258
|
too_many_marks: يستخدم الكثير من علامات الترقيم المتتالية (مثل! و؟)
|
1270
1259
|
too_much_caps: يستخدم عددًا كبيرًا جدًا من الأحرف الكبيرة (أكثر من 25٪ من النص)
|
1271
|
-
too_short: قصير جدًا (أقل من 15 حرفًا)
|
1272
1260
|
forms:
|
1273
1261
|
required: مطلوب
|
1274
1262
|
invisible_captcha:
|