decidim-forms 0.31.8 → 0.32.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.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/app/cells/decidim/forms/step_navigation_cell.rb +1 -2
- data/app/commands/decidim/forms/response_questionnaire.rb +3 -3
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +22 -39
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire_responses.rb +2 -4
- data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +1 -5
- data/app/forms/decidim/forms/questionnaire_form.rb +1 -1
- data/app/forms/decidim/forms/response_form.rb +7 -7
- data/app/models/decidim/forms/question.rb +2 -2
- data/app/models/decidim/forms/response.rb +1 -1
- data/app/packs/src/decidim/forms/admin/collapsible_questions.js +10 -0
- data/app/packs/src/decidim/forms/display_conditions.component.js +0 -27
- data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/edit_questions.html.erb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/responses/index.html.erb +3 -1
- data/app/views/decidim/forms/admin/questionnaires/responses/show.html.erb +3 -1
- data/app/views/decidim/forms/questionnaires/_questionnaire.html.erb +2 -2
- data/app/views/decidim/forms/questionnaires/responses/_files.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/show.html.erb +1 -1
- data/config/locales/ar.yml +0 -4
- data/config/locales/bg.yml +0 -4
- data/config/locales/ca-IT.yml +5 -5
- data/config/locales/ca.yml +5 -5
- data/config/locales/cs.yml +3 -4
- data/config/locales/de.yml +2 -5
- data/config/locales/el.yml +0 -4
- data/config/locales/en.yml +3 -2
- data/config/locales/es-MX.yml +4 -4
- data/config/locales/es-PY.yml +4 -4
- data/config/locales/es.yml +3 -3
- data/config/locales/eu.yml +14 -14
- data/config/locales/fi-plain.yml +4 -4
- data/config/locales/fi.yml +3 -3
- data/config/locales/fr-CA.yml +4 -6
- data/config/locales/fr.yml +4 -6
- data/config/locales/ga-IE.yml +0 -1
- data/config/locales/gl.yml +0 -171
- data/config/locales/hu.yml +0 -4
- data/config/locales/id-ID.yml +0 -4
- data/config/locales/it.yml +0 -4
- data/config/locales/ja.yml +3 -3
- data/config/locales/kaa.yml +0 -1
- data/config/locales/lb.yml +0 -4
- data/config/locales/lt.yml +0 -4
- data/config/locales/lv.yml +0 -4
- data/config/locales/nl.yml +0 -4
- data/config/locales/no.yml +0 -4
- data/config/locales/pl.yml +0 -4
- data/config/locales/pt-BR.yml +3 -4
- data/config/locales/pt.yml +0 -4
- data/config/locales/ro-RO.yml +0 -4
- data/config/locales/ru.yml +0 -4
- data/config/locales/sk.yml +0 -186
- data/config/locales/sv.yml +3 -3
- data/config/locales/tr-TR.yml +0 -4
- data/config/locales/val-ES.yml +0 -1
- data/config/locales/zh-CN.yml +0 -4
- data/config/locales/zh-TW.yml +0 -4
- data/decidim-forms.gemspec +6 -8
- data/lib/decidim/api/questionnaire_entity_interface.rb +1 -0
- data/lib/decidim/forms/download_your_data_user_responses_serializer.rb +1 -0
- data/lib/decidim/forms/test/factories.rb +9 -5
- data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +23 -23
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +1 -1
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +4 -9
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +1 -1
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +9 -11
- data/lib/decidim/forms/version.rb +1 -1
- metadata +10 -18
- data/app/packs/src/decidim/forms/display_conditions.component.test.js +0 -142
- data/app/packs/src/decidim/forms/display_conditions_hidden_responses.test.js +0 -224
- data/db/data/20260616144141_rename_answers_to_responses.rb +0 -31
- data/lib/decidim/forms/test/shared_examples/questionnaire_admin_access.rb +0 -95
- data/lib/decidim/forms/test/shared_examples/questionnaire_admin_controller_permissions.rb +0 -41
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-relative-import-paths/no-relative-import-paths, id-length */
|
|
2
|
-
//
|
|
3
|
-
// Covers what happens to a hidden question's response, for the two question types
|
|
4
|
-
// the display-conditions component cannot clear by hand: `files` (its response
|
|
5
|
-
// lives in UploadModal's markup) and `sorting` (hidden fields only).
|
|
6
|
-
//
|
|
7
|
-
// On the clearAnswers() implementation, the three cases about an already-saved
|
|
8
|
-
// attachment fail: its preview and hidden add_attachments field are removed, and
|
|
9
|
-
// showQuestion() never puts them back. The other two pass there as well, and show
|
|
10
|
-
// why the selector was inconsistent: a file uploaded in the current session, and a
|
|
11
|
-
// sorting question, were never cleared at all.
|
|
12
|
-
//
|
|
13
|
-
// The fixture reproduces the markup actually rendered to participants:
|
|
14
|
-
// decidim-core/app/cells/decidim/upload_modal/files.erb
|
|
15
|
-
// decidim-core/app/cells/decidim/upload_modal/modal.erb
|
|
16
|
-
// decidim-forms/app/views/decidim/forms/questionnaires/responses/_files.html.erb
|
|
17
|
-
// decidim-forms/app/views/decidim/forms/questionnaires/responses/_sorting.html.erb
|
|
18
|
-
// and drives it through the real initializeUploadFields() and
|
|
19
|
-
// createDisplayConditions(), so no behaviour is stubbed.
|
|
20
|
-
//
|
|
21
|
-
// Run with: npx jest decidim-forms/app/packs/src/decidim/forms/display_conditions_hidden_responses.test.js
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
import $ from "jquery";
|
|
25
|
-
import createDisplayConditions from "./display_conditions.component";
|
|
26
|
-
import { initializeUploadFields } from "src/decidim/direct_uploads/upload_field";
|
|
27
|
-
|
|
28
|
-
const MODAL_ID = "modal-qfile";
|
|
29
|
-
// Raw JSON because the keys are the snake_case ones upload_modal/modal.erb emits.
|
|
30
|
-
const LOCALES = `{
|
|
31
|
-
"error": "error", "title_required": "title required", "filename": "filename",
|
|
32
|
-
"file_size_too_large": "too large", "remove": "remove", "title": "title",
|
|
33
|
-
"uploaded": "uploaded", "validating": "validating", "validation_error": "validation error"
|
|
34
|
-
}`;
|
|
35
|
-
const UPLOAD_OPTS = JSON.stringify({
|
|
36
|
-
addAttribute: "add_attachments",
|
|
37
|
-
resourceName: "questionnaire",
|
|
38
|
-
resourceClass: "Decidim::Forms::Questionnaire",
|
|
39
|
-
required: false,
|
|
40
|
-
maxFileSize: 10485760,
|
|
41
|
-
multiple: true,
|
|
42
|
-
titled: false,
|
|
43
|
-
formObjectClass: "Decidim::Forms::QuestionnaireForm"
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const radioCollection = (qid, options) => `
|
|
47
|
-
<div class="js-radio-button-collection">
|
|
48
|
-
${options.map((opt) => `
|
|
49
|
-
<div class="js-collection-input">
|
|
50
|
-
<input name="questionnaire[responses][${qid}][body]" type="radio" value="${opt.value}" />
|
|
51
|
-
<input name="questionnaire[responses][${qid}][custom_body]" type="text" />
|
|
52
|
-
<input name="questionnaire[responses][${qid}][response_option_id]" type="hidden" value="${opt.optionId}" />
|
|
53
|
-
</div>
|
|
54
|
-
`).join("")}
|
|
55
|
-
</div>
|
|
56
|
-
`;
|
|
57
|
-
|
|
58
|
-
const conditionTag = (data) =>
|
|
59
|
-
`<div class="display-condition" ${Object.entries(data).map(([key, val]) => `data-${key}='${val}'`).join(" ")}></div>`;
|
|
60
|
-
|
|
61
|
-
// Mirrors upload_modal/files.erb for one already-persisted, non-image attachment.
|
|
62
|
-
const uploadMarkup = () => `
|
|
63
|
-
<div class="upload-modal__files-container upload-container-for-add_attachments">
|
|
64
|
-
<div>
|
|
65
|
-
<div class="upload-modal__files" data-active-uploads="${MODAL_ID}">
|
|
66
|
-
<div class="attachment-details" data-attachment-id="99" data-title="doc.pdf" data-filename="doc.pdf" data-state="uploaded" data-hidden-field="signed-id-abc">
|
|
67
|
-
<a href="/rails/active_storage/blobs/doc.pdf">doc.pdf</a>
|
|
68
|
-
<input type="hidden" name="questionnaire[responses][QFILE][add_attachments]" value="99" id="hidden_add_attachments_99" />
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
<button id="button-${MODAL_ID}" name="add_attachments" type="button" data-dialog-open="${MODAL_ID}" data-upload='${UPLOAD_OPTS}'>Add file</button>
|
|
73
|
-
</div>
|
|
74
|
-
<div id="${MODAL_ID}" data-dialog="${MODAL_ID}">
|
|
75
|
-
<div id="${MODAL_ID}-content" class="upload-modal">
|
|
76
|
-
<div data-dialog-container>
|
|
77
|
-
<h2 data-dialog-title data-addlabel="Add file" data-editlabel="Edit file">Add file</h2>
|
|
78
|
-
<div data-name="add_attachments" data-dropzone>
|
|
79
|
-
<input id="files-${MODAL_ID}" type="file" multiple hidden />
|
|
80
|
-
<ul hidden data-dropzone-items="" data-locales='${LOCALES}'></ul>
|
|
81
|
-
<div data-dropzone-no-items="">
|
|
82
|
-
<label for="files-${MODAL_ID}"><span>Select file</span></label>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
<div data-dialog-actions>
|
|
87
|
-
<button type="button" data-dropzone-cancel data-dialog-close="${MODAL_ID}">Cancel</button>
|
|
88
|
-
<button type="button" data-dropzone-save data-dialog-close="${MODAL_ID}" disabled>Save</button>
|
|
89
|
-
</div>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
`;
|
|
93
|
-
|
|
94
|
-
// Mirrors responses/_sorting.html.erb
|
|
95
|
-
const sortingMarkup = (qid) => `
|
|
96
|
-
<div class="response-questionnaire__sorting-container js-sortable-check-box-collection">
|
|
97
|
-
${[["10", "1"], ["11", "2"], ["12", "3"]].map(([optId, pos], idx) => `
|
|
98
|
-
<div class="response-questionnaire__sorting js-collection-input" role="button">
|
|
99
|
-
<input type="hidden" name="questionnaire[responses][${qid}][choices][${idx}][position]" value="${pos}" />
|
|
100
|
-
<input type="hidden" name="questionnaire[responses][${qid}][choices][${idx}][body]" value="opt${optId}" />
|
|
101
|
-
<input type="hidden" name="questionnaire[responses][${qid}][choices][${idx}][response_option_id]" value="${optId}" />
|
|
102
|
-
</div>
|
|
103
|
-
`).join("")}
|
|
104
|
-
</div>
|
|
105
|
-
`;
|
|
106
|
-
|
|
107
|
-
const page = () => `
|
|
108
|
-
<form class="response-questionnaire" data-safe-path="/f">
|
|
109
|
-
<div class="question" data-question-id="Q0" data-conditioned="false">
|
|
110
|
-
${radioCollection("Q0", [{ optionId: "optA", value: "A" }, { optionId: "optC", value: "C" }])}
|
|
111
|
-
</div>
|
|
112
|
-
<div class="question" data-question-id="QFILE" data-conditioned="true">
|
|
113
|
-
${conditionTag({ id: "dcFile", type: "equal", condition: "Q0", option: "optC", mandatory: false })}
|
|
114
|
-
${uploadMarkup()}
|
|
115
|
-
<input type="hidden" name="questionnaire[responses][QFILE][question_id]" value="QFILE" />
|
|
116
|
-
</div>
|
|
117
|
-
<div class="question" data-question-id="QSORT" data-conditioned="true">
|
|
118
|
-
${conditionTag({ id: "dcSort", type: "equal", condition: "Q0", option: "optC", mandatory: false })}
|
|
119
|
-
${sortingMarkup("QSORT")}
|
|
120
|
-
<input type="hidden" name="questionnaire[responses][QSORT][question_id]" value="QSORT" />
|
|
121
|
-
</div>
|
|
122
|
-
</form>
|
|
123
|
-
`;
|
|
124
|
-
|
|
125
|
-
const initUploads = () => initializeUploadFields(document.querySelectorAll("button[data-upload]"));
|
|
126
|
-
const initConditions = () =>
|
|
127
|
-
$(".response-questionnaire .question[data-conditioned='true']").each((idx, el) =>
|
|
128
|
-
createDisplayConditions({ wrapperField: $(el) })
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
const wrapper = (qid) => $(`.question[data-question-id='${qid}']`);
|
|
132
|
-
const selectOption = (qid, value) => {
|
|
133
|
-
const $input = wrapper(qid).find(`input[name$='[body]'][value='${value}']`);
|
|
134
|
-
$input.prop("checked", true);
|
|
135
|
-
$input.trigger("change");
|
|
136
|
-
};
|
|
137
|
-
// What the browser would actually submit: enabled fields only.
|
|
138
|
-
const submitted = () =>
|
|
139
|
-
Array.from(document.querySelectorAll("form input:not([disabled])")).
|
|
140
|
-
filter((el) => el.name && (!["radio", "checkbox"].includes(el.type) || el.checked)).
|
|
141
|
-
map((el) => `${el.name}=${el.value}`);
|
|
142
|
-
// Any preview node holding the hidden add_attachments field, whether server
|
|
143
|
-
// rendered (.attachment-details) or re-rendered by updateActiveUploads (no class).
|
|
144
|
-
const previews = () => document.querySelectorAll(`[data-active-uploads='${MODAL_ID}'] > *`).length;
|
|
145
|
-
const serverRenderedPreviews = () => document.querySelectorAll(`[data-active-uploads='${MODAL_ID}'] .attachment-details`).length;
|
|
146
|
-
const modalItems = () => document.querySelectorAll(`#${MODAL_ID} [data-dropzone-items] > *`).length;
|
|
147
|
-
const buttonLabel = () => document.getElementById(`button-${MODAL_ID}`).innerHTML;
|
|
148
|
-
const positions = () =>
|
|
149
|
-
Array.from(document.querySelectorAll("[data-question-id='QSORT'] input[name$='[position]']")).map((el) => el.value);
|
|
150
|
-
|
|
151
|
-
describe("hidden questions and their responses", () => {
|
|
152
|
-
beforeEach(() => {
|
|
153
|
-
// UploadModal renders icons through window.Decidim.config
|
|
154
|
-
window.Decidim = { config: { get: () => "/icons.svg" } };
|
|
155
|
-
document.body.innerHTML = page();
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
describe("a file question hidden on page load", () => {
|
|
159
|
-
it("keeps the attachment and UploadModal in sync, whichever initializes first", () => {
|
|
160
|
-
initUploads();
|
|
161
|
-
initConditions();
|
|
162
|
-
|
|
163
|
-
expect(previews()).toBe(1);
|
|
164
|
-
expect(serverRenderedPreviews()).toBe(1);
|
|
165
|
-
expect(modalItems()).toBe(1);
|
|
166
|
-
expect(buttonLabel()).toBe("Add file");
|
|
167
|
-
// kept, but disabled, so it is not submitted while the question is hidden
|
|
168
|
-
expect(submitted().filter((field) => field.includes("add_attachments"))).toEqual([]);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it("behaves the same when the display conditions initialize first", () => {
|
|
172
|
-
initConditions();
|
|
173
|
-
initUploads();
|
|
174
|
-
|
|
175
|
-
expect(previews()).toBe(1);
|
|
176
|
-
expect(modalItems()).toBe(1);
|
|
177
|
-
expect(submitted().filter((field) => field.includes("add_attachments"))).toEqual([]);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
describe("a file question hidden and shown again", () => {
|
|
182
|
-
it("submits the attachment it already had", () => {
|
|
183
|
-
initUploads();
|
|
184
|
-
initConditions();
|
|
185
|
-
|
|
186
|
-
selectOption("Q0", "C");
|
|
187
|
-
|
|
188
|
-
expect(previews()).toBe(1);
|
|
189
|
-
expect(submitted()).toContain("questionnaire[responses][QFILE][add_attachments]=99");
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it("submits a file uploaded in this session, whose preview carries no attachment-details class", () => {
|
|
193
|
-
initUploads();
|
|
194
|
-
initConditions();
|
|
195
|
-
selectOption("Q0", "C");
|
|
196
|
-
|
|
197
|
-
// saving the modal makes updateActiveUploads() re-render the preview
|
|
198
|
-
document.getElementById(`button-${MODAL_ID}`).click();
|
|
199
|
-
document.querySelector(`#${MODAL_ID} [data-dropzone-save]`).click();
|
|
200
|
-
expect(serverRenderedPreviews()).toBe(0);
|
|
201
|
-
|
|
202
|
-
selectOption("Q0", "A");
|
|
203
|
-
selectOption("Q0", "C");
|
|
204
|
-
|
|
205
|
-
expect(previews()).toBe(1);
|
|
206
|
-
expect(submitted().filter((field) => field.includes("add_attachments"))).not.toEqual([]);
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
describe("a sorting question", () => {
|
|
211
|
-
it("keeps its order out of the submission while hidden, and restores it when shown", () => {
|
|
212
|
-
initUploads();
|
|
213
|
-
initConditions();
|
|
214
|
-
|
|
215
|
-
expect(positions()).toEqual(["1", "2", "3"]);
|
|
216
|
-
expect(submitted().filter((field) => field.includes("QSORT"))).toEqual([]);
|
|
217
|
-
|
|
218
|
-
selectOption("Q0", "C");
|
|
219
|
-
|
|
220
|
-
expect(positions()).toEqual(["1", "2", "3"]);
|
|
221
|
-
expect(submitted()).toContain("questionnaire[responses][QSORT][choices][0][position]=1");
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class RenameAnswersToResponses < ActiveRecord::Migration[7.2]
|
|
4
|
-
class Attachment < ApplicationRecord
|
|
5
|
-
self.table_name = "decidim_attachments"
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
class ActionLog < ApplicationRecord
|
|
9
|
-
self.table_name = "decidim_action_logs"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
class Version < ApplicationRecord
|
|
13
|
-
self.table_name = "versions"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def up
|
|
17
|
-
# rubocop:disable Rails/SkipsModelValidations
|
|
18
|
-
Attachment.where(attached_to_type: "Decidim::Forms::Answer").update_all(attached_to_type: "Decidim::Forms::Response")
|
|
19
|
-
ActionLog.where(resource_type: "Decidim::Forms::Answer").update_all(resource_type: "Decidim::Forms::Response")
|
|
20
|
-
Version.where(item_type: "Decidim::Forms::Answer").update_all(item_type: "Decidim::Forms::Response")
|
|
21
|
-
# rubocop:enable Rails/SkipsModelValidations
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def down
|
|
25
|
-
# rubocop:disable Rails/SkipsModelValidations
|
|
26
|
-
Attachment.where(attached_to_type: "Decidim::Forms::Response").update_all(attached_to_type: "Decidim::Forms::Answer")
|
|
27
|
-
ActionLog.where(resource_type: "Decidim::Forms::Response").update_all(resource_type: "Decidim::Forms::Answer")
|
|
28
|
-
Version.where(item_type: "Decidim::Forms::Response").update_all(item_type: "Decidim::Forms::Answer")
|
|
29
|
-
# rubocop:enable Rails/SkipsModelValidations
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "spec_helper"
|
|
4
|
-
|
|
5
|
-
shared_examples_for "questionnaire admin access" do |denied_error:, allow_process_admin: true|
|
|
6
|
-
context "when the user is not an admin", driver: :rack_test do
|
|
7
|
-
let(:regular_user) { create(:user, :confirmed, organization:) }
|
|
8
|
-
let(:target_path) { manage_questions_path }
|
|
9
|
-
|
|
10
|
-
before do
|
|
11
|
-
login_as regular_user, scope: :user
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
before do
|
|
15
|
-
allow(Rails.application).to \
|
|
16
|
-
receive(:env_config).with(no_args).and_wrap_original do |m, *|
|
|
17
|
-
m.call.merge(
|
|
18
|
-
"action_dispatch.show_exceptions" => true,
|
|
19
|
-
"action_dispatch.show_detailed_exceptions" => false
|
|
20
|
-
)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
visit target_path
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it "leads to an error" do
|
|
27
|
-
denied_response = case denied_error
|
|
28
|
-
when 403
|
|
29
|
-
page.status_code == 403 || page.has_content?("You are not authorized to perform this action")
|
|
30
|
-
when 404
|
|
31
|
-
page.status_code == 404 || page.has_content?("The page you are looking for cannot be found")
|
|
32
|
-
else
|
|
33
|
-
raise ArgumentError, "unsupported denied_error: #{denied_error.inspect}. Use 403 or 404"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
expect(denied_response).to be(true)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
if allow_process_admin
|
|
41
|
-
context "when the user is a process admin" do
|
|
42
|
-
let(:process_admin) { create(:process_admin, :confirmed, participatory_process:) }
|
|
43
|
-
|
|
44
|
-
it "allows access to the questionnaire" do
|
|
45
|
-
login_as process_admin, scope: :user
|
|
46
|
-
visit manage_questions_path
|
|
47
|
-
|
|
48
|
-
expect(page).to have_current_path(manage_questions_path)
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
else
|
|
52
|
-
context "when the user is a process admin", driver: :rack_test do
|
|
53
|
-
let(:participatory_process) { create(:participatory_process, organization:) }
|
|
54
|
-
let(:process_admin) { create(:process_admin, :confirmed, participatory_process:) }
|
|
55
|
-
|
|
56
|
-
before do
|
|
57
|
-
login_as process_admin, scope: :user
|
|
58
|
-
|
|
59
|
-
allow(Rails.application).to \
|
|
60
|
-
receive(:env_config).with(no_args).and_wrap_original do |m, *|
|
|
61
|
-
m.call.merge(
|
|
62
|
-
"action_dispatch.show_exceptions" => true,
|
|
63
|
-
"action_dispatch.show_detailed_exceptions" => false
|
|
64
|
-
)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
visit manage_questions_path
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it "denies access to the questionnaire" do
|
|
71
|
-
denied_response = case denied_error
|
|
72
|
-
when 403
|
|
73
|
-
page.status_code == 403 || page.has_content?("You are not authorized to perform this action")
|
|
74
|
-
when 404
|
|
75
|
-
page.status_code == 404 || page.has_content?("The page you are looking for cannot be found")
|
|
76
|
-
else
|
|
77
|
-
raise ArgumentError, "unsupported denied_error: #{denied_error.inspect}. Use 403 or 404"
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
expect(denied_response).to be(true)
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
context "when the user is an admin" do
|
|
86
|
-
let(:admin) { create(:user, :admin, :confirmed, organization:) }
|
|
87
|
-
|
|
88
|
-
it "allows access to the questionnaire" do
|
|
89
|
-
login_as admin, scope: :user
|
|
90
|
-
visit manage_questions_path
|
|
91
|
-
|
|
92
|
-
expect(page).to have_current_path(manage_questions_path)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "spec_helper"
|
|
4
|
-
|
|
5
|
-
shared_examples_for "questionnaire admin controller permissions" do
|
|
6
|
-
describe "GET #edit" do
|
|
7
|
-
let(:action) { :edit }
|
|
8
|
-
|
|
9
|
-
it "enforces permission to update the questionnaire" do
|
|
10
|
-
expect(controller).to receive(:enforce_permission_to).with(:update, permission_subject, questionnaire:)
|
|
11
|
-
get action
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
describe "PATCH #update" do
|
|
16
|
-
let(:action) { :update }
|
|
17
|
-
|
|
18
|
-
it "enforces permission to update the questionnaire" do
|
|
19
|
-
expect(controller).to receive(:enforce_permission_to).with(:update, permission_subject, questionnaire:)
|
|
20
|
-
patch action, params: { questionnaire: {} }
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
describe "GET #edit_questions" do
|
|
25
|
-
let(:action) { :edit_questions }
|
|
26
|
-
|
|
27
|
-
it "enforces permission to update the questionnaire" do
|
|
28
|
-
expect(controller).to receive(:enforce_permission_to).with(:update, permission_subject, questionnaire:)
|
|
29
|
-
get action
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
describe "PATCH #update_questions" do
|
|
34
|
-
let(:action) { :update_questions }
|
|
35
|
-
|
|
36
|
-
it "enforces permission to update the questionnaire" do
|
|
37
|
-
expect(controller).to receive(:enforce_permission_to).with(:update, permission_subject, questionnaire:)
|
|
38
|
-
patch action, params: { questions: {} }
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|