workflows: cancel fields overwritten by prefills during mass actions (#78146) #356

Merged
fpeters merged 1 commits from wip/78146-mass-interactive-prefill into main 2023-06-12 09:37:10 +02:00
3 changed files with 74 additions and 4 deletions

View File

@ -1312,6 +1312,75 @@ def test_backoffice_multi_actions_interactive_file_field(pub, upload_mode):
)
@pytest.mark.parametrize('mode', ['no_prefill', 'prefill'])
def test_backoffice_multi_actions_interactive_items_field(pub, mode):
user = create_superuser(pub)
workflow = Workflow.get_default_workflow()
workflow.id = '2'
action = workflow.add_global_action('FOOBAR')
form_action = action.add_action('form')
form_action.varname = 'blah'
form_action.formdef = WorkflowFormFieldsFormDef(item=form_action)
form_action.formdef.fields = [
fields.ItemsField(id='1', label='Test', varname='test', required=True, items=['foo', 'bar', 'baz'])
]
if mode == 'prefill':
form_action.formdef.fields[0].prefill = {'type': 'string', 'value': 'baz'}
form_action.hide_submit_button = False
trigger = action.triggers[0]
trigger.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar']
form_action.by = trigger.roles
workflow.store()
formdef = FormDef()
formdef.name = 'test multi actions interactive items field'
formdef.fields = []
formdef.workflow_roles = {'_receiver': user.roles[0]}
formdef.workflow = workflow
formdef.store()
for i in range(10):
formdata = formdef.data_class()()
formdata.just_created()
formdata.jump_status('new')
formdata.store()
app = login(get_app(pub))
resp = app.get(formdef.get_url(backoffice=True))
assert 'id="multi-actions"' in resp.text # always there
resp = app.get(formdef.get_url(backoffice=True) + '?limit=20&order_by=id')
ids = []
for checkbox in resp.forms[0].fields['select[]'][1:6]:
ids.append(checkbox._value)
checkbox.checked = True
resp = resp.forms[0].submit('button-action-1')
assert '/actions/' in resp.location
resp = resp.follow()
assert '5 selected forms' in resp.text
if mode == 'prefill':
assert resp.form['fblah_1$element2'].checked is True
else:
assert resp.form['fblah_1$element2'].checked is False
resp.form['fblah_1$element0'].checked = True
resp.form['fblah_1$element1'].checked = True
resp.form['fblah_1$element2'].checked = False
resp = resp.form.submit('submit')
assert '?job=' in resp.location
resp = resp.follow()
assert 'Executing task "FOOBAR" on forms' in resp.text
assert '>completed<' in resp.text
for formdata in formdef.data_class().select([Contains('id', ids)]):
assert formdata.get_substitution_variables()['form'].workflow_form.blah.var.test.raw == ['foo', 'bar']
def test_backoffice_map(pub):
create_user(pub)
create_environment(pub)

View File

@ -14,6 +14,8 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import copy
from quixote import get_publisher, get_request, get_response, get_session, redirect
from quixote.directory import Directory
from quixote.errors import PublishError
@ -234,8 +236,11 @@ class GlobalInteractiveMassActionAfterJob(AfterJob):
publisher.substitutions.feed(formdata.formdef)
publisher.substitutions.feed(formdata)
request_form = copy.copy(get_request().form)
status = formdata.status
form = action.get_action_form(formdata, user=user)
get_request().form = request_form # cancel fields overwritten by prefills
Review

Le get_action_form() appelle le fill_form() des actions et pour l'action formulaire celui-ci fait le préremplissage, ce qui écrase les valeurs contenues dans request.form (l'appel widget.transfer_form_value(req)).

Le get_action_form() appelle le fill_form() des actions et pour l'action formulaire celui-ci fait le préremplissage, ce qui écrase les valeurs contenues dans request.form (l'appel widget.transfer_form_value(req)).
form.method = 'get'
url = action.handle_form(form, formdata, user=user)
if afterjob:

View File

@ -1745,10 +1745,6 @@ class CheckboxesWidget(Widget):
def get_too_long_message(self):
return _('You must select at most %d answers.') % self.max_choices
def set_value(self, value):
self.value = value
self._parsed = True
Review

Sur les cases à cocher ça échoue en plus parce qu'après le set_value() il n'y avait pas de réévaluation (à cause sur _parsed = True), celui-ci avait été introduit pour le préremplissage des cases à cocher (#22146) mais ça n'est plus nécessaire (le test ajouté à l'époque fonctionne sans) (je pense que ça n'est plus nécessaire depuis #43875 mais je n'ai pas vérifié).

Sur les cases à cocher ça échoue en plus parce qu'après le set_value() il n'y avait pas de réévaluation (à cause sur `_parsed = True`), celui-ci avait été introduit pour le préremplissage des cases à cocher (#22146) mais ça n'est plus nécessaire (le test ajouté à l'époque fonctionne sans) (je pense que ça n'est plus nécessaire depuis #43875 mais je n'ai pas vérifié).
def transfer_form_value(self, request):
for v in self.value or []:
for option in self.get_options():