wcs: option to get forms user can access in current form cell (#56477)
gitea-wip/combo/pipeline/head There was a failure building this commit Details
gitea/combo/pipeline/head Build started... Details

This commit is contained in:
Lauréline Guérin 2021-08-31 09:56:06 +02:00
parent 69425c6200
commit cb7e32cd2e
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
7 changed files with 159 additions and 95 deletions

View File

@ -14,10 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
from django import forms
from django.utils.datastructures import MultiValueDict
from django.utils.translation import ugettext_lazy as _
from combo.utils.forms import MultiSortWidget
@ -130,17 +127,6 @@ class WcsFormsOfCategoryCellForm(forms.ModelForm):
self.fields['manual_order'].widget = MultiSortWidget(choices=formdef_references)
class CategoriesSelectMultiple(forms.SelectMultiple):
def format_value(self, value):
value = json.loads(value)
return super().format_value(value.get('data') or [])
def value_from_datadict(self, data, files, name):
if isinstance(data, MultiValueDict):
return {'data': data.getlist(name)}
return data.get(name, None)
class WcsFormsMixin:
def _init_wcs_site(self):
if len(get_wcs_services()) == 1:
@ -156,27 +142,63 @@ class WcsFormsMixin:
def _init_categories(self):
categories = get_wcs_options('/api/categories/')
self.fields['categories'].help_text = _('By default forms from all categories are displayed.')
self.fields['categories'].widget = CategoriesSelectMultiple(
choices=categories, attrs={'class': 'categories-select'}
self.fields['categories'] = forms.MultipleChoiceField(
choices=categories,
help_text=_('By default forms from all categories are displayed.'),
widget=forms.SelectMultiple(attrs={'class': 'categories-select'}),
initial=self.instance.categories.get('data') or [],
required=False,
)
if self.field_order:
self.order_fields(self.field_order)
def save(self, *args, **kwargs):
super().save(commit=False)
self.instance.categories = {'data': self.cleaned_data.get('categories') or []}
self.instance.save()
return self.instance
class WcsCurrentFormsCellForm(WcsFormsMixin, forms.ModelForm):
field_order = [
'wcs_site',
'categories',
'current_forms',
'done_forms',
'include_drafts',
'include_forms_user_can_access',
]
class Meta:
model = WcsCurrentFormsCell
fields = ['wcs_site', 'categories', 'current_forms', 'done_forms', 'include_drafts']
fields = [
'wcs_site',
'current_forms',
'done_forms',
'include_drafts',
'include_forms_user_can_access',
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._init_wcs_site()
self._init_categories()
def clean(self):
cleaned_data = super().clean()
if not cleaned_data.get('current_forms') and not cleaned_data.get('done_forms'):
raise forms.ValidationError(
_('Please choose at least one option among the following: Current Forms, Done Forms')
)
return cleaned_data
class WcsCurrentDraftsCellForm(WcsFormsMixin, forms.ModelForm):
class Meta:
model = WcsCurrentDraftsCell
fields = ['wcs_site', 'categories']
fields = ['wcs_site']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@ -187,7 +209,7 @@ class WcsCurrentDraftsCellForm(WcsFormsMixin, forms.ModelForm):
class WcsCareFormsCellForm(WcsFormsMixin, forms.ModelForm):
class Meta:
model = WcsCareFormsCell
fields = ['wcs_site', 'categories']
fields = ['wcs_site']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@ -198,7 +220,7 @@ class WcsCareFormsCellForm(WcsFormsMixin, forms.ModelForm):
class BackofficeSubmissionCellForm(WcsFormsMixin, forms.ModelForm):
class Meta:
model = WcsCurrentDraftsCell
fields = ['wcs_site', 'categories']
fields = ['wcs_site']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

View File

@ -0,0 +1,18 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wcs', '0036_remove_wcscurrentformscell_include_forms_user_can_access'),
]
operations = [
migrations.AddField(
model_name='wcscurrentformscell',
name='include_forms_user_can_access',
field=models.BooleanField(
default=False, verbose_name='Include requests for which the user is not the author'
),
),
]

View File

@ -465,6 +465,9 @@ class WcsCurrentFormsCell(CategoriesAndWcsSiteValidityMixin, CategoriesFiltering
current_forms = models.BooleanField(_('Current Forms'), default=True)
done_forms = models.BooleanField(_('Done Forms'), default=False)
include_drafts = models.BooleanField(_('Include drafts'), default=False)
include_forms_user_can_access = models.BooleanField(
_('Include requests for which the user is not the author'), default=False
)
class Meta:
verbose_name = _('User Forms')
@ -475,15 +478,23 @@ class WcsCurrentFormsCell(CategoriesAndWcsSiteValidityMixin, CategoriesFiltering
return WcsCurrentFormsCellForm
def get_api_url(self, context):
url = '/api/user/forms/'
user = self.get_concerned_user(context)
base_url = '/api/user/forms'
if user:
user_name_id = user.get_name_id()
if user_name_id:
base_url = '/api/users/%s/forms' % user_name_id
url = base_url + '?limit=100&sort=desc'
url = '/api/users/%s/forms' % user_name_id
if self.current_forms and self.done_forms:
url += '?status=all'
elif self.done_forms:
url += '?status=done'
else:
url += '?status=open'
if self.include_forms_user_can_access:
url += '&include-accessible=on'
if self.include_drafts:
url += '&include-drafts=on'
url += '&limit=100&sort=desc'
return url
@property
@ -517,22 +528,6 @@ class WcsCurrentFormsCell(CategoriesAndWcsSiteValidityMixin, CategoriesFiltering
def get_cell_extra_context(self, context):
context = super().get_cell_extra_context(context)
for wcs_site in context['user_forms']:
if not context['user_forms'].get(wcs_site):
continue
if not context['user_forms'][wcs_site].get('data'):
continue
forms = context['user_forms'][wcs_site]['data']
if self.current_forms and self.done_forms:
pass # keep them all
elif self.current_forms:
forms = [x for x in forms if not x.get('form_status_is_endpoint')]
elif self.done_forms:
forms = [x for x in forms if x.get('form_status_is_endpoint')]
else:
forms = [] # nothing left
context['user_forms'][wcs_site]['data'] = forms # put it back
context['current_forms'] = context['user_forms'] # legacy
# regroup all forms in a flat list
@ -574,14 +569,6 @@ class WcsCurrentDraftsCell(CategoriesAndWcsSiteValidityMixin, CategoriesFilterin
def get_cell_extra_context(self, context):
context = super().get_cell_extra_context(context)
for wcs_site in context['current_drafts']:
if not context['current_drafts'].get(wcs_site):
continue
if not context['current_drafts'][wcs_site].get('data'):
continue
forms = context['current_drafts'][wcs_site]['data']
context['current_drafts'][wcs_site]['data'] = forms # put it back
# regroup all forms in a flat list
context['drafts'] = []
for wcs_site in context['current_drafts']:

View File

@ -4,7 +4,7 @@
{% if forms %}
{% for slug, forms in current_forms.items %}
<div class="links-list current-forms-{{ slug }} current-forms list-of-forms">
{% include "combo/wcs/list_of_forms.html" with forms=forms %}
{% include "combo/wcs/list_of_forms.html" %}
</div>
{% endfor %}
{% include "combo/pagination.html" %}

View File

@ -4,7 +4,7 @@
{% if forms %}
{% for slug, forms in user_forms.items %}
<div class="links-list user-forms-{{ slug }} user-all-forms list-of-forms">
{% include "combo/wcs/list_of_forms.html" with forms=forms %}
{% include "combo/wcs/list_of_forms.html" %}
</div>
{% endfor %}
{% include "combo/pagination.html" %}

View File

@ -4,7 +4,7 @@
{% if forms %}
{% for slug, forms in user_forms.items %}
<div class="links-list user-forms-{{ slug }} list-of-forms">
{% include "combo/wcs/list_of_forms.html" with forms=forms %}
{% include "combo/wcs/list_of_forms.html" %}
</div>
{% endfor %}
{% include "combo/pagination.html" %}

View File

@ -81,15 +81,6 @@ WCS_USER_FORMS_DATA = [
},
{'name': 'name', 'url': '/form/2/', 'form_receipt_datetime': '2015-01-01T00:00:00', 'readable': True},
{'name': 'name', 'title': 'Title', 'url': '/form/3/', 'form_receipt_datetime': '2015-01-01T00:00:00'},
{
'name': 'name',
'title': 'Title',
'url': '/form/4/',
'form_receipt_datetime': '2015-01-01T00:00:00',
'readable': True,
'form_status_is_endpoint': True,
'category_slug': 'test-9',
},
]
WCS_FORMS_DATA = [
@ -514,27 +505,13 @@ def test_current_forms_cell_render(mock_send, context):
context['synchronous'] = True # to get fresh content
# default is to get current forms from all wcs sites
result = cell.render(context)
assert 'http://127.0.0.1:8999/form/1/' in result
assert 'http://127.0.0.1:8999/form/2/' not in result # no title
assert 'http://127.0.0.1:8999/form/3/' not in result # not readable
assert 'http://127.0.0.1:8999/form/4/' not in result # done
assert 'http://127.0.0.2:8999/form/1/' in result
assert 'http://127.0.0.2:8999/form/2/' not in result
assert 'http://127.0.0.2:8999/form/3/' not in result
assert 'http://127.0.0.2:8999/form/4/' not in result
# done forms
cell.current_forms = False
cell.done_forms = True
cell.include_drafts = False
cell.save()
result = cell.render(context)
assert 'http://127.0.0.1:8999/form/1/' not in result # wip
assert 'http://127.0.0.1:8999/form/4/' in result # done
assert 'http://127.0.0.2:8999/form/1/' not in result # wip
assert 'http://127.0.0.2:8999/form/4/' in result # done
# limit to categories
cell.categories = {'data': ['default:test-3', 'other:test-6']}
@ -543,9 +520,15 @@ def test_current_forms_cell_render(mock_send, context):
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms?limit=100&sort=desc&category_slugs=test-3'
assert (
requests_get.call_args_list[0][0][0]
== '/api/user/forms/?status=open&limit=100&sort=desc&category_slugs=test-3'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms?limit=100&sort=desc&category_slugs=test-6'
assert (
requests_get.call_args_list[1][0][0]
== '/api/user/forms/?status=open&limit=100&sort=desc&category_slugs=test-6'
)
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
# check include drafts
@ -556,9 +539,9 @@ def test_current_forms_cell_render(mock_send, context):
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms?limit=100&sort=desc'
assert requests_get.call_args_list[0][0][0] == '/api/user/forms/?status=open&limit=100&sort=desc'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms?limit=100&sort=desc'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms/?status=open&limit=100&sort=desc'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
cell.include_drafts = True
@ -567,9 +550,15 @@ def test_current_forms_cell_render(mock_send, context):
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms?limit=100&sort=desc&include-drafts=on'
assert (
requests_get.call_args_list[0][0][0]
== '/api/user/forms/?status=open&include-drafts=on&limit=100&sort=desc'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms?limit=100&sort=desc&include-drafts=on'
assert (
requests_get.call_args_list[1][0][0]
== '/api/user/forms/?status=open&include-drafts=on&limit=100&sort=desc'
)
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
cell.categories = {'data': ['default:test-3']}
@ -580,7 +569,7 @@ def test_current_forms_cell_render(mock_send, context):
assert len(requests_get.call_args_list) == 1
assert (
requests_get.call_args_list[0][0][0]
== '/api/user/forms?limit=100&sort=desc&include-drafts=on&category_slugs=test-3'
== '/api/user/forms/?status=open&include-drafts=on&limit=100&sort=desc&category_slugs=test-3'
)
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
@ -591,6 +580,54 @@ def test_current_forms_cell_render(mock_send, context):
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
# current_forms only
cell.include_drafts = False
cell.current_forms = True
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms/?status=open&limit=100&sort=desc'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms/?status=open&limit=100&sort=desc'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
# all forms
cell.done_forms = True
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms/?status=all&limit=100&sort=desc'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms/?status=all&limit=100&sort=desc'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
# done forms only
cell.current_forms = False
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.get_cell_extra_context(context)
assert len(requests_get.call_args_list) == 2
assert requests_get.call_args_list[0][0][0] == '/api/user/forms/?status=done&limit=100&sort=desc'
assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/'
assert requests_get.call_args_list[1][0][0] == '/api/user/forms/?status=done&limit=100&sort=desc'
assert requests_get.call_args_list[1][1]['remote_service']['url'] == 'http://127.0.0.2:8999/'
# include forms user can see
cell.include_forms_user_can_access = True
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert (
requests_get.call_args_list[0][0][0]
== '/api/user/forms/?status=done&include-accessible=on&limit=100&sort=desc'
)
# check empty messages
with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
mock_json = mock.Mock(status_code=200)
@ -719,7 +756,7 @@ def test_current_forms_cell_render_single_site(mock_send, context):
assert 'http://127.0.0.2:8999/form/1/' not in result
def test_current_forms_unknown_name_id(context):
def test_current_forms_name_id(context):
page = Page(title='xxx', slug='test_current_forms_cell_render', template_name='standard')
page.save()
cell = WcsCurrentFormsCell(page=page, placeholder='content', order=0)
@ -739,7 +776,7 @@ def test_current_forms_unknown_name_id(context):
mock_json = mock.Mock(status_code=200)
requests_get.return_value = mock_json
cell.render(context)
assert requests_get.call_args_list[0][0][0] == '/api/users/xyz/forms?limit=100&sort=desc'
assert requests_get.call_args_list[0][0][0] == '/api/users/xyz/forms?status=open&limit=100&sort=desc'
def test_care_forms_cell_setup():
@ -1267,7 +1304,7 @@ def test_manager_forms_of_category_cell(mock_send, app, admin_user):
@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send)
def test_manager_current_forms(mock_send, app, admin_user):
def test_manager_current_forms(mock_send, settings, app, admin_user):
page = Page(title='One', slug='one', template_name='standard')
page.save()
app = login(app)
@ -1289,21 +1326,21 @@ def test_manager_current_forms(mock_send, app, admin_user):
'default:test-3',
'default:test-9',
]
resp.form['c%s-current_forms' % cells[0].get_reference()] = False
resp.form['c%s-done_forms' % cells[0].get_reference()] = False
resp = resp.form.submit()
assert 'Please choose at least one option among the following: Current Forms, Done Forms' in resp
resp = app.get('/manage/pages/%s/' % page.id)
resp.form['c%s-done_forms' % cells[0].get_reference()] = True
resp = resp.form.submit().follow()
# check wcs_site field is a select box
assert resp.form['c%s-wcs_site' % cells[0].get_reference()].tag == 'select'
try:
# check the wcs_site field is hidden if there's a single one defined in
# the configuration
temp_settings = settings.KNOWN_SERVICES.copy()
default = settings.KNOWN_SERVICES['wcs']['default']
settings.KNOWN_SERVICES = {'wcs': {'default': default}}
resp = app.get('/manage/pages/%s/' % page.id)
assert resp.form['c%s-wcs_site' % cells[0].get_reference()].attrs['type'] == 'hidden'
finally:
# restore original settings
settings.KNOWN_SERVICES = temp_settings
default = settings.KNOWN_SERVICES['wcs']['default']
settings.KNOWN_SERVICES = {'wcs': {'default': default}}
resp = app.get('/manage/pages/%s/' % page.id)
assert resp.form['c%s-wcs_site' % cells[0].get_reference()].attrs['type'] == 'hidden'
@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send)