decidim-surveys 0.19.1 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/decidim/surveys/surveys.scss +20 -3
- data/app/controllers/decidim/surveys/admin/surveys_controller.rb +11 -0
- data/app/controllers/decidim/surveys/surveys_controller.rb +12 -1
- data/app/jobs/decidim/surveys/clean_survey_answers_job.rb +32 -0
- data/app/jobs/decidim/surveys/settings_change_job.rb +4 -0
- data/app/models/decidim/surveys/survey.rb +4 -0
- data/app/permissions/decidim/surveys/admin/permissions.rb +12 -6
- data/app/permissions/decidim/surveys/permissions.rb +1 -1
- data/app/queries/decidim/surveys/metrics/answers_metric_manage.rb +2 -8
- data/app/serializers/decidim/surveys/data_importer.rb +66 -0
- data/app/serializers/decidim/surveys/data_serializer.rb +46 -0
- data/app/types/decidim/surveys/survey_type.rb +15 -0
- data/app/types/decidim/surveys/surveys_type.rb +32 -0
- data/config/locales/am-ET.yml +1 -0
- data/config/locales/ar.yml +1 -0
- data/config/locales/bg-BG.yml +10 -0
- data/config/locales/bg.yml +10 -0
- data/config/locales/ca.yml +6 -0
- data/config/locales/cs.yml +6 -0
- data/config/locales/da-DK.yml +1 -0
- data/config/locales/da.yml +1 -0
- data/config/locales/de.yml +6 -0
- data/config/locales/el-GR.yml +1 -0
- data/config/locales/el.yml +59 -0
- data/config/locales/en.yml +6 -0
- data/config/locales/eo.yml +1 -0
- data/config/locales/es-MX.yml +6 -0
- data/config/locales/es-PY.yml +6 -0
- data/config/locales/es.yml +6 -0
- data/config/locales/et-EE.yml +1 -0
- data/config/locales/et.yml +1 -0
- data/config/locales/fi-plain.yml +6 -0
- data/config/locales/fi.yml +7 -1
- data/config/locales/fr-CA.yml +62 -0
- data/config/locales/fr.yml +6 -0
- data/config/locales/ga-IE.yml +1 -0
- data/config/locales/hr-HR.yml +1 -0
- data/config/locales/hr.yml +1 -0
- data/config/locales/hu.yml +3 -0
- data/config/locales/is-IS.yml +25 -0
- data/config/locales/is.yml +25 -0
- data/config/locales/it.yml +11 -7
- data/config/locales/ja-JP.yml +58 -0
- data/config/locales/ja.yml +60 -0
- data/config/locales/ko-KR.yml +1 -0
- data/config/locales/ko.yml +1 -0
- data/config/locales/lt-LT.yml +1 -0
- data/config/locales/lt.yml +1 -0
- data/config/locales/lv.yml +61 -0
- data/config/locales/mt-MT.yml +1 -0
- data/config/locales/mt.yml +1 -0
- data/config/locales/nl.yml +10 -4
- data/config/locales/no.yml +25 -0
- data/config/locales/om-ET.yml +1 -0
- data/config/locales/pl.yml +18 -12
- data/config/locales/pt-BR.yml +1 -1
- data/config/locales/pt.yml +27 -23
- data/config/locales/ro-RO.yml +62 -0
- data/config/locales/sk-SK.yml +63 -0
- data/config/locales/sk.yml +63 -0
- data/config/locales/sl.yml +8 -0
- data/config/locales/so-SO.yml +1 -0
- data/config/locales/sr-CS.yml +1 -0
- data/config/locales/sv.yml +5 -1
- data/config/locales/ti-ER.yml +1 -0
- data/config/locales/vi-VN.yml +1 -0
- data/config/locales/vi.yml +1 -0
- data/config/locales/zh-CN.yml +60 -0
- data/config/locales/zh-TW.yml +1 -0
- data/db/migrate/20200609090533_check_legacy_tables.rb +114 -0
- data/db/migrate/20200610090533_remove_survey_answer_choices.rb +7 -0
- data/db/migrate/20200610090650_remove_survey_answer_options.rb +7 -0
- data/db/migrate/20200610090725_remove_survey_answers.rb +7 -0
- data/db/migrate/20200610090845_remove_survey_questions.rb +7 -0
- data/db/migrate/20200610105927_remove_survey_columns.rb +10 -0
- data/lib/decidim/surveys/admin_engine.rb +10 -0
- data/lib/decidim/surveys/component.rb +38 -6
- data/lib/decidim/surveys/test/factories.rb +1 -1
- data/lib/decidim/surveys/version.rb +1 -1
- metadata +75 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 438c473b61d9bc07cad2c8e3ce3c6c56f900ae0a4aaade52db7dffbcb1e4a433
|
4
|
+
data.tar.gz: 182793a9e4e0fee42249e40ec2862f4a756344656f5010c055167c0477240559
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd718b0903ddd737e42ea62e71039e4fdc34bf7c5cc13444f8b1f4353a5d197dd0b95cbd20434d1c52cbefe6c74d82ed64fb590732fddbe6f1f1a17ea5df685d
|
7
|
+
data.tar.gz: 92a9f208813e602e656b27f7549da9aafbfb88da073f2d2280d5eddde519fd0756a95223f5860cdbb4f3c207406a0420e4e0dbac8a19f6b5ae32129485dab7c0
|
@@ -1,6 +1,10 @@
|
|
1
1
|
@import "decidim/forms/forms";
|
2
2
|
|
3
|
-
|
3
|
+
.answer-questionnaire{
|
4
|
+
label{
|
5
|
+
font-size: inherit;
|
6
|
+
}
|
7
|
+
|
4
8
|
.radio-button-collection,
|
5
9
|
.check-box-collection,
|
6
10
|
.sortable-check-box-collection{
|
@@ -15,8 +19,10 @@ form.answer-questionnaire{
|
|
15
19
|
}
|
16
20
|
}
|
17
21
|
|
18
|
-
|
19
|
-
font-weight:
|
22
|
+
.questionnaire-question{
|
23
|
+
font-weight: 600;
|
24
|
+
line-height: 1.4;
|
25
|
+
margin-bottom: .3em;
|
20
26
|
}
|
21
27
|
|
22
28
|
.help-text{
|
@@ -30,4 +36,15 @@ form.answer-questionnaire{
|
|
30
36
|
.last-sorted{
|
31
37
|
margin-bottom: 1rem;
|
32
38
|
}
|
39
|
+
|
40
|
+
&__steps{
|
41
|
+
font-size: .8rem;
|
42
|
+
}
|
43
|
+
|
44
|
+
&__submit{
|
45
|
+
display: flex;
|
46
|
+
align-items: baseline;
|
47
|
+
justify-content: space-between;
|
48
|
+
margin-top: 2rem;
|
49
|
+
}
|
33
50
|
}
|
@@ -6,11 +6,22 @@ module Decidim
|
|
6
6
|
# This controller allows the user to update a Page.
|
7
7
|
class SurveysController < Admin::ApplicationController
|
8
8
|
include Decidim::Forms::Admin::Concerns::HasQuestionnaire
|
9
|
+
include Decidim::Forms::Admin::Concerns::HasQuestionnaireAnswers
|
9
10
|
|
10
11
|
def questionnaire_for
|
11
12
|
survey
|
12
13
|
end
|
13
14
|
|
15
|
+
# Specify the public url from which the survey can be viewed and answered
|
16
|
+
def public_url
|
17
|
+
Decidim::EngineRouter.main_proxy(current_component).survey_path(survey)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Specify where to redirect after exporting a user response
|
21
|
+
def questionnaire_participant_answers_url(session_token)
|
22
|
+
Decidim::EngineRouter.admin_proxy(survey.component).show_survey_path(session_token: session_token)
|
23
|
+
end
|
24
|
+
|
14
25
|
private
|
15
26
|
|
16
27
|
def i18n_flashes_scope
|
@@ -5,9 +5,10 @@ module Decidim
|
|
5
5
|
# Exposes the survey resource so users can view and answer them.
|
6
6
|
class SurveysController < Decidim::Surveys::ApplicationController
|
7
7
|
include Decidim::Forms::Concerns::HasQuestionnaire
|
8
|
+
include Decidim::ComponentPathHelper
|
8
9
|
helper Decidim::Surveys::SurveyHelper
|
9
10
|
|
10
|
-
delegate :
|
11
|
+
delegate :allow_unregistered?, to: :current_settings
|
11
12
|
|
12
13
|
before_action :check_permissions
|
13
14
|
|
@@ -19,6 +20,16 @@ module Decidim
|
|
19
20
|
survey
|
20
21
|
end
|
21
22
|
|
23
|
+
protected
|
24
|
+
|
25
|
+
def allow_answers?
|
26
|
+
!current_component.published? || current_settings.allow_answers?
|
27
|
+
end
|
28
|
+
|
29
|
+
def form_path
|
30
|
+
main_component_path(current_component)
|
31
|
+
end
|
32
|
+
|
22
33
|
private
|
23
34
|
|
24
35
|
def i18n_flashes_scope
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
class CleanSurveyAnswersJob < ApplicationJob
|
6
|
+
def perform(_event_name, data)
|
7
|
+
@component = data[:resource]
|
8
|
+
return unless component&.manifest_name == "surveys"
|
9
|
+
|
10
|
+
@survey = Survey.find_by(component: component)
|
11
|
+
return unless survey&.questionnaire
|
12
|
+
|
13
|
+
case data[:event_class]
|
14
|
+
when "Decidim::ComponentPublishedEvent"
|
15
|
+
clean_answers
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :survey, :component
|
22
|
+
|
23
|
+
def clean_answers
|
24
|
+
return unless survey.clean_after_publish?
|
25
|
+
|
26
|
+
survey.questionnaire.answers.destroy_all
|
27
|
+
component.settings[:clean_after_publish] = false
|
28
|
+
component.save
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -42,6 +42,10 @@ module Decidim
|
|
42
42
|
!!current_settings[:allow_answers] == false &&
|
43
43
|
previous_settings[:allow_answers] == true
|
44
44
|
end
|
45
|
+
|
46
|
+
def clean_after_publish_changed?(previous_settings, current_settings)
|
47
|
+
current_settings[:clean_after_publish] != previous_settings[:clean_after_publish]
|
48
|
+
end
|
45
49
|
# rubocop:enable Style/DoubleNegation
|
46
50
|
end
|
47
51
|
end
|
@@ -7,13 +7,19 @@ module Decidim
|
|
7
7
|
def permissions
|
8
8
|
return permission_action unless user
|
9
9
|
|
10
|
-
return permission_action
|
10
|
+
return permission_action unless permission_action.scope == :admin
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
case permission_action.subject
|
13
|
+
when :questionnaire
|
14
|
+
case permission_action.action
|
15
|
+
when :export_answers, :update
|
16
|
+
permission_action.allow!
|
17
|
+
end
|
18
|
+
when :questionnaire_answers
|
19
|
+
case permission_action.action
|
20
|
+
when :index, :show, :export_response
|
21
|
+
permission_action.allow!
|
22
|
+
end
|
17
23
|
end
|
18
24
|
|
19
25
|
permission_action
|
@@ -4,7 +4,7 @@ module Decidim
|
|
4
4
|
module Surveys
|
5
5
|
class Permissions < Decidim::DefaultPermissions
|
6
6
|
def permissions
|
7
|
-
return permission_action unless user
|
7
|
+
return permission_action unless user || context[:current_settings].allow_unregistered?
|
8
8
|
|
9
9
|
return Decidim::Surveys::Admin::Permissions.new(user, permission_action, context).permissions if permission_action.scope == :admin
|
10
10
|
return permission_action if permission_action.scope != :public
|
@@ -9,9 +9,6 @@ module Decidim
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def save
|
12
|
-
return @registry if @registry
|
13
|
-
|
14
|
-
@registry = []
|
15
12
|
query.each do |key, results|
|
16
13
|
cumulative_value = results[:cumulative]
|
17
14
|
next if cumulative_value.zero?
|
@@ -23,10 +20,8 @@ module Decidim
|
|
23
20
|
participatory_space_type: space_type, participatory_space_id: space_id,
|
24
21
|
related_object_type: Decidim::Surveys::Survey.name, related_object_id: survey_id)
|
25
22
|
record.assign_attributes(cumulative: cumulative_value, quantity: quantity_value)
|
26
|
-
|
23
|
+
record.save!
|
27
24
|
end
|
28
|
-
@registry.each(&:save!)
|
29
|
-
@registry
|
30
25
|
end
|
31
26
|
|
32
27
|
private
|
@@ -49,8 +44,7 @@ module Decidim
|
|
49
44
|
end
|
50
45
|
|
51
46
|
def retrieve_surveys
|
52
|
-
|
53
|
-
Decidim::Surveys::Survey.where(component: components)
|
47
|
+
Decidim::Surveys::Survey.where(component: visible_component_ids_from_spaces(retrieve_participatory_spaces))
|
54
48
|
end
|
55
49
|
|
56
50
|
def retrieve_questionnaires(survey)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
# Importer for Surveys specific data (this is, its questionnaire).
|
6
|
+
class DataImporter < Decidim::Importers::Importer
|
7
|
+
def initialize(component)
|
8
|
+
@component = component
|
9
|
+
end
|
10
|
+
|
11
|
+
# Public: Creates a new Decidim::Surveys::Survey and Decidim::Forms::Questionnaire associated to the given +component+
|
12
|
+
# for each serialized survey object.
|
13
|
+
# It imports the whole tree of Survey->Questionnaire->questions->answer_options.
|
14
|
+
#
|
15
|
+
# serialized - The Hash of attributes for the Questionnaire and its relations.
|
16
|
+
# user - The +user+ that is performing this action
|
17
|
+
#
|
18
|
+
# Returns the ser.
|
19
|
+
def import(serialized, user)
|
20
|
+
ActiveRecord::Base.transaction do
|
21
|
+
# we duplicate so that we can delete without affecting the received Hash
|
22
|
+
serialized.dup.collect do |serialized_survey|
|
23
|
+
import_survey(serialized_survey, user)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Returns a persisted Survey instance build from +serialized_survey+.
|
31
|
+
def import_survey(serialized_survey, user)
|
32
|
+
serialized_survey = serialized_survey.with_indifferent_access
|
33
|
+
survey = build_survey(serialized_survey)
|
34
|
+
serialized_questionnaire = serialized_survey[:questionnaire]
|
35
|
+
serialized_questions = serialized_questionnaire.delete(:questions)
|
36
|
+
|
37
|
+
questionnaire = build_questionnaire(survey, serialized_questionnaire)
|
38
|
+
Decidim.traceability.perform_action!(:create, Decidim::Surveys::Survey, user) do
|
39
|
+
survey.save!
|
40
|
+
survey
|
41
|
+
end
|
42
|
+
import_questions(questionnaire, serialized_questions)
|
43
|
+
survey
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_survey(_serialized)
|
47
|
+
Survey.new(component: @component)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Builds a Decidim::Forms::Questionnaire with all its questions and answer_options.
|
51
|
+
def build_questionnaire(survey, serialized_questionnaire)
|
52
|
+
survey.build_questionnaire(serialized_questionnaire.except(:id, :published_at))
|
53
|
+
end
|
54
|
+
|
55
|
+
def import_questions(questionnaire, serialized_questions)
|
56
|
+
serialized_questions.each do |serialized_question|
|
57
|
+
serialized_answer_options = serialized_question.delete(:answer_options)
|
58
|
+
question = questionnaire.questions.create!(serialized_question.except(:id, :created_at, :updated_at))
|
59
|
+
serialized_answer_options.each do |serialized_answer_option|
|
60
|
+
question.answer_options.create!(serialized_answer_option.except(:id, :created_at, :updated_at))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
# This class serializes the specific data in each Survey.
|
6
|
+
# This is `Questionnaire->questions->answer_options` but not `answers`
|
7
|
+
# and `answer_choices`.
|
8
|
+
class DataSerializer < Decidim::Exporters::Serializer
|
9
|
+
# Returns: Array of Decidim::Forms::Questionnaire as a json hash,
|
10
|
+
# or nil if none exists.
|
11
|
+
def serialize
|
12
|
+
component = resource
|
13
|
+
surveys = Decidim::Surveys::Survey.where(component: component)
|
14
|
+
surveys.collect do |survey|
|
15
|
+
next if survey.questionnaire.nil?
|
16
|
+
|
17
|
+
json = serialize_survey(survey)
|
18
|
+
json.with_indifferent_access.merge(survey_id: survey.id)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def serialize_survey(survey)
|
23
|
+
questionnaire = survey.questionnaire
|
24
|
+
questionnaire_json = questionnaire.attributes.as_json
|
25
|
+
questionnaire_json[:questions] = serialize_questions(questionnaire.questions.order(:position))
|
26
|
+
json = survey.attributes.as_json
|
27
|
+
json[:questionnaire] = questionnaire_json
|
28
|
+
json
|
29
|
+
end
|
30
|
+
|
31
|
+
def serialize_questions(questions)
|
32
|
+
questions.collect do |question|
|
33
|
+
json = question.attributes.as_json
|
34
|
+
json[:answer_options] = serialize_answer_options(question.answer_options)
|
35
|
+
json
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def serialize_answer_options(answer_options)
|
40
|
+
answer_options.collect do |option|
|
41
|
+
option.attributes.as_json
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
SurveyType = GraphQL::ObjectType.define do
|
6
|
+
name "Survey"
|
7
|
+
description "A survey"
|
8
|
+
|
9
|
+
field :id, !types.ID, "The internal ID for this survey"
|
10
|
+
field :createdAt, Decidim::Core::DateTimeType, "The time this survey was created", property: :created_at
|
11
|
+
field :updatedAt, Decidim::Core::DateTimeType, "The time this survey was updated", property: :updated_at
|
12
|
+
field :questionnaire, Decidim::Forms::QuestionnaireType, "The questionnaire for this survey"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
SurveysType = GraphQL::ObjectType.define do
|
6
|
+
interfaces [-> { Decidim::Core::ComponentInterface }]
|
7
|
+
|
8
|
+
name "Surveys"
|
9
|
+
description "A surveys component of a participatory space."
|
10
|
+
|
11
|
+
connection :surveys, SurveyType.connection_type do
|
12
|
+
resolve ->(component, _args, _ctx) {
|
13
|
+
SurveysTypeHelper.base_scope(component).includes(:component)
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
field(:survey, SurveyType) do
|
18
|
+
argument :id, !types.ID
|
19
|
+
|
20
|
+
resolve ->(component, args, _ctx) {
|
21
|
+
SurveysTypeHelper.base_scope(component).find_by(id: args[:id])
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module SurveysTypeHelper
|
27
|
+
def self.base_scope(component)
|
28
|
+
Survey.where(component: component)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
am:
|
data/config/locales/ar.yml
CHANGED
data/config/locales/ca.yml
CHANGED
@@ -20,8 +20,13 @@ ca:
|
|
20
20
|
settings:
|
21
21
|
global:
|
22
22
|
announcement: Avís
|
23
|
+
clean_after_publish: Esborrar les respostes en publicar l'enquesta
|
24
|
+
scope_id: Àmbit
|
25
|
+
scopes_enabled: Àmbits habilitats
|
23
26
|
step:
|
24
27
|
allow_answers: Permetre respostes
|
28
|
+
allow_unregistered: Permet a usuàries no registrades contestar l'enquesta
|
29
|
+
allow_unregistered_help: Si s'activa, no caldrà iniciar sessió per a contestar l'enquesta. Això pot comportar que les dades siguin poc fiables i serà més vulnerable a atacs automatitzats. Feu-ho servir amb cura!
|
25
30
|
announcement: Avís
|
26
31
|
events:
|
27
32
|
surveys:
|
@@ -53,4 +58,5 @@ ca:
|
|
53
58
|
surveys:
|
54
59
|
answer:
|
55
60
|
invalid: S'ha produït un error en respondre l'enquesta.
|
61
|
+
spam_detected: Hi ha hagut un problema contestant el formulari. Potser has estat massa ràpid, ho pots tornar a intentar?
|
56
62
|
success: Enquesta resposta correctament.
|