decidim-forms 0.29.6 → 0.30.0.rc1

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/forms/step_navigation_cell.rb +18 -5
  3. data/app/commands/decidim/forms/admin/update_questionnaire.rb +1 -82
  4. data/app/commands/decidim/forms/admin/update_questions.rb +109 -0
  5. data/app/commands/decidim/forms/answer_questionnaire.rb +10 -3
  6. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +39 -3
  7. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire_answers.rb +2 -2
  8. data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +12 -4
  9. data/app/forms/decidim/forms/admin/display_condition_form.rb +1 -1
  10. data/app/forms/decidim/forms/admin/questionnaire_form.rb +0 -9
  11. data/app/forms/decidim/forms/admin/questions_form.rb +18 -0
  12. data/app/forms/decidim/forms/answer_choice_form.rb +5 -0
  13. data/app/forms/decidim/forms/answer_form.rb +1 -0
  14. data/app/forms/decidim/forms/questionnaire_form.rb +7 -0
  15. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_pagination_helper.rb +1 -1
  16. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +5 -5
  17. data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +5 -1
  18. data/app/models/decidim/forms/answer_choice.rb +0 -2
  19. data/app/models/decidim/forms/answer_option.rb +1 -1
  20. data/app/models/decidim/forms/question.rb +10 -0
  21. data/app/packs/entrypoints/decidim_forms.js +0 -1
  22. data/app/packs/entrypoints/decidim_forms_admin.js +6 -0
  23. data/app/packs/src/decidim/forms/admin/publish_answers_buttons.js +72 -0
  24. data/app/packs/src/decidim/forms/forms.js +4 -25
  25. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +1 -1
  26. data/app/presenters/decidim/forms/admin_log/question_presenter.rb +31 -0
  27. data/app/queries/decidim/forms/questionnaire_user_answers.rb +1 -1
  28. data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +1 -1
  29. data/app/views/decidim/forms/admin/questionnaires/_display_condition_template.html.erb +1 -1
  30. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +0 -89
  31. data/app/views/decidim/forms/admin/questionnaires/_matrix_row_template.html.erb +1 -1
  32. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +14 -4
  33. data/app/views/decidim/forms/admin/questionnaires/_questions_form.html.erb +80 -0
  34. data/app/views/decidim/forms/admin/questionnaires/_separator.html.erb +10 -3
  35. data/app/views/decidim/forms/admin/questionnaires/_title_and_description.html.erb +11 -1
  36. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +0 -20
  37. data/app/views/decidim/forms/admin/questionnaires/edit_questions.html.erb +47 -0
  38. data/app/views/decidim/forms/questionnaires/_answer.html.erb +1 -1
  39. data/app/views/decidim/forms/questionnaires/_questionnaire.html.erb +8 -1
  40. data/app/views/decidim/forms/questionnaires/answers/_files.html.erb +1 -1
  41. data/app/views/decidim/forms/questionnaires/answers/_long_answer.html.erb +1 -1
  42. data/app/views/decidim/forms/questionnaires/answers/_short_answer.html.erb +1 -1
  43. data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +12 -6
  44. data/app/views/decidim/forms/questionnaires/edit.html.erb +47 -0
  45. data/app/views/decidim/forms/questionnaires/show.html.erb +13 -2
  46. data/config/assets.rb +1 -2
  47. data/config/locales/ar.yml +18 -1
  48. data/config/locales/bg.yml +42 -2
  49. data/config/locales/ca.yml +59 -13
  50. data/config/locales/cs.yml +54 -8
  51. data/config/locales/de.yml +56 -10
  52. data/config/locales/el.yml +41 -2
  53. data/config/locales/en.yml +51 -5
  54. data/config/locales/es-MX.yml +61 -15
  55. data/config/locales/es-PY.yml +61 -15
  56. data/config/locales/es.yml +60 -14
  57. data/config/locales/eu.yml +58 -12
  58. data/config/locales/fi-plain.yml +56 -10
  59. data/config/locales/fi.yml +56 -10
  60. data/config/locales/fr-CA.yml +51 -13
  61. data/config/locales/fr.yml +51 -13
  62. data/config/locales/ga-IE.yml +9 -0
  63. data/config/locales/gl.yml +11 -1
  64. data/config/locales/hu.yml +14 -1
  65. data/config/locales/id-ID.yml +9 -1
  66. data/config/locales/it.yml +31 -3
  67. data/config/locales/ja.yml +13 -12
  68. data/config/locales/lb.yml +32 -1
  69. data/config/locales/lt.yml +41 -2
  70. data/config/locales/lv.yml +15 -1
  71. data/config/locales/nl.yml +29 -0
  72. data/config/locales/no.yml +33 -0
  73. data/config/locales/pl.yml +43 -2
  74. data/config/locales/pt-BR.yml +35 -0
  75. data/config/locales/pt.yml +31 -0
  76. data/config/locales/ro-RO.yml +50 -17
  77. data/config/locales/ru.yml +3 -2
  78. data/config/locales/sk.yml +12 -1
  79. data/config/locales/sl.yml +7 -0
  80. data/config/locales/sv.yml +17 -15
  81. data/config/locales/tr-TR.yml +27 -0
  82. data/config/locales/val-ES.yml +2 -0
  83. data/config/locales/zh-CN.yml +27 -0
  84. data/config/locales/zh-TW.yml +41 -2
  85. data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +1 -1
  86. data/db/migrate/20241122142230_add_survey_answers_published_at_to_questions.rb +7 -0
  87. data/decidim-forms.gemspec +1 -2
  88. data/lib/decidim/api/answer_option_type.rb +1 -1
  89. data/lib/decidim/api/question_type.rb +4 -4
  90. data/lib/decidim/api/questionnaire_type.rb +4 -4
  91. data/lib/decidim/exporters/form_pdf.rb +114 -11
  92. data/lib/decidim/forms/download_your_data_user_answers_serializer.rb +0 -4
  93. data/lib/decidim/forms/test/factories.rb +2 -2
  94. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +46 -7
  95. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +17 -17
  96. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +19 -21
  97. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +70 -94
  98. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +15 -18
  99. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +115 -247
  100. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +3 -29
  101. data/lib/decidim/forms/version.rb +1 -1
  102. data/lib/decidim/forms.rb +0 -1
  103. metadata +18 -33
  104. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.js +0 -1
  105. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.scss +0 -1
  106. data/app/packs/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +0 -69
  107. data/app/views/decidim/forms/admin/questionnaires/answers/export/_answer.html.erb +0 -31
  108. data/app/views/decidim/forms/admin/questionnaires/answers/export/pdf.html.erb +0 -13
  109. data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +0 -12
  110. data/config/initializers/wicked_pdf.rb +0 -26
  111. data/config/locales/ca-IT.yml +0 -192
  112. data/lib/decidim/exporters/form_pdf_controller_helper.rb +0 -13
@@ -9,6 +9,12 @@ sk:
9
9
  question_type: Typ
10
10
  questionnaire_question:
11
11
  mandatory: Povinné
12
+ errors:
13
+ models:
14
+ answer:
15
+ attributes:
16
+ choices:
17
+ missing: nie je kompletné
12
18
  decidim:
13
19
  forms:
14
20
  admin:
@@ -19,6 +25,7 @@ sk:
19
25
  questionnaires:
20
26
  answer_option:
21
27
  answer_option: Možnosť odpovede
28
+ free_text: Voľný text
22
29
  remove: Odstrániť
23
30
  statement: Prehlásenie
24
31
  edit:
@@ -32,9 +39,11 @@ sk:
32
39
  add_answer_option: Pridať možnosť odpovede
33
40
  any: Akékoľvek
34
41
  description: Popis
42
+ down: Nadol
35
43
  question: Otázka
36
44
  remove: Odstrániť
37
45
  statement: Prehlásenie
46
+ up: Hore
38
47
  update:
39
48
  invalid: Vyskytol sa problém s ukladaním formulára.
40
49
  question_types:
@@ -68,4 +77,6 @@ sk:
68
77
  user_answers_serializer:
69
78
  created_at: Odpovedané na
70
79
  id: ID odpovede
71
- question: Otázka
80
+ registered: Registrovaný
81
+ unregistered: Neregistrovaný
82
+ user_status: Status Užívateľa
@@ -4,3 +4,10 @@ sl:
4
4
  attributes:
5
5
  answer:
6
6
  body: Odgovor
7
+ decidim:
8
+ forms:
9
+ admin:
10
+ questionnaires:
11
+ answers:
12
+ actions:
13
+ export: Izvozi
@@ -40,7 +40,7 @@ sv:
40
40
  answer_option: Svarsalternativ
41
41
  free_text: Fritext
42
42
  remove: Ta bort
43
- statement: Titel
43
+ statement: Påstående
44
44
  answers:
45
45
  actions:
46
46
  back: Tillbaka till svar
@@ -78,12 +78,9 @@ sv:
78
78
  select_condition_type: Välj en typ av villkor
79
79
  edit:
80
80
  save: Spara
81
- title: Redigera frågeformulär
81
+ title: Redigera enkät
82
82
  form:
83
83
  add_question: Lägg till fråga
84
- add_separator: Lägg till avgränsare
85
- add_title_and_description: Lägg till titel och beskrivning
86
- already_answered_warning: Frågeformuläret har redan besvarats av användare och du kan inte längre ändra frågorna.
87
84
  collapse: Dölj alla frågor
88
85
  expand: Visa alla frågor
89
86
  preview: Förhandsgranska
@@ -91,29 +88,35 @@ sv:
91
88
  matrix_row:
92
89
  matrix_row: Rad
93
90
  remove: Ta bort
94
- statement: Titel
91
+ statement: Påstående
95
92
  question:
96
93
  add_answer_option: Lägg till svarsalternativ
97
94
  add_display_condition: Lägg till visningsvillkor
98
95
  add_display_condition_info: Spara formuläret för att konfigurera visningsvillkor
99
96
  add_matrix_row: Lägg till rad
100
- any: Valfritt
97
+ any: Någon
101
98
  collapse: Dölj
102
99
  description: Beskrivning
100
+ down: Ned
103
101
  expand: Visa
104
102
  question: Fråga
105
103
  remove: Ta bort
106
- statement: Titel
104
+ statement: Påstående
105
+ up: Upp
107
106
  separator:
108
- remove: Ta bort
107
+ down: Ner
108
+ remove: Radera
109
109
  separator: Avgränsare
110
+ up: Upp
110
111
  title_and_description:
111
112
  collapse: Dölj
112
113
  description: Beskrivning
114
+ down: Ner
113
115
  expand: Visa
114
- remove: Ta bort
116
+ remove: Radera
115
117
  title: Titel
116
118
  title_and_description: Titel och beskrivning
119
+ up: Upp
117
120
  update:
118
121
  invalid: Det gick inte att spara formuläret.
119
122
  success: Formuläret har sparats.
@@ -143,7 +146,7 @@ sv:
143
146
  questionnaires:
144
147
  answer:
145
148
  invalid: Det gick inte att besvara formuläret.
146
- max_choices_alert: Du har valt för många alternativ
149
+ max_choices_alert: För många alternativ har valts
147
150
  success: Formuläret har besvarats.
148
151
  question:
149
152
  max_choices: 'Högst antal val: %{n}'
@@ -171,19 +174,18 @@ sv:
171
174
  title: JavaScript är inaktiverat
172
175
  questionnaire_not_published:
173
176
  body: Formulär är ännu inte publicerat.
174
- tos_agreement: Genom att fortsätta godkänner du villkoren för anmälan
177
+ tos_agreement: Genom att delta godkänner du användarvillkoren
175
178
  step_navigation:
176
179
  show:
177
- are_you_sure: Efter att du har skickat in anmälan kan du inte ändra i den. Vill du fortsätta?
178
180
  back: Tillbaka
179
181
  continue: Fortsätt
180
- submit: Skicka
182
+ submit: Skicka in
181
183
  user_answers_serializer:
182
184
  body: Svar
183
185
  completion: Slutfört
184
186
  created_at: Besvarad
185
187
  id: Svars-ID
186
- ip_hash: IP-hash
188
+ ip_hash: IP Hash
187
189
  question: Fråga
188
190
  registered: Registrerad
189
191
  session_token: Identifierare för användare
@@ -4,11 +4,19 @@ tr:
4
4
  attributes:
5
5
  answer:
6
6
  body: Cevap
7
+ choices: Seçenekler
8
+ selected_choices: Seçilmiş seçenekler
7
9
  question:
8
10
  max_choices: Maksimum seçenek sayısı
9
11
  question_type: tip
10
12
  questionnaire_question:
11
13
  mandatory: Zorunlu
14
+ errors:
15
+ models:
16
+ answer:
17
+ attributes:
18
+ choices:
19
+ missing: tamamlanmadı
12
20
  decidim:
13
21
  forms:
14
22
  admin:
@@ -22,14 +30,22 @@ tr:
22
30
  show: Yanıtları göster
23
31
  answer_option:
24
32
  answer_option: Cevap seçeneği
33
+ free_text: Ücretsiz Metin
25
34
  remove: Kaldır
26
35
  statement: Beyan
27
36
  answers:
28
37
  actions:
38
+ back: Yanıtlara dön
39
+ export: Dışa aktar
29
40
  show: Cevapları göster
30
41
  empty: Henüz cevap bulunmuyor
42
+ export:
43
+ answer:
44
+ title: '#%{number} yanıt'
31
45
  export_response:
32
46
  title: survey_user_answers _%{token}
47
+ index:
48
+ title: "%{total} toplam yanıt"
33
49
  show:
34
50
  title: '%{number} cevap'
35
51
  display_condition:
@@ -71,13 +87,17 @@ tr:
71
87
  any: herhangi
72
88
  collapse: Daralt
73
89
  description: Açıklama
90
+ down: Aşağı
74
91
  expand: Genişlet
75
92
  question: Soru
76
93
  remove: Kaldır
77
94
  statement: Beyan
95
+ up: yukarı
78
96
  separator:
97
+ down: Aşağı
79
98
  remove: Kaldır
80
99
  separator: Ayraç
100
+ up: Yukarı
81
101
  update:
82
102
  invalid: Formu kaydederken bir sorun oluştu.
83
103
  success: Başarıyla kaydedildi.
@@ -94,6 +114,7 @@ tr:
94
114
  questionnaires:
95
115
  answer:
96
116
  invalid: Formu yanıtlarken bir sorun oluştu.
117
+ max_choices_alert: Çok fazla seçenek seçilmiş
97
118
  success: Form başarıyla cevaplandı.
98
119
  question:
99
120
  max_choices: 'Maksimum seçenek: %{n}'
@@ -125,6 +146,12 @@ tr:
125
146
  submit: Gönder
126
147
  user_answers_serializer:
127
148
  body: Cevap
149
+ completion: Tamamlanma
128
150
  created_at: Yanıtlandı
129
151
  id: Cevap kimliği
152
+ ip_hash: IP Hash
130
153
  question: Soru
154
+ registered: Kayıtlı
155
+ session_token: Kullanıcı tanımlayıcı
156
+ unregistered: Kayıtlı değil
157
+ user_status: Kullanıcı durumu
@@ -7,9 +7,11 @@ val:
7
7
  title_and_description:
8
8
  collapse: Redueix
9
9
  description: Descripció
10
+ down: Baixar
10
11
  expand: Expandeix
11
12
  remove: Elimina
12
13
  title: Títol
13
14
  title_and_description: Títol i descripció
15
+ up: Pujar
14
16
  question_types:
15
17
  title_and_description: Títol i descripció
@@ -4,11 +4,19 @@ zh-CN:
4
4
  attributes:
5
5
  answer:
6
6
  body: 答案
7
+ choices: 选择
8
+ selected_choices: 选定的选择
7
9
  question:
8
10
  max_choices: 选择的最大数量
9
11
  question_type: 类型
10
12
  questionnaire_question:
11
13
  mandatory: Mandatory
14
+ errors:
15
+ models:
16
+ answer:
17
+ attributes:
18
+ choices:
19
+ missing: 不完成
12
20
  decidim:
13
21
  forms:
14
22
  admin:
@@ -22,14 +30,22 @@ zh-CN:
22
30
  show: 显示回复
23
31
  answer_option:
24
32
  answer_option: 答案选项
33
+ free_text: 免费文本
25
34
  remove: 删除
26
35
  statement: 声明
27
36
  answers:
28
37
  actions:
38
+ back: 回到回应
39
+ export: 导出
29
40
  show: 显示答案
30
41
  empty: 尚无答案
42
+ export:
43
+ answer:
44
+ title: '回复 #%{number}'
31
45
  export_response:
32
46
  title: survey_user_answers_%{token}
47
+ index:
48
+ title: "%{total} 个回复总数"
33
49
  show:
34
50
  title: '答案 #%{number}'
35
51
  display_condition:
@@ -70,13 +86,17 @@ zh-CN:
70
86
  any: 任何
71
87
  collapse: 收起
72
88
  description: 描述
89
+ down: 向下
73
90
  expand: 扩展
74
91
  question: 问
75
92
  remove: 删除
76
93
  statement: 声明
94
+ up: 上移
77
95
  separator:
96
+ down: 向下
78
97
  remove: 删除
79
98
  separator: 分隔符
99
+ up: 上移
80
100
  update:
81
101
  invalid: 保存表单时出错。
82
102
  success: 表单保存成功。
@@ -93,6 +113,7 @@ zh-CN:
93
113
  questionnaires:
94
114
  answer:
95
115
  invalid: 回答表单时出现问题。
116
+ max_choices_alert: 选择了太多选项
96
117
  success: 表单回答成功。
97
118
  question:
98
119
  max_choices: '最大选择数: %{n}'
@@ -123,6 +144,12 @@ zh-CN:
123
144
  submit: 提交
124
145
  user_answers_serializer:
125
146
  body: 答案
147
+ completion: 完成
126
148
  created_at: 回答于
127
149
  id: 答案 ID
150
+ ip_hash: IP哈希
128
151
  question: 问
152
+ registered: 已注册
153
+ session_token: 用户标识符
154
+ unregistered: 未注册
155
+ user_status: 用户状态
@@ -4,6 +4,8 @@ zh-TW:
4
4
  attributes:
5
5
  answer:
6
6
  body: 回答
7
+ choices: 選項
8
+ selected_choices: 已選擇的選項
7
9
  question:
8
10
  max_choices: 選擇的最大數量
9
11
  question_type: 類別
@@ -12,8 +14,14 @@ zh-TW:
12
14
  max_characters: 字元限制(如果不需要限制,請設為0)
13
15
  errors:
14
16
  models:
15
- questionnaire:
16
- request_invalid: 處理請求時發生錯誤。請再試一次。
17
+ answer:
18
+ attributes:
19
+ add_documents:
20
+ needs_to_be_reattached: 需要重新附加
21
+ body:
22
+ too_long: 太長
23
+ choices:
24
+ missing: 尚未完成
17
25
  decidim:
18
26
  forms:
19
27
  admin:
@@ -27,14 +35,24 @@ zh-TW:
27
35
  show: 顯示回應
28
36
  answer_option:
29
37
  answer_option: 答案選項:
38
+ free_text: 免費文字
30
39
  remove: 移除
31
40
  statement: 聲明
32
41
  answers:
33
42
  actions:
43
+ back: 返回回覆
44
+ export: 匯出
45
+ next: 下一個 ›
46
+ previous: "‹ 上一篇"
34
47
  show: 顯示答案
35
48
  empty: 目前尚未回答
49
+ export:
50
+ answer:
51
+ title: '回應 #%{number}'
36
52
  export_response:
37
53
  title: 調查問卷使用者回答_%{token}
54
+ index:
55
+ title: "%{total} 個回應總數"
38
56
  show:
39
57
  title: '回答#%{number}'
40
58
  display_condition:
@@ -76,26 +94,35 @@ zh-TW:
76
94
  any: 任何
77
95
  collapse: 收回
78
96
  description: 說明
97
+ down: 向下
79
98
  expand: 展開
80
99
  question: 問題
81
100
  remove: 移除
82
101
  statement: 聲明
102
+ up: 往上
83
103
  separator:
104
+ down: 向下
84
105
  remove: 移除
85
106
  separator: 分隔線
107
+ up: 往上
86
108
  title_and_description:
87
109
  collapse: 收回
88
110
  description: 說明
111
+ down: 向下
89
112
  expand: 展開
90
113
  remove: 移除
91
114
  title: 標題
92
115
  title_and_description: 標題和描述
116
+ up: 往上
93
117
  update:
94
118
  invalid: 儲存表單時發生問題。
95
119
  success: 表單已成功儲存。
96
120
  admin_log:
97
121
  questionnaire:
98
122
  update: "%{user_name} 更新了 %{resource_name} 問卷模板"
123
+ errors:
124
+ answer:
125
+ body: 內容不能為空
99
126
  images:
100
127
  dimensions: "%{width} x %{height} 像素"
101
128
  processors:
@@ -111,14 +138,20 @@ zh-TW:
111
138
  single_option: 單選
112
139
  sorting: 排序中
113
140
  title_and_description: 標題和描述
141
+ questionnaire_answer_presenter:
142
+ download_attachment: 下載附件
114
143
  questionnaires:
115
144
  answer:
116
145
  invalid: 回答表單時出現問題
146
+ max_choices_alert: 選擇的項目太多了
117
147
  success: 表單已成功回答
118
148
  question:
119
149
  max_choices: '最多選擇數量: %{n}'
120
150
  show:
121
151
  answer_questionnaire:
152
+ already_have_an_account?: 已經有帳號了嗎?
153
+ are_you_new?: 新用戶?
154
+ sign_up_description: 建立參與者帳號以填寫問卷
122
155
  title: 回答表單
123
156
  current_step: 步驟%{step}
124
157
  of_total_steps: 的%{total_steps}
@@ -144,6 +177,12 @@ zh-TW:
144
177
  submit: 提交
145
178
  user_answers_serializer:
146
179
  body: 回答
180
+ completion: 完成
147
181
  created_at: 回答時間
148
182
  id: 回答 ID
183
+ ip_hash: IP Hash
149
184
  question: 問題
185
+ registered: 已註冊
186
+ session_token: 使用者識別碼
187
+ unregistered: 未註冊
188
+ user_status: 用戶狀態
@@ -10,7 +10,7 @@ class AddSessionTokenToDecidimFormsAnswers < ActiveRecord::Migration[5.2]
10
10
  add_index :decidim_forms_answers, :session_token
11
11
 
12
12
  Answer.find_each do |answer|
13
- answer.session_token = Digest::MD5.hexdigest("#{answer.decidim_user_id}-#{Rails.application.secrets.secret_key_base}")
13
+ answer.session_token = Digest::MD5.hexdigest("#{answer.decidim_user_id}-#{Rails.application.secret_key_base}")
14
14
  answer.save!
15
15
  end
16
16
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddSurveyAnswersPublishedAtToQuestions < ActiveRecord::Migration[7.0]
4
+ def change
5
+ add_column :decidim_forms_questions, :survey_answers_published_at, :datetime, index: true
6
+ end
7
+ end
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  "homepage_uri" => "https://decidim.org",
20
20
  "source_code_uri" => "https://github.com/decidim/decidim"
21
21
  }
22
- s.required_ruby_version = "~> 3.2.0"
22
+ s.required_ruby_version = "~> 3.3.0"
23
23
 
24
24
  s.name = "decidim-forms"
25
25
  s.summary = "Decidim forms"
@@ -33,7 +33,6 @@ Gem::Specification.new do |s|
33
33
  end
34
34
 
35
35
  s.add_dependency "decidim-core", Decidim::Forms.version
36
- s.add_dependency "wicked_pdf", "~> 2.1"
37
36
 
38
37
  s.add_development_dependency "decidim-admin", Decidim::Forms.version
39
38
  s.add_development_dependency "decidim-dev", Decidim::Forms.version
@@ -5,9 +5,9 @@ module Decidim
5
5
  class AnswerOptionType < Decidim::Api::Types::BaseObject
6
6
  description "An answer option for a multi-choice question in a questionnaire"
7
7
 
8
- field :id, GraphQL::Types::ID, "ID of this answer option", null: false
9
8
  field :body, Decidim::Core::TranslatedFieldType, "The text answer response option.", null: false
10
9
  field :free_text, GraphQL::Types::Boolean, "Whether if this answer accepts any free text from the user.", null: false
10
+ field :id, GraphQL::Types::ID, "ID of this answer option", null: false
11
11
  end
12
12
  end
13
13
  end
@@ -7,15 +7,15 @@ module Decidim
7
7
 
8
8
  implements Decidim::Core::TimestampsInterface
9
9
 
10
- field :id, GraphQL::Types::ID, "ID of this question", null: false
10
+ field :answer_options, [AnswerOptionType, { null: true }], "List of answer options in multi-choice questions.", null: false
11
11
  field :body, Decidim::Core::TranslatedFieldType, "What is being asked in this question.", null: false
12
12
  field :description, Decidim::Core::TranslatedFieldType, "The description of this question.", null: true
13
+ field :id, GraphQL::Types::ID, "ID of this question", null: false
13
14
  field :mandatory, GraphQL::Types::Boolean, "Whether if this question is mandatory.", null: false
14
- field :position, GraphQL::Types::Int, "Order position of the question in the questionnaire", null: true
15
- field :max_choices, GraphQL::Types::Int, "On questions with answer options, maximum number of choices the user has", null: true
16
15
  field :max_characters, GraphQL::Types::Int, "On questions with free text answers, maximum number of characters the answer can have (0 if no limit)", null: false
16
+ field :max_choices, GraphQL::Types::Int, "On questions with answer options, maximum number of choices the user has", null: true
17
+ field :position, GraphQL::Types::Int, "Order position of the question in the questionnaire", null: true
17
18
  field :question_type, GraphQL::Types::String, "Type of question.", null: true
18
- field :answer_options, [AnswerOptionType, { null: true }], "List of answer options in multi-choice questions.", null: false
19
19
  end
20
20
  end
21
21
  end
@@ -7,13 +7,13 @@ module Decidim
7
7
 
8
8
  implements Decidim::Core::TimestampsInterface
9
9
 
10
- field :id, GraphQL::Types::ID, "ID of this questionnaire", null: false
11
- field :title, Decidim::Core::TranslatedFieldType, "The title of this questionnaire.", null: false
12
10
  field :description, Decidim::Core::TranslatedFieldType, "The description of this questionnaire.", null: true
13
- field :tos, Decidim::Core::TranslatedFieldType, "The Terms of Service for this questionnaire.", null: true
14
- field :for_type, GraphQL::Types::String, "Type of entity using this questionnaire.", method: :questionnaire_for_type, null: true
15
11
  field :for_entity, QuestionnaireEntityInterface, "Entity using this questionnaire.", method: :questionnaire_for, null: true
12
+ field :for_type, GraphQL::Types::String, "Type of entity using this questionnaire.", method: :questionnaire_for_type, null: true
13
+ field :id, GraphQL::Types::ID, "ID of this questionnaire", null: false
16
14
  field :questions, [Decidim::Forms::QuestionType, { null: true }], "Questions in this questionnaire.", null: false
15
+ field :title, Decidim::Core::TranslatedFieldType, "The title of this questionnaire.", null: false
16
+ field :tos, Decidim::Core::TranslatedFieldType, "The Terms of Service for this questionnaire.", null: true
17
17
  end
18
18
  end
19
19
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "wicked_pdf"
4
-
5
3
  module Decidim
6
4
  module Exporters
7
5
  # Inherits from abstract PDF exporter. This class is used to set
@@ -9,25 +7,130 @@ module Decidim
9
7
  #
10
8
  class FormPDF < PDF
11
9
  # i18n-tasks-use t('decidim.admin.exports.formats.FormPDF')
10
+ include ActionView::Helpers::NumberHelper
11
+ include Decidim::Forms::Admin::QuestionnaireAnswersHelper
12
+
13
+ class QuestionnaireAnswerPresenter < Decidim::Forms::Admin::QuestionnaireAnswerPresenter
14
+ def choice(choice_hash)
15
+ render_body_for choice_hash
16
+ end
17
+
18
+ delegate :attachments, to: :answer
19
+
20
+ def body
21
+ return { string: answer.body } if answer.body.present?
22
+ return { attachments: answer.attachments } if answer.attachments.any?
23
+ return { string: "-" } if answer.choices.empty?
24
+
25
+ choices = answer.choices.map do |choice|
26
+ {
27
+ answer_option_body: choice.try(:answer_option).try(:translated_body),
28
+ choice_body: body_or_custom_body(choice)
29
+ }
30
+ end
31
+
32
+ return { single_option: choice(choices.first) } if answer.question.question_type == "single_option"
12
33
 
13
- def controller
14
- @controller ||= FormPDFControllerHelper.new
34
+ { multiple_option: choices.map { |c| choice(c) } }
35
+ end
15
36
  end
16
37
 
17
- def template
18
- "decidim/forms/admin/questionnaires/answers/export/pdf"
38
+ class ParticipantPresenter < Decidim::Forms::Admin::QuestionnaireParticipantPresenter
39
+ def answers
40
+ siblings.map { |answer| QuestionnaireAnswerPresenter.new(answer:) }
41
+ end
19
42
  end
20
43
 
21
- def layout
22
- "decidim/forms/admin/questionnaires/questionnaire_answers"
44
+ protected
45
+
46
+ def add_data!
47
+ composer.text(decidim_sanitize(translated_attribute(questionnaire.title), strip_tags: true), style: :h1)
48
+ composer.text(decidim_sanitize(translated_attribute(questionnaire.description), strip_tags: true), style: :description)
49
+ composer.text(I18n.t("title", scope: "decidim.forms.admin.questionnaires.answers.index", total: collection.count), style: :section_title)
50
+
51
+ local_collection = collection.map { |answer| ParticipantPresenter.new(participant: answer.first) }
52
+
53
+ local_collection.each_with_index do |record, index|
54
+ add_response_box(record, index)
55
+ end
23
56
  end
24
57
 
25
- def locals
58
+ def questionnaire = collection.first.first.questionnaire
59
+
60
+ def styles
26
61
  {
27
- questionnaire: collection.first.first.questionnaire,
28
- collection: collection.map { |answer| Decidim::Forms::Admin::QuestionnaireParticipantPresenter.new(participant: answer.first) }
62
+ h1: { font: bold_font, font_size: 18, margin: [0, 0, 10, 0] },
63
+ th: { font: bold_font, font_size: 10, margin: [0, 0, 10, 0] },
64
+ td: { font:, font_size: 10, margin: [0, 0, 10, 0] },
65
+ description: { font:, margin: [0, 0, 10, 0], font_size: 10 },
66
+ section_title: { font: bold_font, margin: [15, 0, 15, 0], font_size: 16 },
67
+ question_title: { font: bold_font, margin: [10, 0, 10, 0], font_size: 12 },
68
+ question_answer: { font:, margin: [10, 0, 10, 0], font_size: 10 },
69
+ file_info: { font:, margin: [10, 0, 10, 0], font_size: 8 },
70
+ link: { font:, margin: [10, 0, 10, 0], font_size: 10, underline: true }
29
71
  }
30
72
  end
73
+
74
+ def header
75
+ [
76
+ layout.text(I18n.t("session_token", scope: "decidim.forms.user_answers_serializer"), style: :th),
77
+ layout.text(I18n.t("user_status", scope: "decidim.forms.user_answers_serializer"), style: :th),
78
+ layout.text(I18n.t("ip_hash", scope: "decidim.forms.user_answers_serializer"), style: :th),
79
+ layout.text(I18n.t("completion", scope: "decidim.forms.user_answers_serializer"), style: :th),
80
+ layout.text(I18n.t("created_at", scope: "decidim.forms.user_answers_serializer"), style: :th)
81
+ ]
82
+ end
83
+
84
+ def add_user_data(record)
85
+ cells = [
86
+ layout.text(record.session_token, style: :td),
87
+ layout.text(record.status, style: :td),
88
+ layout.text(record.ip_hash, style: :td),
89
+ layout.text(display_percentage(record.completion), style: :td),
90
+ layout.text(I18n.l(record.answered_at, format: :short), style: :td)
91
+ ]
92
+ composer.table([cells], header: ->(_table) { [header] }, cell_style: { border: { width: 0 } })
93
+ end
94
+
95
+ def add_response_box(record, index)
96
+ composer.text(I18n.t("title", number: index + 1, scope: "decidim.forms.admin.questionnaires.answers.export.answer"), style: :section_title)
97
+ add_user_data(record)
98
+
99
+ record.answers.each do |answer|
100
+ composer.text(answer.question, style: :question_title)
101
+ add_answer_body(answer)
102
+ end
103
+ end
104
+
105
+ def add_answer_body(answer)
106
+ return composer.text(answer.body[:string], style: :question_answer) if answer.body.has_key?(:string)
107
+
108
+ if answer.attachments.any?
109
+ composer.list(marker_type: :disc) do |sub_list|
110
+ answer.attachments.each do |attachment|
111
+ sub_list.formatted_text(
112
+ [{ link: attachment.url,
113
+ text: translated_attribute(attachment.title).presence ||
114
+ I18n.t("download_attachment", scope: "decidim.forms.questionnaire_answer_presenter"),
115
+ style: :link },
116
+ " (#{attachment.file_type} #{number_to_human_size(attachment.file_size)})"],
117
+ style: :file_info
118
+ )
119
+ end
120
+ end
121
+ return
122
+ end
123
+
124
+ if answer.body.has_key?(:single_option)
125
+ composer.list(marker_type: :disc) do |sub_list|
126
+ sub_list.text(answer.body[:single_option], style: :question_answer)
127
+ end
128
+ else
129
+ composer.list(marker_type: :disc) do |sub_list|
130
+ answer.body[:multiple_option].map { |choice| sub_list.text(choice, style: :question_answer) }
131
+ end
132
+ end
133
+ end
31
134
  end
32
135
  end
33
136
  end