diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..281e74073 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,5 @@ +# Black reformat +135eb9119066aedf946aaf3d22cbb839d59fc038 + +# DJLint reformat +664077453c8fe393cdd8db692a33d515e5db6f69 \ No newline at end of file diff --git a/.github/workflows/check-missing-migrations.yml b/.github/workflows/check-missing-migrations.yml deleted file mode 100644 index 1d5423359..000000000 --- a/.github/workflows/check-missing-migrations.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Check for missing migrations - -on: - pull_request: -jobs: - run-check: - runs-on: ubuntu-latest - steps: - - name: Install OS dependencies - run: | - sudo apt-get update - sudo apt-get install libldap2-dev libsasl2-dev libssl-dev gettext poppler-utils poppler-data libpoppler-cpp-dev - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.9 - - name: Install Dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - name: Check for missing migrations - run: | - python manage.py makemigrations --check --dry-run diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 000000000..f672f6466 --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,55 @@ +name: PR checks + +on: + pull_request: +jobs: + check-migrations: + name: Check if there are any missing migrations + runs-on: ubuntu-latest + steps: + - name: Install OS dependencies + run: | + sudo apt-get update + sudo apt-get install libldap2-dev libsasl2-dev libssl-dev gettext poppler-utils poppler-data libpoppler-cpp-dev + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Check for missing migrations + run: | + python manage.py makemigrations --check --dry-run + check-djlint: + name: Check if DJLint thinks everything is correctly formatted + runs-on: ubuntu-latest + steps: + - name: Install OS dependencies + run: | + sudo apt-get update + sudo apt-get install libldap2-dev libsasl2-dev libssl-dev gettext poppler-utils poppler-data libpoppler-cpp-dev + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Run DJLint + # This exclude flag is needed because Github downloads dependencies there, which causes djlint to judge those + run: | + djlint . --check --exclude src + black-check: # Rhymes with blackjack :D + name: Check if Black thinks everything is correctly formatted + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: psf/black@stable + with: + src: . + diff --git a/.gitignore b/.gitignore index ee1ad8e43..71f2b417a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ *.pyc __pycache__/ .env* - +*.mo ### Project-specific ### media/ diff --git a/docs/conf.py b/docs/conf.py index 9bcb4a0cd..4e274db8a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,54 +18,55 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('..')) -os.environ['DJANGO_SETTINGS_MODULE'] = 'fetc.settings' +sys.path.insert(0, os.path.abspath("..")) +os.environ["DJANGO_SETTINGS_MODULE"] = "fetc.settings" import django + django.setup() # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinxcontrib.apidoc', - 'sphinx.ext.autodoc', - 'sphinxcontrib_django', - 'sphinx.ext.coverage', - 'sphinx.ext.viewcode' + "sphinxcontrib.apidoc", + "sphinx.ext.autodoc", + "sphinxcontrib_django", + "sphinx.ext.coverage", + "sphinx.ext.viewcode", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'FEtC-H' -copyright = u'2019, Martijn van der Klis & Ty Mees' -author = u'Martijn van der Klis & Ty Mees' +project = "FEtC-H" +copyright = "2019, Martijn van der Klis & Ty Mees" +author = "Martijn van der Klis & Ty Mees" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'1.0' +version = "1.0" # The full version, including alpha/beta/rc tags. -release = u'1.0' +release = "1.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -76,38 +77,38 @@ # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +# keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -122,153 +123,152 @@ # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. # " v documentation" by default. -#html_title = u'FEtC-H v1.0' +# html_title = u'FEtC-H v1.0' # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] +# html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. -#html_extra_path = [] +# html_extra_path = [] # If not None, a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. # The empty string is equivalent to '%b %d, %Y'. -#html_last_updated_fmt = None +# html_last_updated_fmt = None # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' -#html_search_language = 'en' +# html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # 'ja' uses this config value. # 'zh' user can custom change `jieba` dictionary path. -#html_search_options = {'type': 'default'} +# html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. -#html_search_scorer = 'scorer.js' +# html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'FEtCdoc' +htmlhelp_basename = "FEtCdoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', - -# Latex figure (float) alignment -#'figure_align': 'htbp', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', + # Latex figure (float) alignment + #'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'FEtC-H.tex', u'FEtC-H Documentation', - u'Martijn van der Klis & Ty Mees', 'manual'), + ( + master_doc, + "FEtC-H.tex", + "FEtC-H Documentation", + "Martijn van der Klis & Ty Mees", + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'fetc', u'FeTC-H Documentation', - [author], 1) -] +man_pages = [(master_doc, "fetc", "FeTC-H Documentation", [author], 1)] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------- @@ -277,29 +277,35 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'FeTC-h', u'FeTC-H Documentation', - author, 'FeTC-H', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "FeTC-h", + "FeTC-H Documentation", + author, + "FeTC-H", + "One line description of project.", + "Miscellaneous", + ), ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +# texinfo_no_detailmenu = False -apidoc_module_dir = '..' -apidoc_output_dir = 'reference' -apidoc_excluded_paths = ['docs', '*/migrations', 'manage.py'] +apidoc_module_dir = ".." +apidoc_output_dir = "reference" +apidoc_excluded_paths = ["docs", "*/migrations", "manage.py"] apidoc_separate_modules = True apidoc_module_first = True -apidoc_toc_file = 'index' +apidoc_toc_file = "index" -todo_include_todos = True \ No newline at end of file +todo_include_todos = True diff --git a/docs/developing/install/steps.rst b/docs/developing/install/steps.rst index c7b17358e..44245a0f3 100644 --- a/docs/developing/install/steps.rst +++ b/docs/developing/install/steps.rst @@ -21,6 +21,8 @@ Your host OS needs some packages, below is a list of debian packages: + libsasl2-dev + libssl-dev + gettext ++ libcairo2-dev ++ libpoppler-cpp-dev Pip might throw errors while installing `mysqlclient` if you do not have a mysql-dev package. That package is not needed for development, so you can (temporarily) comment out that dependency if you run into problems. (Or just install the diff --git a/faqs/admin.py b/faqs/admin.py index 7ed69910b..9f31d8776 100644 --- a/faqs/admin.py +++ b/faqs/admin.py @@ -5,5 +5,8 @@ @admin.register(Faq) class FaqAdmin(admin.ModelAdmin): - list_display = ('order', 'question', ) - ordering = ['order'] + list_display = ( + "order", + "question", + ) + ordering = ["order"] diff --git a/faqs/menus.py b/faqs/menus.py index aa4f4845a..4afdaaefd 100644 --- a/faqs/menus.py +++ b/faqs/menus.py @@ -22,15 +22,14 @@ _("FAQs"), reverse("faqs:list"), ), - MenuItem( - _("Feedback"), - reverse("feedback:create"), - ) ) -Menu.add_item("main", MenuItem(_('Help'), - "#", - children=help_menu, - exact_url=True, - )) - +Menu.add_item( + "main", + MenuItem( + _("Help"), + "#", + children=help_menu, + exact_url=True, + ), +) diff --git a/faqs/migrations/0001_initial.py b/faqs/migrations/0001_initial.py index ce076326e..57192d352 100644 --- a/faqs/migrations/0001_initial.py +++ b/faqs/migrations/0001_initial.py @@ -5,21 +5,27 @@ class Migration(migrations.Migration): - - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Faq', + name="Faq", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('order', models.PositiveIntegerField(unique=True)), - ('question', models.TextField()), - ('answer', models.TextField()), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("order", models.PositiveIntegerField(unique=True)), + ("question", models.TextField()), + ("answer", models.TextField()), ], options={ - 'verbose_name': 'FAQ', + "verbose_name": "FAQ", }, ), ] diff --git a/faqs/migrations/0002_auto_20161013_1959.py b/faqs/migrations/0002_auto_20161013_1959.py index 92865698b..d045a58d2 100644 --- a/faqs/migrations/0002_auto_20161013_1959.py +++ b/faqs/migrations/0002_auto_20161013_1959.py @@ -5,30 +5,29 @@ class Migration(migrations.Migration): - dependencies = [ - ('faqs', '0001_initial'), + ("faqs", "0001_initial"), ] operations = [ migrations.AddField( - model_name='faq', - name='answer_en', + model_name="faq", + name="answer_en", field=models.TextField(null=True), ), migrations.AddField( - model_name='faq', - name='answer_nl', + model_name="faq", + name="answer_nl", field=models.TextField(null=True), ), migrations.AddField( - model_name='faq', - name='question_en', + model_name="faq", + name="question_en", field=models.TextField(null=True), ), migrations.AddField( - model_name='faq', - name='question_nl', + model_name="faq", + name="question_nl", field=models.TextField(null=True), ), ] diff --git a/faqs/models.py b/faqs/models.py index 53e5ce68b..2e68ddb0e 100644 --- a/faqs/models.py +++ b/faqs/models.py @@ -8,7 +8,7 @@ class Faq(models.Model): answer = models.TextField() class Meta: - verbose_name = _('FAQ') + verbose_name = _("FAQ") def __str__(self): return self.question diff --git a/faqs/templates/faqs/faq_list.html b/faqs/templates/faqs/faq_list.html index deccc7ad3..c86f6d1f8 100644 --- a/faqs/templates/faqs/faq_list.html +++ b/faqs/templates/faqs/faq_list.html @@ -9,15 +9,14 @@ {% block content %}
-

- {% trans "Frequently Asked Questions" %} -

+

{% trans "Frequently Asked Questions" %}

{% for faq in faqs %} {% endfor %} - {% for faq in faqs %}

{{ faq.question }}

diff --git a/faqs/translation.py b/faqs/translation.py index 2d95ff64d..303badbbe 100644 --- a/faqs/translation.py +++ b/faqs/translation.py @@ -5,4 +5,7 @@ @register(Faq) class FaqTranslationOptions(TranslationOptions): - fields = ('question', 'answer',) + fields = ( + "question", + "answer", + ) diff --git a/faqs/urls.py b/faqs/urls.py index abf3a8354..01a891be7 100644 --- a/faqs/urls.py +++ b/faqs/urls.py @@ -2,8 +2,8 @@ from .views import FaqsView -app_name = 'faqs' +app_name = "faqs" urlpatterns = [ - path('', FaqsView.as_view(), name='list'), + path("", FaqsView.as_view(), name="list"), ] diff --git a/faqs/views.py b/faqs/views.py index 067061412..46ae683ca 100644 --- a/faqs/views.py +++ b/faqs/views.py @@ -5,4 +5,4 @@ class FaqsView(generic.ListView): model = Faq - context_object_name = 'faqs' + context_object_name = "faqs" diff --git a/feedback/__init__.py b/feedback/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/feedback/admin.py b/feedback/admin.py deleted file mode 100644 index e783a64ce..000000000 --- a/feedback/admin.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.contrib import admin - -from .models import Feedback - - -@admin.register(Feedback) -class FeedbackAdmin(admin.ModelAdmin): - fields = ('url', 'comment', 'submitter', 'priority', 'status') - list_display = ['url', 'comment', 'submitter', 'date_created'] - list_filter = ('priority', 'status') diff --git a/feedback/forms.py b/feedback/forms.py deleted file mode 100644 index dc2cdae54..000000000 --- a/feedback/forms.py +++ /dev/null @@ -1,12 +0,0 @@ -from django import forms - -from .models import Feedback - - -class FeedbackForm(forms.ModelForm): - class Meta: - model = Feedback - fields = ['url', 'comment'] - widgets = { - 'url': forms.HiddenInput(), - } diff --git a/feedback/migrations/0001_initial.py b/feedback/migrations/0001_initial.py deleted file mode 100644 index d178ddff9..000000000 --- a/feedback/migrations/0001_initial.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models -from django.conf import settings - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Feedback', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('url', models.URLField()), - ('comment', models.TextField(verbose_name='Feedback')), - ('priority', models.IntegerField(default=1, choices=[(1, 'Laag'), (2, 'Gemiddeld'), (3, 'Hoog')])), - ('status', models.IntegerField(default=1, choices=[(1, 'Open'), (2, 'Opgepakt'), (3, 'Afgehandeld')])), - ('date_created', models.DateTimeField(auto_now_add=True)), - ('date_modified', models.DateField(auto_now=True)), - ('submitter', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), - ], - ), - ] diff --git a/feedback/migrations/__init__.py b/feedback/migrations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/feedback/models.py b/feedback/models.py deleted file mode 100644 index b168b09c9..000000000 --- a/feedback/models.py +++ /dev/null @@ -1,27 +0,0 @@ -from django.db import models -from django.conf import settings -from django.utils.translation import ugettext_lazy as _ - -STATUS_CODES = ( - (1, _('Open')), - (2, _('Opgepakt')), - (3, _('Afgehandeld')), -) - -PRIORITY_CODES = ( - (1, _('Laag')), - (2, _('Gemiddeld')), - (3, _('Hoog')), -) - - -class Feedback(models.Model): - url = models.URLField() - comment = models.TextField(_('Feedback')) - priority = models.IntegerField(default=1, choices=PRIORITY_CODES) - status = models.IntegerField(default=1, choices=STATUS_CODES) - - date_created = models.DateTimeField(auto_now_add=True) - date_modified = models.DateField(auto_now=True) - - submitter = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) diff --git a/feedback/templates/feedback/feedback_form.html b/feedback/templates/feedback/feedback_form.html deleted file mode 100644 index 2a0d9584d..000000000 --- a/feedback/templates/feedback/feedback_form.html +++ /dev/null @@ -1,30 +0,0 @@ -{% extends "base/base.html" %} - -{% load static %} -{% load i18n %} - -{% block header_title %} - {% trans "Feedback versturen" %} - {{ block.super }} -{% endblock %} - -{% block content %} -
-
-

- {% trans "Feedback versturen" %} -

-

- {% trans "Hier kan je feedback achterlaten op het FETC-GW portal." %} -

-
{% csrf_token %} - {{ form.as_table }}
-

- - {% trans "Terug naar de vorige pagina" %} - - -

-
-
-
-{% endblock %} diff --git a/feedback/templates/feedback/feedback_list.html b/feedback/templates/feedback/feedback_list.html deleted file mode 100644 index 2f1947499..000000000 --- a/feedback/templates/feedback/feedback_list.html +++ /dev/null @@ -1,39 +0,0 @@ -{% extends "base/base.html" %} - -{% load static %} -{% load i18n %} -{% load datatables %} - -{% block header_title %} - {% trans "Feedbackoverzicht" %} - {{ block.super }} -{% endblock %} - -{% block content %} -
-
-

- {% trans "Feedbackoverzicht" %} -

- - - - - - - - - - - {% for feedback in feedback_list %} - - - - - - - {% endfor %} - -
{% trans "Toegevoegd op" %}{% trans "URL" %}{% trans "Feedback" %}{% trans "Gegeven door" %}
{{ feedback.date_created|date:"j M Y, G:i" }}{{ feedback.url }}{{ feedback.comment }}{{ feedback.submitter.get_full_name }}
-
-
-{% endblock %} diff --git a/feedback/templates/feedback/feedback_thanks.html b/feedback/templates/feedback/feedback_thanks.html deleted file mode 100644 index fd9c0e0a3..000000000 --- a/feedback/templates/feedback/feedback_thanks.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends "base/base.html" %} - -{% load static %} -{% load i18n %} - -{% block header_title %} - {% trans "Bedankt voor je feedback!" %} - {{ block.super }} -{% endblock %} - -{% block content %} -
-
-

- {% trans "Bedankt voor je feedback!" %} -

-

- {% blocktrans with url=feedback.url %} - Klik hier om terug te keren naar pagina waar je gebleven was. - {% endblocktrans %} -

-
-
-{% endblock %} diff --git a/feedback/tests.py b/feedback/tests.py deleted file mode 100644 index 7ce503c2d..000000000 --- a/feedback/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/feedback/urls.py b/feedback/urls.py deleted file mode 100644 index 7bccea3aa..000000000 --- a/feedback/urls.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.urls import path - -from .views import FeedbackCreate, FeedbackListing, FeedbackThanks - -app_name = 'feedback' - -urlpatterns = [ - path('', FeedbackListing.as_view(), name='overview'), - path('create/', FeedbackCreate.as_view(), name='create'), - path('thanks//', FeedbackThanks.as_view(), name='thanks'), -] diff --git a/feedback/views.py b/feedback/views.py deleted file mode 100644 index 675b02c05..000000000 --- a/feedback/views.py +++ /dev/null @@ -1,39 +0,0 @@ -from django.contrib.messages.views import SuccessMessageMixin -from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ -from django.views import generic - -from braces.views import LoginRequiredMixin - -from .forms import FeedbackForm -from .models import Feedback - - -class FeedbackCreate(LoginRequiredMixin, SuccessMessageMixin, generic.CreateView): - model = Feedback - form_class = FeedbackForm - success_message = _('Feedback verstuurd') - - def get_initial(self): - """Sets URL to the referrer and submitter to current User""" - initial = super(FeedbackCreate, self).get_initial() - initial['url'] = self.request.META.get('HTTP_REFERER') - return initial - - def form_valid(self, form): - """Sets submitter to current User""" - form.instance.submitter = self.request.user - return super(FeedbackCreate, self).form_valid(form) - - def get_success_url(self): - """Redirect to thank-you page""" - return reverse('feedback:thanks', args=(self.object.pk,)) - - -class FeedbackThanks(LoginRequiredMixin, generic.DetailView): - model = Feedback - template_name = 'feedback/feedback_thanks.html' - - -class FeedbackListing(LoginRequiredMixin, generic.ListView): - model = Feedback diff --git a/fetc/constants.py b/fetc/constants.py index a35827f82..96d9745c5 100644 --- a/fetc/constants.py +++ b/fetc/constants.py @@ -2,10 +2,12 @@ # Separate to make deployment less of a hassle # Group names -GROUP_SECRETARY = 'Secretaris' -GROUP_PRIMARY_SECRETARY = 'Primaire secretaris' -GROUP_LINGUISTICS_CHAMBER = 'LK' -GROUP_GENERAL_CHAMBER = 'AK' +GROUP_SECRETARY = "Secretaris" +GROUP_PRIMARY_SECRETARY = "Primaire secretaris" +GROUP_LINGUISTICS_CHAMBER = "LK" +GROUP_GENERAL_CHAMBER = "AK" +GROUP_CHAIR = "Voorzitter" +GROUP_PO = "Privacy officer" # Route durations PREASSESSMENT_ROUTE_WEEKS = 1 diff --git a/fetc/saml_settings.example.py b/fetc/saml_settings.example.py index bae4171da..5ee23de12 100644 --- a/fetc/saml_settings.example.py +++ b/fetc/saml_settings.example.py @@ -16,6 +16,7 @@ consult the CDH Federated Authentication docs: https://centrefordigitalhumanities.github.io/Federated-Authentication-Docs/ """ + import os # Import all default SAML settings from the library, we override some later @@ -32,11 +33,11 @@ # See also: # https://djangosaml2.readthedocs.io/contents/setup.html#users-attributes-and-account-linking SAML_ATTRIBUTE_MAPPING = { - 'uuShortID': ('username',), - 'mail': ('email',), - 'givenName': ('first_name',), - 'uuPrefixedSn': ('last_name',), - 'uuLegacyDepartment': ('process_faculties', ), + "uuShortID": ("username",), + "mail": ("email",), + "givenName": ("first_name",), + "uuPrefixedSn": ("last_name",), + "uuLegacyDepartment": ("process_faculties",), } # Controls which mechanism is used to exchange SAML data with the IdP @@ -51,39 +52,41 @@ # localhost, port 8000. Please change if you run the app on a different # hostname/port # Note that localhost and 127.0.0.1 are not interchangeable here - base_url='http://localhost:8000/', + base_url="http://localhost:8000/", # The name of the app, does not _really_ matter - name='FEtC-H Portal', + name="FEtC-H Portal", # The full location of the private key of the cert, currently # /certs/private.key - key_file=os.path.join(_BASE_DIR, 'certs/private.key'), + key_file=os.path.join(_BASE_DIR, "certs/private.key"), # The full location of the certificate, currently # /certs/private.key - cert_file=os.path.join(_BASE_DIR, 'certs/public.cert'), + cert_file=os.path.join(_BASE_DIR, "certs/public.cert"), # The location of the IdP's metadata # The current value is valid for the Development IdP, if run at port 7000 # If you run it in a different place/port, please update # If you use a different IdP, find its metadata URL and copy/paste it here - idp_metadata='http://localhost:7000/saml/idp/metadata/', + idp_metadata="http://localhost:7000/saml/idp/metadata/", # If set to True, the app will allow login attempts not requested by the app # This _can_ happen if a user logs in directly from the IdP. Currently set # to true, as the DevIdP can sometimes do funky stuff with the session ID allow_unsolicited=True, # A list of attributes the IdP needs to provide for the app to authenticate # Uses the naming of the IdP, not the internal names in Django - required_attributes=['uuShortID', 'mail', 'givenName', 'uuPrefixedSn'], + required_attributes=["uuShortID", "mail", "givenName", "uuPrefixedSn"], # A list of nice-to-have attributes from the IdP # Uses the naming of the IdP, not the internal names in Django - optional_attributes=['uuLegacyDepartment', ], + optional_attributes=[ + "uuLegacyDepartment", + ], # Contact info for this app; will be added to the app's metadata and is # generally used by the IdP admins to contact all app-admins if they change # something. - contact_given_name='Humanities IT Portal Development', - contact_email='portaldev.gw@uu.nl', + contact_given_name="Humanities IT Portal Development", + contact_email="portaldev.gw@uu.nl", ) # Add the SAML auth backend to the list of enabled backends. AUTHENTICATION_BACKENDS = ( - 'django.contrib.auth.backends.ModelBackend', - 'djangosaml2.backends.Saml2Backend', + "django.contrib.auth.backends.ModelBackend", + "djangosaml2.backends.Saml2Backend", ) diff --git a/fetc/settings.py b/fetc/settings.py index 45697d112..6b753f47e 100644 --- a/fetc/settings.py +++ b/fetc/settings.py @@ -9,6 +9,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.8/ref/settings/ """ + import os from django.core.exceptions import ImproperlyConfigured @@ -21,78 +22,74 @@ # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ -SECRET_KEY = 'j8dwfg6kvg=fnfs33s0x(t&0pfe)p9$3dm943)6hvurj6@=+4j' +SECRET_KEY = "j8dwfg6kvg=fnfs33s0x(t&0pfe)p9$3dm943)6hvurj6@=+4j" DEBUG = True ALLOWED_HOSTS = [] -INTERNAL_IPS = ['127.0.0.1', 'localhost'] -WSGI_APPLICATION = 'fetc.wsgi.application' +INTERNAL_IPS = ["127.0.0.1", "localhost"] +WSGI_APPLICATION = "fetc.wsgi.application" # Application definition INSTALLED_APPS = [ - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'menu', - 'debug_toolbar', - 'django_extensions', - 'rest_framework', - - 'main', - 'uil.core', - 'uil.vue', - 'proposals', - 'studies', - 'tasks', - 'interventions', - 'observations', - 'reviews', - 'feedback', - 'faqs', - - 'modeltranslation', - 'impersonate', - - 'django.contrib.admin', - 'django_user_agents', + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "menu", + "debug_toolbar", + "django_extensions", + "rest_framework", + "main", + "uil.core", + "uil.vue", + "proposals", + "studies", + "tasks", + "interventions", + "observations", + "reviews", + "faqs", + "modeltranslation", + "impersonate", + "django.contrib.admin", + "django_user_agents", ] MIDDLEWARE = [ - 'debug_toolbar.middleware.DebugToolbarMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'django_user_agents.middleware.UserAgentMiddleware', - 'impersonate.middleware.ImpersonateMiddleware', + "debug_toolbar.middleware.DebugToolbarMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django.middleware.security.SecurityMiddleware", + "django_user_agents.middleware.UserAgentMiddleware", + "impersonate.middleware.ImpersonateMiddleware", ] TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -ROOT_URLCONF = 'fetc.urls' +ROOT_URLCONF = "fetc.urls" -LOGIN_REDIRECT_URL = '/' +LOGIN_REDIRECT_URL = "/" # Determines what login options are displayed on the landing page. NOTE: this # does not determine which login screen is actually used as default when using @@ -109,53 +106,50 @@ # https://docs.djangoproject.com/en/1.8/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.path.join(BASE_DIR, "db.sqlite3"), }, #'mysql': { # 'ENGINE': 'django.db.backends.mysql', # 'NAME': 'ethics', # 'USER': 'root', # 'PASSWORD': 'root++', - #} + # } } -DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' - +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # Internationalization # https://docs.djangoproject.com/en/1.8/topics/i18n/ -LANGUAGE_CODE = 'nl-NL' +LANGUAGE_CODE = "nl-NL" LANGUAGES = ( - ('nl', _('Nederlands')), - ('en', _('Engels')), + ("nl", _("Nederlands")), + ("en", _("Engels")), ) USE_I18N = True USE_L10N = True -LOCALE_PATHS = ( - 'locale', -) +LOCALE_PATHS = ("locale",) -TIME_ZONE = 'Europe/Amsterdam' +TIME_ZONE = "Europe/Amsterdam" USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.8/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = "/static/" # File handling -MEDIA_ROOT = 'media' -MEDIA_URL = '/media/' +MEDIA_ROOT = "media" +MEDIA_URL = "/media/" # E-mail settings -EMAIL_HOST = 'localhost' +EMAIL_HOST = "localhost" EMAIL_PORT = 2525 -EMAIL_FROM = 'T.D.Mees@uu.nl' -EMAIL_LOCAL_STAFF = 'T.D.Mees@uu.nl' +EMAIL_FROM = "T.D.Mees@uu.nl" +EMAIL_LOCAL_STAFF = "T.D.Mees@uu.nl" # Django Simple Menu # https://django-simple-menu.readthedocs.io/en/latest/index.html @@ -164,10 +158,10 @@ MENU_HIDE_EMPTY = False # Base URL -BASE_URL = '127.0.0.1:8000' +BASE_URL = "127.0.0.1:8000" # CSRF Setting -CSRF_FAILURE_VIEW = 'main.error_views.csrf_failure' +CSRF_FAILURE_VIEW = "main.error_views.csrf_failure" try: from .constants import * @@ -177,7 +171,7 @@ try: from .ldap_settings import * except ImportError: - print('Proceeding without LDAP settings') + print("Proceeding without LDAP settings") try: from .saml_settings import * @@ -186,11 +180,11 @@ INSTALLED_APPS += SAML_APPS MIDDLEWARE += SAML_MIDDLEWARE - LOGIN_URL = reverse_lazy('saml-login') + LOGIN_URL = reverse_lazy("saml-login") SHOW_SAML_LOGIN = True # Custom proxy model for SAML attribute processing - SAML_USER_MODEL = 'main.SamlUserProxy' + SAML_USER_MODEL = "main.SamlUserProxy" except ImportError: - print('Proceeding without SAML settings') + print("Proceeding without SAML settings") diff --git a/fetc/urls.py b/fetc/urls.py index 09b9285ed..3e2ef8418 100644 --- a/fetc/urls.py +++ b/fetc/urls.py @@ -4,6 +4,7 @@ The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.8/topics/http/urls/ """ + from django.conf import settings from django.conf.urls.static import static from django.contrib import admin @@ -12,78 +13,69 @@ from main.views import UserMediaView -handler404 = 'main.error_views.error_404' -handler500 = 'main.error_views.error_500' -handler403 = 'main.error_views.error_403' -handler400 = 'main.error_views.error_400' +handler404 = "main.error_views.error_404" +handler500 = "main.error_views.error_500" +handler403 = "main.error_views.error_403" +handler400 = "main.error_views.error_400" urlpatterns = [ # Always keep the default login view available, just to be sure # We set the correct login view (this or SAML) in settings - path('accounts/login/', auth_views.LoginView.as_view(), name='login'), - + path("accounts/login/", auth_views.LoginView.as_view(), name="login"), # Access user uploads - path('media/', - UserMediaView.as_view(), - name='user_upload'), - - path('', include('main.urls')), - path('proposals/', include('proposals.urls')), - path('studies/', include('studies.urls')), - path('tasks/', include('tasks.urls')), - path('observations/', include('observations.urls')), - path('interventions/', include('interventions.urls')), - path('reviews/', include('reviews.urls')), - path('feedback/', include('feedback.urls')), - path('faqs/', include('faqs.urls')), - - path('admin/', admin.site.urls), - path('impersonate/', include('impersonate.urls')), - - path('i18n/', include('django.conf.urls.i18n')), - path('uilcore/', include('uil.core.urls')), - path('vue/', include('uil.vue.urls')), + path("media/", UserMediaView.as_view(), name="user_upload"), + path("", include("main.urls")), + path("proposals/", include("proposals.urls")), + path("studies/", include("studies.urls")), + path("tasks/", include("tasks.urls")), + path("observations/", include("observations.urls")), + path("interventions/", include("interventions.urls")), + path("reviews/", include("reviews.urls")), + path("faqs/", include("faqs.urls")), + path("admin/", admin.site.urls), + path("impersonate/", include("impersonate.urls")), + path("i18n/", include("django.conf.urls.i18n")), + path("uilcore/", include("uil.core.urls")), + path("vue/", include("uil.vue.urls")), ] -if 'debug_toolbar' in settings.INSTALLED_APPS and settings.DEBUG: +if "debug_toolbar" in settings.INSTALLED_APPS and settings.DEBUG: import debug_toolbar urlpatterns.append( - path('__debug__/', include(debug_toolbar.urls)), + path("__debug__/", include(debug_toolbar.urls)), ) # If SAML is enabled, add the required URL patterns for SAML -if 'cdh.federated_auth' in settings.INSTALLED_APPS: +if "cdh.federated_auth" in settings.INSTALLED_APPS: from djangosaml2.views import EchoAttributesView, LoginView from cdh.federated_auth.saml.views import LogoutInitView - urlpatterns.extend([ - path('saml/login/', LoginView.as_view(), name='saml-login'), - # We can only have one logout view. Luckily, the SAML logout view can - # handle local accounts as well. - path('saml/logout/', LogoutInitView.as_view(), name='logout'), - path('saml/', include('djangosaml2.urls')), - ]) + urlpatterns.extend( + [ + path("saml/login/", LoginView.as_view(), name="saml-login"), + # We can only have one logout view. Luckily, the SAML logout view can + # handle local accounts as well. + path("saml/logout/", LogoutInitView.as_view(), name="logout"), + path("saml/", include("djangosaml2.urls")), + ] + ) if settings.DEBUG: urlpatterns.append( path( - 'saml/echo_attributes/', + "saml/echo_attributes/", EchoAttributesView.as_view(), - name='saml-attributes' + name="saml-attributes", ) ) else: # If not, append the default logout-view urlpatterns.append( - path( - 'accounts/logout/', - auth_views.LogoutView.as_view(), - name='logout' - ), + path("accounts/logout/", auth_views.LogoutView.as_view(), name="logout"), ) -admin.site.site_header = 'FETC-GW' -admin.site.site_title = 'FETC-GW administratie' -admin.site.index_title = 'FETC-GW administratie' +admin.site.site_header = "FETC-GW" +admin.site.site_title = "FETC-GW administratie" +admin.site.index_title = "FETC-GW administratie" diff --git a/interventions/forms.py b/interventions/forms.py index e56cc86bf..1597f44b2 100644 --- a/interventions/forms.py +++ b/interventions/forms.py @@ -9,34 +9,42 @@ class InterventionForm(SoftValidationMixin, ConditionalModelForm): class Meta: model = Intervention fields = [ - 'setting', 'setting_details', 'supervision', 'leader_has_coc', - 'period', 'multiple_sessions', 'session_frequency', 'duration', - 'experimenter', 'description', - 'has_controls', 'controls_description', - 'measurement', 'extra_task' + "setting", + "setting_details", + "supervision", + "leader_has_coc", + "period", + "multiple_sessions", + "session_frequency", + "duration", + "experimenter", + "description", + "has_controls", + "controls_description", + "measurement", + "extra_task", ] widgets = { - 'setting': forms.CheckboxSelectMultiple(), - 'supervision': forms.RadioSelect(choices=YES_NO), - 'multiple_sessions': forms.RadioSelect(choices=YES_NO), - 'leader_has_coc': forms.RadioSelect(choices=YES_NO), - 'has_controls': forms.RadioSelect(choices=YES_NO), - 'extra_task': forms.RadioSelect(choices=YES_NO), + "setting": forms.CheckboxSelectMultiple(), + "supervision": forms.RadioSelect(choices=YES_NO), + "multiple_sessions": forms.RadioSelect(choices=YES_NO), + "leader_has_coc": forms.RadioSelect(choices=YES_NO), + "has_controls": forms.RadioSelect(choices=YES_NO), + "extra_task": forms.RadioSelect(choices=YES_NO), } - def __init__(self, *args, **kwargs): """ - Set the Study for later reference - Don't ask the supervision question when there are only adult AgeGroups in this Study """ - self.study = kwargs.pop('study', None) + self.study = kwargs.pop("study", None) super(InterventionForm, self).__init__(*args, **kwargs) if not self.study.has_children(): - del self.fields['supervision'] - del self.fields['leader_has_coc'] + del self.fields["supervision"] + del self.fields["leader_has_coc"] def get_soft_validation_fields(self): # We want soft validation on all fields @@ -53,21 +61,22 @@ def clean(self): self.mark_soft_required( cleaned_data, - 'setting', - 'period', - 'experimenter', - 'description', - 'measurement', + "setting", + "period", + "experimenter", + "description", + "measurement", ) - self.check_dependency_multiple(cleaned_data, 'setting', 'needs_details', - 'setting_details') + self.check_dependency_multiple( + cleaned_data, "setting", "needs_details", "setting_details" + ) if self.study.has_children(): - self.check_dependency_multiple(cleaned_data, 'setting', - 'needs_supervision', 'supervision') - self.check_dependency(cleaned_data, 'supervision', 'leader_has_coc', - f1_value=False) - self.check_dependency(cleaned_data, 'has_controls', - 'controls_description') - self.check_dependency(cleaned_data, 'multiple_sessions', - 'session_frequency') + self.check_dependency_multiple( + cleaned_data, "setting", "needs_supervision", "supervision" + ) + self.check_dependency( + cleaned_data, "supervision", "leader_has_coc", f1_value=False + ) + self.check_dependency(cleaned_data, "has_controls", "controls_description") + self.check_dependency(cleaned_data, "multiple_sessions", "session_frequency") diff --git a/interventions/migrations/0001_initial.py b/interventions/migrations/0001_initial.py index bd828f72b..9d16a19a4 100644 --- a/interventions/migrations/0001_initial.py +++ b/interventions/migrations/0001_initial.py @@ -5,32 +5,99 @@ class Migration(migrations.Migration): - dependencies = [ - ('studies', '0001_initial'), - ('main', '0001_initial'), + ("studies", "0001_initial"), + ("main", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Intervention', + name="Intervention", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('setting_details', models.CharField(max_length=200, verbose_name='Namelijk', blank=True)), - ('supervision', models.NullBooleanField(verbose_name='Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?')), - ('period', models.TextField(verbose_name='Wat is de periode waarbinnen de interventie plaatsvindt?')), - ('amount_per_week', models.PositiveIntegerField(verbose_name='Hoe vaak per week vindt de interventiesessie plaats?')), - ('duration', models.PositiveIntegerField(verbose_name='Wat is de duur van de interventie per sessie in minuten?')), - ('experimenter', models.TextField(verbose_name='Wie voert de interventie uit?')), - ('description', models.TextField(verbose_name='Geef een beschrijving van de experimentele interventie')), - ('has_controls', models.BooleanField(default=False, verbose_name='Is er sprake van een controlegroep?')), - ('controls_description', models.TextField(verbose_name='Geef een beschrijving van de controleinterventie', blank=True)), - ('measurement', models.TextField(help_text='Wanneer u de deelnemer extra taken laat uitvoeren, dus een taak die niet behoort tot het reguliere onderwijspakket, dan moet u op de vorige pagina ook "takenonderzoek" aanvinken.', verbose_name='Hoe wordt het effect van de interventie gemeten?')), - ('setting', models.ManyToManyField(to='main.Setting', verbose_name='Geef aan waar de dataverzameling plaatsvindt')), - ('study', models.OneToOneField(to='studies.Study', on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "setting_details", + models.CharField( + max_length=200, verbose_name="Namelijk", blank=True + ), + ), + ( + "supervision", + models.NullBooleanField( + verbose_name="Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?" + ), + ), + ( + "period", + models.TextField( + verbose_name="Wat is de periode waarbinnen de interventie plaatsvindt?" + ), + ), + ( + "amount_per_week", + models.PositiveIntegerField( + verbose_name="Hoe vaak per week vindt de interventiesessie plaats?" + ), + ), + ( + "duration", + models.PositiveIntegerField( + verbose_name="Wat is de duur van de interventie per sessie in minuten?" + ), + ), + ( + "experimenter", + models.TextField(verbose_name="Wie voert de interventie uit?"), + ), + ( + "description", + models.TextField( + verbose_name="Geef een beschrijving van de experimentele interventie" + ), + ), + ( + "has_controls", + models.BooleanField( + default=False, + verbose_name="Is er sprake van een controlegroep?", + ), + ), + ( + "controls_description", + models.TextField( + verbose_name="Geef een beschrijving van de controleinterventie", + blank=True, + ), + ), + ( + "measurement", + models.TextField( + help_text='Wanneer u de deelnemer extra taken laat uitvoeren, dus een taak die niet behoort tot het reguliere onderwijspakket, dan moet u op de vorige pagina ook "takenonderzoek" aanvinken.', + verbose_name="Hoe wordt het effect van de interventie gemeten?", + ), + ), + ( + "setting", + models.ManyToManyField( + to="main.Setting", + verbose_name="Geef aan waar de dataverzameling plaatsvindt", + ), + ), + ( + "study", + models.OneToOneField(to="studies.Study", on_delete=models.CASCADE), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), ] diff --git a/interventions/migrations/0002_intervention_leader_has_coc.py b/interventions/migrations/0002_intervention_leader_has_coc.py index de8abbd8d..d9ba88883 100644 --- a/interventions/migrations/0002_intervention_leader_has_coc.py +++ b/interventions/migrations/0002_intervention_leader_has_coc.py @@ -5,15 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('interventions', '0001_initial'), + ("interventions", "0001_initial"), ] operations = [ migrations.AddField( - model_name='intervention', - name='leader_has_coc', - field=models.NullBooleanField(help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De ETCL neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', verbose_name='Is de testleider in het bezit van een VOG?'), + model_name="intervention", + name="leader_has_coc", + field=models.NullBooleanField( + help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De ETCL neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', + verbose_name="Is de testleider in het bezit van een VOG?", + ), ), ] diff --git a/interventions/migrations/0003_auto_20180808_1131.py b/interventions/migrations/0003_auto_20180808_1131.py index 1bdbd951e..38cf377ce 100644 --- a/interventions/migrations/0003_auto_20180808_1131.py +++ b/interventions/migrations/0003_auto_20180808_1131.py @@ -6,30 +6,42 @@ class Migration(migrations.Migration): - dependencies = [ - ('interventions', '0002_intervention_leader_has_coc'), + ("interventions", "0002_intervention_leader_has_coc"), ] operations = [ migrations.AddField( - model_name='intervention', - name='extra_task', - field=models.BooleanField(default=False, help_text='Moet het nog een taak doen, zoals het invullen van een (onderzoeks)vragenlijst, die niet binnen de interventie zelf valt?', verbose_name='Voert de leerling nog een taak uit die niet onder het leerplan valt?'), + model_name="intervention", + name="extra_task", + field=models.BooleanField( + default=False, + help_text="Moet het nog een taak doen, zoals het invullen van een (onderzoeks)vragenlijst, die niet binnen de interventie zelf valt?", + verbose_name="Voert de leerling nog een taak uit die niet onder het leerplan valt?", + ), ), migrations.AddField( - model_name='intervention', - name='multiple_sessions', - field=models.BooleanField(default=False, verbose_name='Zal de interventie vaker dan één keer plaatsvinden?'), + model_name="intervention", + name="multiple_sessions", + field=models.BooleanField( + default=False, + verbose_name="Zal de interventie vaker dan één keer plaatsvinden?", + ), ), migrations.AddField( - model_name='intervention', - name='version', - field=models.PositiveIntegerField(default=1, verbose_name='INTERNAL - Describes which version of the intervention model is used'), + model_name="intervention", + name="version", + field=models.PositiveIntegerField( + default=1, + verbose_name="INTERNAL - Describes which version of the intervention model is used", + ), ), migrations.AlterField( - model_name='intervention', - name='period', - field=models.TextField(help_text='De interventie vindt plaats binnen het schooljaar 2018-2019', verbose_name='Wat is de periode waarbinnen de interventie plaatsvindt?'), + model_name="intervention", + name="period", + field=models.TextField( + help_text="De interventie vindt plaats binnen het schooljaar 2018-2019", + verbose_name="Wat is de periode waarbinnen de interventie plaatsvindt?", + ), ), ] diff --git a/interventions/migrations/0004_auto_20180808_1327.py b/interventions/migrations/0004_auto_20180808_1327.py index 5ead67d5c..1738e3a2b 100644 --- a/interventions/migrations/0004_auto_20180808_1327.py +++ b/interventions/migrations/0004_auto_20180808_1327.py @@ -6,25 +6,33 @@ class Migration(migrations.Migration): - dependencies = [ - ('interventions', '0003_auto_20180808_1131'), + ("interventions", "0003_auto_20180808_1131"), ] operations = [ migrations.AddField( - model_name='intervention', - name='session_frequency', - field=models.TextField(blank=True, verbose_name='Wat is de frequentie van de interventie?'), + model_name="intervention", + name="session_frequency", + field=models.TextField( + blank=True, verbose_name="Wat is de frequentie van de interventie?" + ), ), migrations.AlterField( - model_name='intervention', - name='amount_per_week', - field=models.PositiveIntegerField(blank=True, default=1, verbose_name='Hoe vaak per week vindt de interventiesessie plaats?'), + model_name="intervention", + name="amount_per_week", + field=models.PositiveIntegerField( + blank=True, + default=1, + verbose_name="Hoe vaak per week vindt de interventiesessie plaats?", + ), ), migrations.AlterField( - model_name='intervention', - name='version', - field=models.PositiveIntegerField(default=2, verbose_name='INTERNAL - Describes which version of the intervention model is used'), + model_name="intervention", + name="version", + field=models.PositiveIntegerField( + default=2, + verbose_name="INTERNAL - Describes which version of the intervention model is used", + ), ), ] diff --git a/interventions/migrations/0005_auto_20190206_1119.py b/interventions/migrations/0005_auto_20190206_1119.py index 47a184b62..d3cb41e01 100644 --- a/interventions/migrations/0005_auto_20190206_1119.py +++ b/interventions/migrations/0005_auto_20190206_1119.py @@ -6,40 +6,60 @@ class Migration(migrations.Migration): - dependencies = [ - ('interventions', '0004_auto_20180808_1327'), + ("interventions", "0004_auto_20180808_1327"), ] operations = [ migrations.AlterField( - model_name='intervention', - name='description', - field=models.TextField(blank=True, verbose_name='Geef een beschrijving van de experimentele interventie'), + model_name="intervention", + name="description", + field=models.TextField( + blank=True, + verbose_name="Geef een beschrijving van de experimentele interventie", + ), ), migrations.AlterField( - model_name='intervention', - name='duration', - field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Wat is de duur van de interventie per sessie in minuten?'), + model_name="intervention", + name="duration", + field=models.PositiveIntegerField( + blank=True, + null=True, + verbose_name="Wat is de duur van de interventie per sessie in minuten?", + ), ), migrations.AlterField( - model_name='intervention', - name='experimenter', - field=models.TextField(blank=True, verbose_name='Wie voert de interventie uit?'), + model_name="intervention", + name="experimenter", + field=models.TextField( + blank=True, verbose_name="Wie voert de interventie uit?" + ), ), migrations.AlterField( - model_name='intervention', - name='measurement', - field=models.TextField(blank=True, help_text='Wanneer u de deelnemer extra taken laat uitvoeren, dus een taak die niet behoort tot het reguliere onderwijspakket, dan moet u op de vorige pagina ook "takenonderzoek" aanvinken.', verbose_name='Hoe wordt het effect van de interventie gemeten?'), + model_name="intervention", + name="measurement", + field=models.TextField( + blank=True, + help_text='Wanneer u de deelnemer extra taken laat uitvoeren, dus een taak die niet behoort tot het reguliere onderwijspakket, dan moet u op de vorige pagina ook "takenonderzoek" aanvinken.', + verbose_name="Hoe wordt het effect van de interventie gemeten?", + ), ), migrations.AlterField( - model_name='intervention', - name='period', - field=models.TextField(blank=True, help_text='De interventie vindt plaats binnen het schooljaar 2018-2019', verbose_name='Wat is de periode waarbinnen de interventie plaatsvindt?'), + model_name="intervention", + name="period", + field=models.TextField( + blank=True, + help_text="De interventie vindt plaats binnen het schooljaar 2018-2019", + verbose_name="Wat is de periode waarbinnen de interventie plaatsvindt?", + ), ), migrations.AlterField( - model_name='intervention', - name='setting', - field=models.ManyToManyField(blank=True, to='main.Setting', verbose_name='Geef aan waar de dataverzameling plaatsvindt'), + model_name="intervention", + name="setting", + field=models.ManyToManyField( + blank=True, + to="main.Setting", + verbose_name="Geef aan waar de dataverzameling plaatsvindt", + ), ), ] diff --git a/interventions/migrations/0006_auto_20190401_1343.py b/interventions/migrations/0006_auto_20190401_1343.py index 854377cc3..21e3ff7b3 100644 --- a/interventions/migrations/0006_auto_20190401_1343.py +++ b/interventions/migrations/0006_auto_20190401_1343.py @@ -6,15 +6,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('interventions', '0005_auto_20190206_1119'), + ("interventions", "0005_auto_20190206_1119"), ] operations = [ migrations.AlterField( - model_name='intervention', - name='leader_has_coc', - field=models.NullBooleanField(help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', verbose_name='Is de testleider in het bezit van een VOG?'), + model_name="intervention", + name="leader_has_coc", + field=models.NullBooleanField( + help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', + verbose_name="Is de testleider in het bezit van een VOG?", + ), ), ] diff --git a/interventions/migrations/0007_auto_20200428_1337.py b/interventions/migrations/0007_auto_20200428_1337.py index 47f5ecd24..dc22c5091 100644 --- a/interventions/migrations/0007_auto_20200428_1337.py +++ b/interventions/migrations/0007_auto_20200428_1337.py @@ -4,20 +4,28 @@ class Migration(migrations.Migration): - dependencies = [ - ('interventions', '0006_auto_20190401_1343'), + ("interventions", "0006_auto_20190401_1343"), ] operations = [ migrations.AlterField( - model_name='intervention', - name='leader_has_coc', - field=models.BooleanField(blank=True, help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', null=True, verbose_name='Is de testleider in het bezit van een VOG?'), + model_name="intervention", + name="leader_has_coc", + field=models.BooleanField( + blank=True, + help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', + null=True, + verbose_name="Is de testleider in het bezit van een VOG?", + ), ), migrations.AlterField( - model_name='intervention', - name='supervision', - field=models.BooleanField(blank=True, null=True, verbose_name='Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?'), + model_name="intervention", + name="supervision", + field=models.BooleanField( + blank=True, + null=True, + verbose_name="Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?", + ), ), ] diff --git a/interventions/migrations/0008_auto_20220103_1527.py b/interventions/migrations/0008_auto_20220103_1527.py index 93cc22f1e..a2868ecee 100644 --- a/interventions/migrations/0008_auto_20220103_1527.py +++ b/interventions/migrations/0008_auto_20220103_1527.py @@ -4,15 +4,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('interventions', '0007_auto_20200428_1337'), + ("interventions", "0007_auto_20200428_1337"), ] operations = [ migrations.AlterField( - model_name='intervention', - name='measurement', - field=models.TextField(blank=True, help_text='Wanneer je de deelnemer extra taken laat uitvoeren, dus een taak die niet behoort tot het reguliere onderwijspakket, dan moet je op de vorige pagina ook "takenonderzoek" aanvinken.', verbose_name='Hoe wordt het effect van de interventie gemeten?'), + model_name="intervention", + name="measurement", + field=models.TextField( + blank=True, + help_text='Wanneer je de deelnemer extra taken laat uitvoeren, dus een taak die niet behoort tot het reguliere onderwijspakket, dan moet je op de vorige pagina ook "takenonderzoek" aanvinken.', + verbose_name="Hoe wordt het effect van de interventie gemeten?", + ), ), ] diff --git a/interventions/migrations/0009_alter_intervention_has_controls.py b/interventions/migrations/0009_alter_intervention_has_controls.py index 3feeba302..6753469ac 100644 --- a/interventions/migrations/0009_alter_intervention_has_controls.py +++ b/interventions/migrations/0009_alter_intervention_has_controls.py @@ -4,15 +4,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('interventions', '0008_auto_20220103_1527'), + ("interventions", "0008_auto_20220103_1527"), ] operations = [ migrations.AlterField( - model_name='intervention', - name='has_controls', - field=models.BooleanField(default=False, verbose_name='Is er sprake van een controlegroep? (Let op: als de controlegroep ook een ander soort taken krijgt, moet je hier een apart traject voor aanmaken)'), + model_name="intervention", + name="has_controls", + field=models.BooleanField( + default=False, + verbose_name="Is er sprake van een controlegroep? (Let op: als de controlegroep ook een ander soort taken krijgt, moet je hier een apart traject voor aanmaken)", + ), ), ] diff --git a/interventions/models.py b/interventions/models.py index b7746a6cd..ecb027ce7 100644 --- a/interventions/models.py +++ b/interventions/models.py @@ -6,73 +6,80 @@ class Intervention(SettingModel): - # This is used internally to provide backwards compatibility with the old version of this model. All old fields are # still used if this is 1. - version = models.PositiveIntegerField('INTERNAL - Describes which version of the intervention model is used', default=2) + version = models.PositiveIntegerField( + "INTERNAL - Describes which version of the intervention model is used", + default=2, + ) period = models.TextField( - _('Wat is de periode waarbinnen de interventie plaatsvindt?'), - help_text=_('De interventie vindt plaats binnen het schooljaar ' - '2018-2019'), + _("Wat is de periode waarbinnen de interventie plaatsvindt?"), + help_text=_("De interventie vindt plaats binnen het schooljaar " "2018-2019"), blank=True, ) multiple_sessions = models.BooleanField( - _('Zal de interventie vaker dan één keer plaatsvinden?'), + _("Zal de interventie vaker dan één keer plaatsvinden?"), default=False, ) session_frequency = models.TextField( - _('Wat is de frequentie van de interventie?'), + _("Wat is de frequentie van de interventie?"), blank=True, ) duration = models.PositiveIntegerField( - _('Wat is de duur van de interventie per sessie in minuten?'), + _("Wat is de duur van de interventie per sessie in minuten?"), blank=True, null=True, ) experimenter = models.TextField( - _('Wie voert de interventie uit?'), + _("Wie voert de interventie uit?"), blank=True, ) description = models.TextField( - _('Geef een beschrijving van de experimentele interventie'), + _("Geef een beschrijving van de experimentele interventie"), blank=True, ) has_controls = models.BooleanField( - _('Is er sprake van een controlegroep? (Let op: als de controlegroep \ + _( + "Is er sprake van een controlegroep? (Let op: als de controlegroep \ ook een ander soort taken krijgt, moet je hier een apart traject \ -voor aanmaken)'), +voor aanmaken)" + ), default=False, ) controls_description = models.TextField( - _('Geef een beschrijving van de controleinterventie'), + _("Geef een beschrijving van de controleinterventie"), blank=True, ) measurement = models.TextField( - _('Hoe wordt het effect van de interventie gemeten?'), - help_text=_('Wanneer je de deelnemer extra taken laat uitvoeren, \ + _("Hoe wordt het effect van de interventie gemeten?"), + help_text=_( + 'Wanneer je de deelnemer extra taken laat uitvoeren, \ dus een taak die niet behoort tot het reguliere onderwijspakket, dan moet \ -je op de vorige pagina ook "takenonderzoek" aanvinken.'), +je op de vorige pagina ook "takenonderzoek" aanvinken.' + ), blank=True, ) extra_task = models.BooleanField( - _('Voert de leerling nog een taak uit die niet onder het leerplan valt?'), - help_text=_('Moet het nog een taak doen, zoals het invullen van een (onderzoeks)vragenlijst, die niet binnen de interventie zelf valt?'), + _("Voert de leerling nog een taak uit die niet onder het leerplan valt?"), + help_text=_( + "Moet het nog een taak doen, zoals het invullen van een (onderzoeks)vragenlijst, die niet binnen de interventie zelf valt?" + ), default=False, ) # Legacy, not used in version 2 of the form amount_per_week = models.PositiveIntegerField( - _('Hoe vaak per week vindt de interventiesessie plaats?'), + _("Hoe vaak per week vindt de interventiesessie plaats?"), blank=True, default=1, ) diff --git a/interventions/templates/interventions/intervention_form.html b/interventions/templates/interventions/intervention_form.html index bb0bddae0..a28285223 100644 --- a/interventions/templates/interventions/intervention_form.html +++ b/interventions/templates/interventions/intervention_form.html @@ -45,12 +45,11 @@ {% with nav_items=study.proposal.available_urls active=3 %} {% include 'base/navigation.html' %} {% endwith %} -

- {% trans "Het interventieonderzoek" %} -

+

{% trans "Het interventieonderzoek" %}

{% include "main/setting_checks.html" %} {% include "studies/study_title.html" %} -
{% csrf_token %} + + {% csrf_token %} {{ form.as_table }} @@ -58,10 +57,10 @@

- {% blocktrans trimmed %} - Als je dit nog niet gedaan hebt, zul je op de vorige pagina naast "interventie" - ook "takenonderzoek" moeten aanvinken, om je aanvraag volledig in te vullen. - {% endblocktrans %} + {% blocktrans trimmed %} + Als je dit nog niet gedaan hebt, zul je op de vorige pagina naast "interventie" + ook "takenonderzoek" moeten aanvinken, om je aanvraag volledig in te vullen. + {% endblocktrans %}
diff --git a/interventions/urls.py b/interventions/urls.py index 82346d215..4aa31867f 100644 --- a/interventions/urls.py +++ b/interventions/urls.py @@ -2,9 +2,9 @@ from .views import InterventionCreate, InterventionUpdate -app_name = 'interventions' +app_name = "interventions" urlpatterns = [ - path('create//', InterventionCreate.as_view(), name='create'), - path('update//', InterventionUpdate.as_view(), name='update'), + path("create//", InterventionCreate.as_view(), name="create"), + path("update//", InterventionUpdate.as_view(), name="update"), ] diff --git a/interventions/utils.py b/interventions/utils.py index a88e64a26..de7cf4921 100644 --- a/interventions/utils.py +++ b/interventions/utils.py @@ -8,12 +8,12 @@ def intervention_url(study): """ Returns the available URLs for an Intervention """ - result = AvailableURL(title=_('Interventieonderzoek'), margin=2) + result = AvailableURL(title=_("Interventieonderzoek"), margin=2) if study.has_intervention: - if hasattr(study, 'intervention'): - result.url = reverse('interventions:update', args=(study.intervention.pk,)) + if hasattr(study, "intervention"): + result.url = reverse("interventions:update", args=(study.intervention.pk,)) else: - result.url = reverse('interventions:create', args=(study.pk,)) + result.url = reverse("interventions:create", args=(study.pk,)) return result diff --git a/interventions/views.py b/interventions/views.py index 0771e8e66..d1b3e79af 100644 --- a/interventions/views.py +++ b/interventions/views.py @@ -14,40 +14,41 @@ ############################## class InterventionMixin(object): """Mixin for an Intervention, to use in both InterventionCreate and InterventionUpdate below""" + model = Intervention form_class = InterventionForm - success_message = _('Interventie opgeslagen') + success_message = _("Interventie opgeslagen") def get_context_data(self, **kwargs): """Setting the Study and progress on the context""" context = super(InterventionMixin, self).get_context_data(**kwargs) study = self.get_study() - context['study'] = study - context['progress'] = get_study_progress(study) + 7 + context["study"] = study + context["progress"] = get_study_progress(study) + 7 return context def get_form_kwargs(self): """Sets the Study as a form kwarg""" kwargs = super(InterventionMixin, self).get_form_kwargs() - kwargs['study'] = self.get_study() + kwargs["study"] = self.get_study() return kwargs def get_next_url(self): study = self.get_study() - next_url = 'studies:design_end' + next_url = "studies:design_end" pk = study.pk if study.has_observation: - if hasattr(study, 'observation'): - next_url = 'observations:update' + if hasattr(study, "observation"): + next_url = "observations:update" pk = study.observation.pk else: - next_url = 'observations:create' + next_url = "observations:create" elif study.has_sessions: - next_url = 'studies:session_start' + next_url = "studies:session_start" return reverse(next_url, args=(pk,)) def get_back_url(self): - return reverse('studies:design', args=(self.get_study().pk,)) + return reverse("studies:design", args=(self.get_study().pk,)) def get_study(self): raise NotImplementedError @@ -63,7 +64,7 @@ def form_valid(self, form): def get_study(self): """Retrieves the Study from the pk kwarg""" - return Study.objects.get(pk=self.kwargs['pk']) + return Study.objects.get(pk=self.kwargs["pk"]) class InterventionUpdate(InterventionMixin, AllowErrorsOnBackbuttonMixin, UpdateView): diff --git a/locale/en/LC_MESSAGES/django.mo b/locale/en/LC_MESSAGES/django.mo deleted file mode 100644 index 937898bd6..000000000 Binary files a/locale/en/LC_MESSAGES/django.mo and /dev/null differ diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index f6fae7c6b..6f60d5ff3 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -6,63 +6,18 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-23 13:58+0200\n" -"PO-Revision-Date: 2020-10-07 11:22+0200\n" +"POT-Creation-Date: 2024-03-19 16:09+0100\n" +"PO-Revision-Date: 2024-01-17 10:48+0100\n" "Last-Translator: Anna Asbury \n" "Language-Team: \n" "Language: en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"#-#-#-#-# django.po.develop #-#-#-#-#\n" -"#-#-#-#-# django.po.develop #-#-#-#-#\n" -"#-#-#-#-# django.po.pr #-#-#-#-#\n" -"#-#-#-#-# django.po.pr #-#-#-#-#\n" -"#-#-#-#-# manual.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# github.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# django.po.develop #-#-#-#-#\n" -"#-#-#-#-# manual.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# github.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# django.po.develop #-#-#-#-#\n" -"#-#-#-#-# manual.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# github.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# django.po.acc #-#-#-#-#\n" -"#-#-#-#-# manual.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# github.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# django.po.acc #-#-#-#-#\n" -"#-#-#-#-# django.po.pr #-#-#-#-#\n" -"#-#-#-#-# manual.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# github.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# django.po.acc #-#-#-#-#\n" -"#-#-#-#-# manual.po #-#-#-#-#\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.4.1\n" -"#-#-#-#-# github.po #-#-#-#-#\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.4.1\n" -#: faqs/menus.py:7 main/templates/base/menu.html:125 -#: main/templates/main/index.html:201 +#: faqs/menus.py:7 main/templates/main/index.html:187 msgid "FETC-GW website" msgstr "FEtC-H website" @@ -74,16 +29,15 @@ msgstr "https://fetc-gw.wp.hum.uu.nl/en/" msgid "Reglement FETC-GW" msgstr "Regulations FEtC-H" -#: faqs/menus.py:13 main/templates/main/index.html:204 -#: proposals/templates/proposals/proposal_start_pre_approved.html:14 +#: faqs/menus.py:13 main/templates/main/index.html:190 +#: proposals/templates/proposals/proposal_start_pre_approved.html:11 msgid "https://fetc-gw.wp.hum.uu.nl/reglement-fetc-gw/" msgstr "https://fetc-gw.wp.hum.uu.nl/en/regulations-fetc-h/" -#: faqs/menus.py:17 main/templates/base/menu.html:134 -#: main/templates/main/index.html:209 -#: proposals/templates/proposals/proposal_pdf.html:430 +#: faqs/menus.py:17 main/templates/main/index.html:194 #: proposals/templates/proposals/study_consent.html:8 #: proposals/templates/proposals/translated_consent_forms.html:7 +#: proposals/utils/pdf_diff_logic.py:878 msgid "Informed consent formulieren" msgstr "Informed consent forms" @@ -93,17 +47,11 @@ msgstr "" "https://intranet.uu.nl/en/knowledgebase/documents-ethics-assessment-" "committee-humanities" -#: faqs/menus.py:22 main/templates/base/menu.html:137 +#: faqs/menus.py:22 msgid "FAQs" msgstr "FAQs" -#: faqs/menus.py:26 feedback/models.py:20 -#: feedback/templates/feedback/feedback_list.html:22 -#: main/templates/base/menu.html:140 -msgid "Feedback" -msgstr "Feedback" - -#: faqs/menus.py:31 main/templates/base/menu.html:122 +#: faqs/menus.py:30 msgid "Help" msgstr "Help" @@ -111,134 +59,47 @@ msgstr "Help" msgid "FAQ" msgstr "FAQ" -#: faqs/templates/faqs/faq_list.html:6 faqs/templates/faqs/faq_list.html:13 +#: faqs/templates/faqs/faq_list.html:6 faqs/templates/faqs/faq_list.html:12 msgid "Frequently Asked Questions" msgstr "Frequently Asked Questions" -#: feedback/models.py:6 -msgid "Open" -msgstr "Open" - -#: feedback/models.py:7 -msgid "Opgepakt" -msgstr "In progress" - -#: feedback/models.py:8 -msgid "Afgehandeld" -msgstr "Processed" - -#: feedback/models.py:12 -msgid "Laag" -msgstr "Low" - -#: feedback/models.py:13 -msgid "Gemiddeld" -msgstr "Average" - -#: feedback/models.py:14 -msgid "Hoog" -msgstr "High" - -#: feedback/templates/feedback/feedback_form.html:7 -#: feedback/templates/feedback/feedback_form.html:14 -#: feedback/templates/feedback/feedback_form.html:25 -msgid "Feedback versturen" -msgstr "Send feedback" - -#: feedback/templates/feedback/feedback_form.html:17 -msgid "Hier kan je feedback achterlaten op het FETC-GW portal." -msgstr "You can leave feedback on the FEtC-H portal here." - -#: feedback/templates/feedback/feedback_form.html:23 -#: observations/templates/observations/observation_update_attachments.html:39 -#: proposals/templates/proposals/proposal_confirmation.html:36 -#: proposals/templates/proposals/proposal_diff.html:294 -#: proposals/templates/proposals/proposal_diff.html:294 -#: proposals/templates/proposals/proposal_update_attachments.html:26 -#: reviews/templates/reviews/change_chamber_form.html:19 -#: reviews/templates/reviews/decision_form.html:90 -#: reviews/templates/reviews/review_assign_form.html:46 -#: reviews/templates/reviews/review_close_form.html:41 -#: reviews/templates/reviews/review_discontinue_form.html:72 -#: studies/templates/studies/study_update_attachments.html:26 -msgid "Terug naar de vorige pagina" -msgstr "Back to the previous page" - -#: feedback/templates/feedback/feedback_list.html:8 -#: feedback/templates/feedback/feedback_list.html:15 -msgid "Feedbackoverzicht" -msgstr "Feedback overview" - -#: feedback/templates/feedback/feedback_list.html:20 -msgid "Toegevoegd op" -msgstr "Added on" - -#: feedback/templates/feedback/feedback_list.html:21 -msgid "URL" -msgstr "URL" - -#: feedback/templates/feedback/feedback_list.html:23 -msgid "Gegeven door" -msgstr "Given by" - -#: feedback/templates/feedback/feedback_thanks.html:7 -#: feedback/templates/feedback/feedback_thanks.html:14 -msgid "Bedankt voor je feedback!" -msgstr "Thanks for your feedback!" - -#: feedback/templates/feedback/feedback_thanks.html:17 -#, python-format -msgid "" -"\n" -" Klik hier om terug te keren naar " -"pagina waar je gebleven was.\n" -" " -msgstr "" -"\n" -"Click here to return to where you left off.\n" -" " - -#: feedback/views.py:15 -msgid "Feedback verstuurd" -msgstr "Feedback sent" - -#: fetc/settings.py:132 +#: fetc/settings.py:129 msgid "Nederlands" msgstr "Dutch" -#: fetc/settings.py:133 +#: fetc/settings.py:130 msgid "Engels" msgstr "English" -#: interventions/models.py:15 +#: interventions/models.py:17 msgid "Wat is de periode waarbinnen de interventie plaatsvindt?" msgstr "What is the period in which the intervention will take place?" -#: interventions/models.py:16 +#: interventions/models.py:18 msgid "De interventie vindt plaats binnen het schooljaar 2018-2019" msgstr "The intervention will take place in the academic year 2018-2019" -#: interventions/models.py:22 +#: interventions/models.py:23 msgid "Zal de interventie vaker dan één keer plaatsvinden?" msgstr "Will there be more than one intervention session?" -#: interventions/models.py:27 +#: interventions/models.py:28 msgid "Wat is de frequentie van de interventie?" msgstr "What is the frequency of the intervention?" -#: interventions/models.py:32 +#: interventions/models.py:33 msgid "Wat is de duur van de interventie per sessie in minuten?" msgstr "What is the duration of the intervention session in minutes?" -#: interventions/models.py:38 +#: interventions/models.py:39 msgid "Wie voert de interventie uit?" msgstr "Who will conduct the intervention?" -#: interventions/models.py:43 +#: interventions/models.py:44 msgid "Geef een beschrijving van de experimentele interventie" msgstr "Give a description of the experimental intervention" -#: interventions/models.py:48 +#: interventions/models.py:50 msgid "" "Is er sprake van een controlegroep? (Let op: als de controlegroep ook een " "ander soort taken krijgt, moet je hier een apart traject voor aanmaken)" @@ -246,15 +107,15 @@ msgstr "" "Is there a control group? (If the control receives significantly different " "tasks, it should have its own trajectory)" -#: interventions/models.py:55 +#: interventions/models.py:58 msgid "Geef een beschrijving van de controleinterventie" msgstr "Give a description of the control intervention" -#: interventions/models.py:60 +#: interventions/models.py:63 msgid "Hoe wordt het effect van de interventie gemeten?" msgstr "How will the effect of the intervention be measured?" -#: interventions/models.py:61 +#: interventions/models.py:65 msgid "" "Wanneer je de deelnemer extra taken laat uitvoeren, dus een taak die niet " "behoort tot het reguliere onderwijspakket, dan moet je op de vorige pagina " @@ -264,12 +125,12 @@ msgstr "" "part of the regular educational package, you should also check \"task-based " "research\" on the previous page." -#: interventions/models.py:68 +#: interventions/models.py:73 msgid "Voert de leerling nog een taak uit die niet onder het leerplan valt?" msgstr "" "Does the pupil have to perform a task that is not part of the curriculum?" -#: interventions/models.py:69 +#: interventions/models.py:75 msgid "" "Moet het nog een taak doen, zoals het invullen van een " "(onderzoeks)vragenlijst, die niet binnen de interventie zelf valt?" @@ -277,23 +138,21 @@ msgstr "" "For example, does the pupil have to fill out a (research) questionnaire that " "is not part of intervention?" -#: interventions/models.py:75 +#: interventions/models.py:82 msgid "Hoe vaak per week vindt de interventiesessie plaats?" msgstr "How many times a week will the intervention session take place?" #: interventions/templates/interventions/intervention_form.html:7 -#: interventions/templates/interventions/intervention_form.html:49 -#: proposals/templates/proposals/diff/intervention.html:4 -#: proposals/templates/proposals/proposal_pdf.html:285 -#: proposals/templates/proposals/proposal_pdf_empty.html:186 +#: interventions/templates/interventions/intervention_form.html:48 +#: proposals/utils/pdf_diff_logic.py:605 msgid "Het interventieonderzoek" msgstr "Intervention study" #: interventions/templates/interventions/intervention_form.html:17 -#: main/models.py:57 -#: observations/templates/observations/observation_form.html:27 -#: studies/templates/studies/study_end.html:67 -#: studies/templates/studies/study_end.html:98 +#: main/models.py:50 +#: observations/templates/observations/observation_form.html:26 +#: studies/templates/studies/study_end.html:65 +#: studies/templates/studies/study_end.html:96 msgid "Setting" msgstr "Setting" @@ -305,7 +164,7 @@ msgstr "Description of the intervention" msgid "Extra taak" msgstr "Extra task" -#: interventions/templates/interventions/intervention_form.html:61 +#: interventions/templates/interventions/intervention_form.html:60 msgid "" "Als je dit nog niet gedaan hebt, zul je op de vorige pagina naast " "\"interventie\" ook \"takenonderzoek\" moeten aanvinken, om je aanvraag " @@ -315,62 +174,59 @@ msgstr "" "research\" on the previous page to answer the required task questions " "related to tasks." -#: interventions/utils.py:11 studies/models.py:144 studies/models.py:262 -#: studies/templates/studies/study_end.html:58 +#: interventions/utils.py:11 studies/models.py:270 +#: studies/templates/studies/study_end.html:56 msgid "Interventieonderzoek" msgstr "Interventional research" -#: interventions/views.py:19 +#: interventions/views.py:20 msgid "Interventie opgeslagen" msgstr "Intervention saved" #: main/forms/conditional_form.py:11 main/forms/conditional_form.py:20 -#: main/forms/conditional_form.py:29 main/forms/conditional_form.py:38 -#: main/forms/conditional_form.py:48 main/forms/mixins.py:83 -#: proposals/forms.py:560 proposals/forms.py:624 proposals/forms.py:639 -#: studies/forms.py:104 tasks/forms.py:87 +#: main/forms/conditional_form.py:31 main/forms/conditional_form.py:42 +#: main/forms/conditional_form.py:58 main/forms/mixins.py:81 +#: proposals/forms.py:614 proposals/forms.py:699 proposals/forms.py:720 +#: studies/forms.py:137 tasks/forms.py:104 msgid "Dit veld is verplicht." msgstr "This field is required." -#: main/menus.py:6 main/templates/base/menu.html:7 -#: main/templates/main/index.html:7 main/templates/main/index.html:24 -#: main/templates/main/landing.html:34 +#: main/menus.py:6 main/templates/main/index.html:7 +#: main/templates/main/index.html:53 main/templates/main/landing.html:33 msgid "Startpagina" msgstr "Start page" -#: main/menus.py:11 #: main/menus.py:11 msgid "Log in" msgstr "Log in" -#: main/menus.py:16 main/templates/base/login_header.html:7 -#: main/menus.py:16 main/templates/base/login_header.html:7 +#: main/menus.py:17 main/templates/base/login_header.html:7 msgid "Log uit" msgstr "Log out" -#: main/models.py:10 main/utils.py:13 +#: main/models.py:8 main/utils.py:16 proposals/utils/pdf_diff_logic.py:244 msgid "ja" msgstr "yes" -#: main/models.py:11 main/utils.py:13 +#: main/models.py:9 main/utils.py:16 proposals/utils/pdf_diff_logic.py:244 msgid "nee" msgstr "no" -#: main/models.py:12 +#: main/models.py:10 msgid "twijfel" msgstr "uncertain" -#: main/models.py:66 +#: main/models.py:59 msgid "Geef aan waar de dataverzameling plaatsvindt" msgstr "Specify where the data collection will take place" -#: main/models.py:68 observations/models.py:129 proposals/models.py:255 -#: studies/models.py:208 studies/models.py:244 tasks/models.py:157 -#: tasks/models.py:169 +#: main/models.py:63 observations/models.py:139 proposals/models.py:282 +#: studies/models.py:211 studies/models.py:253 tasks/models.py:169 +#: tasks/models.py:181 msgid "Namelijk" msgstr "Please specify" -#: main/models.py:75 +#: main/models.py:69 msgid "" "Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of " "een ander persoon die bevoegd is?" @@ -378,13 +234,13 @@ msgstr "" "Will the task be conducted under the supervision of the teacher or another " "qualified person?" -#: main/models.py:81 +#: main/models.py:76 msgid "Is de testleider in het bezit van een VOG?" msgstr "" "Does the test leader hold a Certificate of Conduct (Verklaring Omtrent " "Gedrag, VOG)?" -#: main/models.py:82 +#: main/models.py:78 msgid "" "Iedereen die op een school werkt moet in het bezit zijn van een " "Verklaring Omtrent Gedrag (VOG, zie >" msgstr "Save and go to next step >>" #: main/templates/base/login_header.html:6 msgid "Welkom {}" -msgstr "" - -#: main/templates/base/menu.html:11 proposals/menus.py:80 -msgid "Mijn aanvragen" -msgstr "My applications" - -#: main/templates/base/menu.html:14 proposals/menus.py:9 -msgid "Nieuwe aanvraag starten" -msgstr "Start a new application" - -#: main/templates/base/menu.html:17 -msgid "Nieuwe studie starten op basis van een kopie van een oude studie" -msgstr "Start a new study based on a copy of an old study" +msgstr "Welcome {}" -#: main/templates/base/menu.html:20 -msgid "Nieuwe voortoetsing aanvraag starten" -msgstr "Start a new preliminary application" - -#: main/templates/base/menu.html:23 -msgid "" -"Nieuwe aanvraag starten (die al goedgekeurd is door een andere ethische " -"toetsingscommissie)" -msgstr "" -"Start a new application (that has been approved by another ethics committee)" - -#: main/templates/base/menu.html:26 proposals/menus.py:30 -msgid "Maak een revisie van een bestaande aanvraag" -msgstr "Create a revision for an existing application" - -#: main/templates/base/menu.html:29 proposals/menus.py:34 -msgid "Maak een amendement van een al goedgekeurde aanvraag" -msgstr "Create an amendment to an already approved application" - -#: main/templates/base/menu.html:32 proposals/menus.py:56 -#: proposals/views/proposal_views.py:76 -#: proposals/views/proposal_views.py:76 -msgid "Mijn conceptaanvragen" -msgstr "My draft applications" - -#: main/templates/base/menu.html:35 proposals/menus.py:60 -#: proposals/views/proposal_views.py:126 -#: proposals/views/proposal_views.py:126 -msgid "Mijn oefenaanvragen" -msgstr "My practice applications" - -#: main/templates/base/menu.html:38 proposals/menus.py:64 -#: proposals/views/proposal_views.py:88 -#: proposals/views/proposal_views.py:88 -msgid "Mijn ingediende aanvragen" -msgstr "My submitted applications" - -#: main/templates/base/menu.html:41 proposals/menus.py:68 -#: proposals/views/proposal_views.py:100 -#: proposals/views/proposal_views.py:100 -msgid "Mijn afgehandelde aanvragen" -msgstr "My processed applications" - -#: main/templates/base/menu.html:44 proposals/menus.py:72 -#: proposals/views/proposal_views.py:112 -#: proposals/views/proposal_views.py:112 -msgid "Mijn aanvragen als eindverantwoordelijke" -msgstr "My supervised applications" - -#: main/templates/base/menu.html:47 proposals/menus.py:52 -msgid "Al mijn aanvragen" -msgstr "All my applications" - -#: main/templates/base/menu.html:52 proposals/menus.py:108 -#: proposals/views/proposal_views.py:149 -msgid "Archief" -msgstr "Archive" - -#: main/templates/base/menu.html:55 -msgid "Alle aanvragen bekijken van de Algemene Kamer" -msgstr "View all applications of the General Chamber" - -#: main/templates/base/menu.html:58 -msgid "Alle aanvragen bekijken van de Linguïstiek Kamer" -msgstr "" -"View all processed and approved applications of the Linguistics Chamber" - -#: main/templates/base/menu.html:62 proposals/menus.py:100 -msgid "Site-export" -msgstr "Site-export" - -#: main/templates/base/menu.html:69 reviews/forms.py:31 reviews/menus.py:60 -#: reviews/mixins.py:127 -msgid "Algemene Kamer" -msgstr "General Chamber" - -#: main/templates/base/menu.html:72 main/templates/base/menu.html:99 -#: reviews/menus.py:14 reviews/views.py:70 -msgid "Mijn openstaande besluiten" -msgstr "My pending decisions" - -#: main/templates/base/menu.html:75 main/templates/base/menu.html:102 -#: reviews/menus.py:18 -msgid "Al mijn besluiten" -msgstr "All my decisions" - -#: main/templates/base/menu.html:79 main/templates/base/menu.html:106 -#: reviews/menus.py:22 -msgid "Alle openstaande besluiten commissieleden" -msgstr "All pending decisions committee members" - -#: main/templates/base/menu.html:82 main/templates/base/menu.html:109 -#: reviews/menus.py:27 -msgid "Alle openstaande besluiten eindverantwoordelijken" -msgstr "All pending decisions supervisors" - -#: main/templates/base/menu.html:85 main/templates/base/menu.html:112 -#: reviews/menus.py:32 reviews/views.py:229 -msgid "Nog af te handelen aanvragen" -msgstr "Applications waiting for conclusion" - -#: main/templates/base/menu.html:88 main/templates/base/menu.html:115 -#: reviews/menus.py:47 reviews/views.py:275 -msgid "Alle ingezonden aanvragen" -msgstr "All submitted applications" - -#: main/templates/base/menu.html:96 reviews/forms.py:32 reviews/menus.py:67 -#: reviews/mixins.py:130 -msgid "Linguïstiek Kamer" -msgstr "Linguistics Chamber" - -#: main/templates/base/menu.html:128 -msgid "Reglement Algemene Kamer (AK)" -msgstr "Regulations General Chamber (GC)" - -#: main/templates/base/menu.html:131 -msgid " Reglement Linguïstiek Kamer (LK) " -msgstr " Regulations Linguistics Chamber (LC) " - -#: main/templates/base/menu.html:145 -#: main/templates/registration/logged_out.html:9 -msgid "Uitloggen" -msgstr "Log out" - -#: main/templates/base/menu.html:149 -msgid "FETC-GW-website" -msgstr "FEtC-H website" - -#: main/templates/base/menu.html:152 main/templates/main/landing.html:77 -#: main/templates/registration/login.html:15 -#: main/templates/registration/login.html:32 -#: main/templates/registration/login.html:15 -#: main/templates/registration/login.html:32 -msgid "Inloggen" -msgstr "Log in" - -#: main/templates/base/sidebar.html:27 +#: main/templates/base/sidebar.html:29 msgid "Toon voortgang" msgstr "Show progress" -#: main/templates/base/sidebar.html:30 +#: main/templates/base/sidebar.html:32 msgid "Sluiten" msgstr "Close" -#: main/templates/base/sidebar.html:31 +#: main/templates/base/sidebar.html:33 msgid "Voortgang" msgstr "Progress" -#: main/templates/base/site_header.html:2 +#: main/templates/base/site_header.html:3 msgid "Portal FETC - Geesteswetenschappen" msgstr "Portal FEtC – Humanities" -#: main/templates/base/site_title.html:2 +#: main/templates/base/site_title.html:3 msgid "FETC-GW" msgstr "FEtC-H" -#: main/templates/error/400.html:10 main/templates/error/500.html:9 +#: main/templates/error/400.html:10 main/templates/error/500.html:8 msgid "Server error" msgstr "Server error" -#: main/templates/error/400.html:13 main/templates/error/500.html:12 +#: main/templates/error/400.html:13 main/templates/error/500.html:10 msgid "Er is een fout opgetreden tijdens het opvragen van deze pagina." msgstr "We encountered an error while processing your request." -#: main/templates/error/400.html:18 main/templates/error/500.html:17 +#: main/templates/error/400.html:18 main/templates/error/500.html:15 msgid "Blijft dit probleem aanhouden?" msgstr "If this problem persists; " -#: main/templates/error/400.html:21 main/templates/error/403.html:41 -#: main/templates/error/403_csrf.html:39 main/templates/error/500.html:20 +#: main/templates/error/400.html:21 main/templates/error/403.html:31 +#: main/templates/error/403_csrf.html:27 main/templates/error/500.html:18 +#: reviews/templates/reviews/review_closed.html:37 msgid "" "Neem dan contact op met het technisch beheer van de portal via portalsupport.gw@uu.nl." @@ -743,27 +450,27 @@ msgstr "" "Please contact the technical support staff of the portal by email at portalsupport.gw@uu.nl. " -#: main/templates/error/403.html:9 +#: main/templates/error/403.html:8 msgid "Geen toegang" msgstr "Access denied" -#: main/templates/error/403.html:12 +#: main/templates/error/403.html:9 msgid "Je hebt geen toegang tot de opgevraagde pagina." msgstr "You are not allowed to view this page." -#: main/templates/error/403.html:16 +#: main/templates/error/403.html:11 msgid "Dit kan meerdere oorzaken hebben:" msgstr "This may be caused by the following:" -#: main/templates/error/403.html:20 +#: main/templates/error/403.html:13 msgid "Je hebt niet de benodigde rechten om deze pagina te bekijken;" msgstr "You don't have the required permissions to view this page;" -#: main/templates/error/403.html:23 +#: main/templates/error/403.html:14 msgid "Je bent niet als mede-onderzoeker opgegeven voor deze aanvraag;" msgstr "You have not been added as a researcher to this application;" -#: main/templates/error/403.html:26 +#: main/templates/error/403.html:16 msgid "" "Je probeert een door jou eerder genomen beslissing aan te passen, maar de " "beoordelingsperiode is verstreken." @@ -771,14 +478,15 @@ msgstr "" "You are trying to change one of your decisions, but the assessment period " "has expired." -#: main/templates/error/403.html:32 +#: main/templates/error/403.html:22 #, python-format msgid "" -"Je bent niet ingelogd, probeer in te loggen." +"Je bent niet ingelogd, probeer in te loggen." msgstr "" -"You are not logged in, please try to log in." +"You are not logged in, please ." -#: main/templates/error/403.html:38 main/templates/error/403_csrf.html:36 +#: main/templates/error/403.html:28 main/templates/error/403_csrf.html:24 +#: reviews/templates/reviews/review_closed.html:34 msgid "Denk je dat dit niet klopt?" msgstr "Do you think this is in error?" @@ -786,15 +494,15 @@ msgstr "Do you think this is in error?" msgid "Verificatie Fout" msgstr "Verification Error" -#: main/templates/error/403_csrf.html:13 +#: main/templates/error/403_csrf.html:12 msgid "Verzoek kon niet geverifieerd worden" msgstr "Request could not be verified" -#: main/templates/error/403_csrf.html:16 +#: main/templates/error/403_csrf.html:13 msgid "Er is iets fout gegaan met het verifiëren van je browser." msgstr "Something went wrong while verifying your browser" -#: main/templates/error/403_csrf.html:19 +#: main/templates/error/403_csrf.html:15 msgid "" "Dit kan meerdere oorzaken hebben, zoals het gebruik van een script- of ad-" "blocker, of je cookie-instellingen. Probeer eerst een volledige " @@ -803,33 +511,33 @@ msgstr "" "This can have several causes, like using a script- or ad-blocker, or your " "cookie settings. First try a fresh refresh of the page:" -#: main/templates/error/403_csrf.html:23 +#: main/templates/error/403_csrf.html:18 msgid "Voor Chrome: ctrl + F5 (Windows) of cmd + shift + R (Mac)" msgstr "For Chrome: ctrl + F5 (Windows) or cmd + shift + R (Mac)" -#: main/templates/error/403_csrf.html:26 +#: main/templates/error/403_csrf.html:19 msgid "Voor Firefox: ctrl + shift + R (Windows) of cmd + shift + R (Mac)" msgstr "For Firefox: ctrl + shift + R (Windows) or cmd + shift + R (Mac)" -#: main/templates/error/403_csrf.html:29 +#: main/templates/error/403_csrf.html:20 msgid "Voor Edge: ctrl + F5" msgstr "For Edge: ctrl + F5" -#: main/templates/error/403_csrf.html:32 +#: main/templates/error/403_csrf.html:21 msgid "Voor Safari: option + cmnd + E" msgstr "For Safari: option + cmnd + E" -#: main/templates/error/404.html:9 +#: main/templates/error/404.html:8 msgid "Pagina niet gevonden" msgstr "Page not found" -#: main/templates/error/404.html:12 +#: main/templates/error/404.html:9 msgid "Sorry, deze pagina is helaas niet (meer) beschikbaar." msgstr "" "We are sorry but the page (or document) you have requested is currently not " "available." -#: main/templates/error/404.html:15 +#: main/templates/error/404.html:11 msgid "" "Mogelijk ben je hier terechtgekomen via een verouderde of foutieve link. " "Graag vernemen wij welke link niet werkt. Je kan ons dat laten weten door contacting our secretary. We will try to solve the problem as soon as possible." -#: main/templates/error/500.html:23 +#: main/templates/error/500.html:21 msgid "" "Maak hierbij zo veel mogelijk duidelijk wat je aan het doen was, en op welke " "pagina." @@ -857,16 +565,16 @@ msgstr "" "This portal is intended for employees (and students) of the Faculty of " "Humanities." -#: main/templates/main/index.html:24 +#: main/templates/main/index.html:23 msgid "Volgens onze gegevens werk/studeer je bij de" msgstr "According to our information, you work/study at the" -#: main/templates/main/index.html:29 +#: main/templates/main/index.html:28 msgid "" "Volgens onze gegevens werk/studeer je bij een andere faculteit of dienst." msgstr "According to our data, you work/study at another faculty or service." -#: main/templates/main/index.html:34 +#: main/templates/main/index.html:32 msgid "" "Controleer of je inderdaad een aanvraag wilt indienen bij de Facultaire " "Ethische Toetsingscommissie van Geesteswetenschappen." @@ -874,7 +582,7 @@ msgstr "" "Please check whether you indeed want to submit an application to the Faculty " "Ethics Assessment Committee – Humanities." -#: main/templates/main/index.html:39 +#: main/templates/main/index.html:37 msgid "" "Als je vermoedt dat dit incorrect is, neem dan contact op met portalsupport.gw@uu.nl." @@ -882,7 +590,7 @@ msgstr "" "If you suspect this is incorrect, please contact support at portalsupport.gw@uu.nl. " -#: main/templates/main/index.html:64 +#: main/templates/main/index.html:59 msgid "" "Formele goedkeuring door één van beide kamers van de FETC-GW (middels een " "formele goedkeuringsbrief) is vereist voor mensgebonden onderzoek binnen de " @@ -897,7 +605,7 @@ msgstr "" "even to recruiting participants. Therefore, always wait for the letter of " "approval before starting research activities." -#: main/templates/main/index.html:71 +#: main/templates/main/index.html:64 msgid "" "NB: Goedgekeurde aanvragen komen in het archief van deze portal te staan, " "zie het menu hierboven. Dit archief is toegankelijk voor iedereen met een " @@ -907,7 +615,7 @@ msgstr "" "studying or working at the Faculty of Humanities with a Solis-ID can access " "this archive through the menu bar above." -#: main/templates/main/index.html:79 +#: main/templates/main/index.html:69 msgid "" "Heb je een vraag over de werking van de portal, ontdek je een foutje, " "missende functionaliteit, of verkeerde vertaling? Neem dan contact op met " @@ -918,23 +626,23 @@ msgstr "" "email to portalsupport.gw@uu.nl." -#: main/templates/main/index.html:86 +#: main/templates/main/index.html:75 #: proposals/templates/proposals/proposal_start.html:16 -#: proposals/templates/proposals/proposal_start_practice.html:18 +#: proposals/templates/proposals/proposal_start_practice.html:16 msgid "Check voor het indienen:" msgstr "Before submitting an application, please consult:" -#: main/templates/main/index.html:89 +#: main/templates/main/index.html:78 #: proposals/templates/proposals/proposal_start.html:19 -#: proposals/templates/proposals/proposal_start_practice.html:21 +#: proposals/templates/proposals/proposal_start_practice.html:19 msgid "" -"De UU-webpagina " +"De UU-webpagina " "van de FETC-GW voor nieuws en de agenda." msgstr "" "The UU-" "webpage of the FEtC-H for news and upcoming dates." -#: main/templates/main/index.html:96 +#: main/templates/main/index.html:84 msgid "" "Het reglement van de FETC-GW." @@ -942,26 +650,26 @@ msgstr "" "The regulations of the FEtC-H ." -#: main/templates/main/index.html:102 +#: main/templates/main/index.html:90 msgid "" "Gebruik de juiste (meest recente) voorbeelddocumenten voor de informed consent. " -"(de laatstse versie is van december 2021)" +"(de laatstse versie is van december 2021) " msgstr "" "Make sure to use the correct (most recent) model documents for informed consent. (Latest " "version: December 2021)" -#: main/templates/main/index.html:106 +#: main/templates/main/index.html:96 msgid "" -"
  • Voor advies over data management (plannen): datamanagement.gw@uu.nl.
  • Voor advies " -"over privacy zaken: privacy.gw@uu.nl." -"
  • Voor vragen over de procedure: Desiree Capel.
  • Voor vragen over de portal zelf: portalsupport.gw@uu.nl.
  • " +"
  • Voor advies over data management (plannen): datamanagement.gw@uu.nl.
  • Voor " +"advies over privacy zaken: privacy.gw@uu." +"nl.
  • Voor vragen over de procedure: Desiree Capel.
  • Voor vragen over de portal zelf: portalsupport.gw@uu.nl.
  • " msgstr "" "
  • For advice on data management: datamanagement.gw@uu.nl.
  • For issues concerning privacy: portalsupport.gw@uu.nl." "
  • " -#: main/templates/main/index.html:115 +#: main/templates/main/index.html:112 msgid "In deze portal kan je het volgende doen:" msgstr "In this portal you can do the following:" -#: main/templates/main/index.html:124 +#: main/templates/main/index.html:120 msgid "Dien een nieuwe aanvraag in" msgstr "Submit a new proposal" -#: main/templates/main/index.html:129 +#: main/templates/main/index.html:124 msgid "die volledig nieuw is in deze portal;" msgstr "that is completely new in this portal;" -#: main/templates/main/index.html:132 +#: main/templates/main/index.html:127 msgid "op basis van een kopie van een oude aanvraag;" msgstr "from a copy of an old proposal;" -#: main/templates/main/index.html:135 +#: main/templates/main/index.html:130 msgid "voor (al dan niet goedgekeurde) subsidieaanvragen;" msgstr "to supplement a grant application" -#: main/templates/main/index.html:138 +#: main/templates/main/index.html:133 msgid "die al goedgekeurd is door een andere ethische toetsingscomissie." msgstr "that has been approved by another ethics committee." -#: main/templates/main/index.html:144 +#: main/templates/main/index.html:138 msgid "Een aanvraag reviseren" msgstr "Revise a proposal" -#: main/templates/main/index.html:149 +#: main/templates/main/index.html:142 msgid "als een revisie, gebaseerd op opmerkingen van de FETC-GW;" msgstr "as a revision, based on comments of the FEtC-H;" -#: main/templates/main/index.html:152 +#: main/templates/main/index.html:145 msgid "als amendement, wanneer de aanvraag al goedgekeurd is door de FETC-GW." msgstr "" "as an amendment, after your proposal has already been approved by the FEtC-H." -#: main/templates/main/index.html:160 +#: main/templates/main/index.html:152 msgid "Bekijk" msgstr "View" -#: main/templates/main/index.html:164 +#: main/templates/main/index.html:155 msgid "mijn conceptaanvragen;" msgstr "my draft applications;" -#: main/templates/main/index.html:167 +#: main/templates/main/index.html:158 msgid "mijn oefenaanvragen;" msgstr "my practice applications;" -#: main/templates/main/index.html:170 +#: main/templates/main/index.html:161 msgid "mijn ingediende aanvragen;" msgstr "my submitted applications;" -#: main/templates/main/index.html:173 +#: main/templates/main/index.html:164 msgid "mijn afgehandelde aanvragen;" msgstr "my processed applications;" -#: main/templates/main/index.html:176 +#: main/templates/main/index.html:167 msgid "mijn aanvragen als eindverantwoordelijke;" msgstr "my supervised applications;" -#: main/templates/main/index.html:179 +#: main/templates/main/index.html:170 msgid "al mijn aanvragen." msgstr "all my applications" -#: main/templates/main/index.html:183 +#: main/templates/main/index.html:173 msgid "FETC-GW archief" msgstr "FEtC-H archive" -#: main/templates/main/index.html:187 +#: main/templates/main/index.html:176 msgid "Alle goedgekeurde aanvragen bekijken van de Algemene Kamer" msgstr "View all processed and approved applications of the General Chamber" -#: main/templates/main/index.html:190 +#: main/templates/main/index.html:179 msgid "Alle goedgekeurde aanvragen bekijken van de Linguïstiek Kamer" msgstr "" "View all processed and approved applications of the Linguistics Chamber" -#: main/templates/main/index.html:205 +#: main/templates/main/index.html:190 msgid "Reglement van de FETC-GW" msgstr "Regulations of the FEtC-H" -#: main/templates/main/index.html:212 +#: main/templates/main/index.html:197 msgid "Veelgestelde vragen m.b.t. dit portal" msgstr "Frequently asked questions relating to this portal" -#: main/templates/main/index.html:215 -msgid "Feedback op dit portal geven" -msgstr "Give feedback on this portal" - -#: main/templates/main/index.html:225 +#: main/templates/main/index.html:204 msgid "Bannerfoto door Kim O'leary" msgstr "Cover image by Kim O'leary" -#: main/templates/main/landing.html:52 +#: main/templates/main/landing.html:50 msgid "" "Welkom bij het portal van de Facultaire Ethische Toetsingscommissie " "Geesteswetenschappen (FETC-GW)." @@ -1073,8 +777,8 @@ msgstr "" "Welcome to the portal of the Faculty Ethics assessment Committee Humanities " "(FEtC-H)" -#: main/templates/main/landing.html:58 -#: main/templates/registration/logged_out.html:22 +#: main/templates/main/landing.html:56 +#: main/templates/registration/logged_out.html:18 msgid "" "Klik hier om terug te keren naar " "de FETC-GW-website." @@ -1082,22 +786,28 @@ msgstr "" "Click here to return to the " "FEtC-H website." -#: main/templates/main/landing.html:62 +#: main/templates/main/landing.html:60 msgid "Contact" msgstr "Contact" -#: main/templates/main/landing.html:64 +#: main/templates/main/landing.html:62 msgid "Secretaris FETC-GW" msgstr "FEtC-H Secretary" -#: main/templates/main/landing.html:66 main/templates/main/landing.html:72 +#: main/templates/main/landing.html:65 main/templates/main/landing.html:72 msgid "Om hier een e-mail adres te zien moet Javascript aan staan" msgstr "Javascript needs to be enabled to see the email address" -#: main/templates/main/landing.html:70 +#: main/templates/main/landing.html:69 msgid "Technische ondersteuning" msgstr "Technical support" +#: main/templates/main/landing.html:77 +#: main/templates/registration/login.html:14 +#: main/templates/registration/login.html:37 +msgid "Inloggen" +msgstr "Log in" + #: main/templates/main/landing.html:79 msgid "" "Om in te loggen heb je een Solis-ID nodig. Heb je geen Solis-ID, neem dan " @@ -1106,60 +816,59 @@ msgstr "" "You need a Solis-ID to log in. If you do not have a Solis ID, please contact " "the secretary of the FEtC-H." -#: main/templates/main/landing.html:86 main/templates/main/landing.html:93 -#: main/templates/main/landing.html:86 main/templates/main/landing.html:93 +#: main/templates/main/landing.html:87 main/templates/main/landing.html:96 msgid "Log in met je Solis-ID" msgstr "Log in with your Solis-ID" -#: main/templates/registration/logged_out.html:12 +#: main/templates/registration/logged_out.html:8 +msgid "Uitloggen" +msgstr "Log out" + +#: main/templates/registration/logged_out.html:9 msgid "Je bent succesvol uitgelogd." -msgstr "You have successfully logged out." +msgstr "You have logged out succesfully" -#: main/templates/registration/logged_out.html:17 +#: main/templates/registration/logged_out.html:13 #, python-format msgid "" "Klik hier om naar de startpagina te gaan." msgstr "" "Click here to return to the start page." -#: main/templates/registration/login.html:23 -#: main/templates/registration/login.html:23 +#: main/templates/registration/login.html:20 msgid "" "Gebruikersnaam of wachtwoord incorrect. Probeer het alstublieft opnieuw." msgstr "Username or password incorrect. Please try again." -#: main/templates/registration/login.html:27 -#: main/templates/registration/login.html:27 +#: main/templates/registration/login.html:22 msgid "Je kan hier inloggen met je Solis-ID en wachtwoord." msgstr "You can log in here with your Solis-ID and password." -#: main/templates/registration/login.html:30 -#: main/templates/registration/login.html:30 +#: main/templates/registration/login.html:29 msgid "Gebruikersnaam" msgstr "Username" -#: main/templates/registration/login.html:31 -#: main/templates/registration/login.html:31 +#: main/templates/registration/login.html:35 msgid "Wachtwoord" msgstr "Password" -#: main/templatetags/compare_tags.py:80 -#: proposals/templates/proposals/vue_templates/proposal_list.html:49 -#: reviews/templates/reviews/review_detail_sidebar.html:34 -#: reviews/templates/reviews/simple_compare_link.html:8 +#: main/templatetags/compare_tags.py:63 +#: proposals/templates/proposals/vue_templates/proposal_list.html:51 +#: reviews/templates/reviews/review_detail_sidebar.html:30 +#: reviews/templates/reviews/simple_compare_link.html:7 #: reviews/templates/reviews/vue_templates/decision_list.html:53 #: reviews/templates/reviews/vue_templates/review_list.html:54 msgid "Toon verschillen" msgstr "Show differences" -#: main/validators.py:14 +#: main/validators.py:17 #, python-format msgid "Dit veld mag maximaal %(limit_value)d woord bevatten." msgid_plural "Dit veld mag maximaal %(limit_value)d woorden bevatten." msgstr[0] "This field can contain a maximum of %(limit_value)d word." msgstr[1] "This field can contain a maximum of %(limit_value)d words." -#: main/validators.py:23 +#: main/validators.py:28 msgid "Alleen .pdf- of .doc(x)-bestanden zijn toegestaan." msgstr "Only .pdf or .doc(x) files are accepted." @@ -1178,11 +887,11 @@ msgstr "" "will be observed. For example: The teacher will be observed. The observation " "of interest is the interaction between the teacher and their pupils." -#: observations/models.py:40 +#: observations/models.py:41 msgid "Beschrijf waarom er wordt geobserveerd." msgstr "Describe why the participant will be observed." -#: observations/models.py:42 +#: observations/models.py:43 msgid "" "Wat is het doel van de observatie? Bijvoorbeeld: Het doel van de observatie " "is inzicht te krijgen in hoe de leerkracht omgaat met de uitleg van de " @@ -1194,43 +903,42 @@ msgstr "" "method. One question to be answered will be whether the teachers explain the " "new method well in understandable language." -#: observations/models.py:51 +#: observations/models.py:52 msgid "Beschrijf hoe vaak en hoe lang de observant wordt geobserveerd." msgstr "" "Describe how often and how long the participant will be observed." -#: observations/models.py:52 +#: observations/models.py:54 msgid "" "Bijvoorbeeld: De leraar zal 5 lessen van 45 minuten worden geobserveerd." msgstr "" "For example: Each teacher will be observed during 5 lessons of 45 minutes." -#: observations/models.py:58 +#: observations/models.py:61 msgid "Wordt er anoniem geobserveerd?" msgstr "Will the observation be anonymous?" -#: observations/models.py:60 +#: observations/models.py:63 msgid "" "Zoals zou kunnen voorkomen op fora en de onderzoeker ook een account heeft." msgstr "As might happen on forums where the researcher also has an account." -#: observations/models.py:65 observations/models.py:75 -#: observations/models.py:88 proposals/models.py:745 studies/models.py:172 -#: observations/models.py:88 proposals/models.py:745 studies/models.py:172 -#: studies/models.py:228 studies/models.py:358 +#: observations/models.py:69 observations/models.py:79 +#: observations/models.py:94 proposals/models.py:793 studies/models.py:170 +#: studies/models.py:232 studies/models.py:392 msgid "Licht toe" msgstr "Explain" -#: observations/models.py:70 +#: observations/models.py:74 msgid "Doet de onderzoeker zich voor als behorende tot de doelgroep?" msgstr "" "Will the researcher present themselves as belonging to the target group?" -#: observations/models.py:80 +#: observations/models.py:84 msgid "Wordt er geobserveerd in een niet-openbare ruimte?" msgstr "Will observations be made in a non-public space?" -#: observations/models.py:81 +#: observations/models.py:86 msgid "" "Bijvoorbeeld er wordt geobserveerd bij iemand thuis, tijdens een " "hypotheekgesprek, tijdens politieverhoren of een forum waar een account voor " @@ -1240,11 +948,11 @@ msgstr "" "negotiation, during a police interrogation or in a forum for which an " "account must be created." -#: observations/models.py:93 +#: observations/models.py:99 msgid "Vindt informed consent van tevoren plaats?" msgstr "Will informed consent take place beforehand?" -#: observations/models.py:99 +#: observations/models.py:105 msgid "" "Leg uit waarom informed consent niet van te voren plaatsvindt en geef ook op " "welke wijze dit achteraf verzorgd wordt." @@ -1252,7 +960,7 @@ msgstr "" "Please explain why informed consent is not taken beforehand and how it will " "be taken afterwards." -#: observations/models.py:106 +#: observations/models.py:113 msgid "" "Heb je toestemming nodig van een (samenwerkende) instantie om deze " "observatie te mogen uitvoeren?" @@ -1260,15 +968,15 @@ msgstr "" "Do you need permission from a (collaborating) institution in order to carry " "out this observation?" -#: observations/models.py:112 +#: observations/models.py:120 msgid "Welke instantie?" msgstr "Which institution?" -#: observations/models.py:118 +#: observations/models.py:126 msgid "Upload hier het toestemmingsdocument (in .pdf of .doc(x)-formaat)" msgstr "Upload the permission document (in .pdf or .doc(x)-format) here" -#: observations/models.py:125 +#: observations/models.py:134 msgid "" "Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het " "gebruik van de term ‘anoniem’ of ‘geanonimiseerd’ in je documenten voor " @@ -1286,56 +994,55 @@ msgstr "" "versie-1.1_21dec2021.pdf' target='_blank'>Guidelines for Informed Consent, " "‘Audio and Video’." -#: observations/models.py:126 +#: observations/models.py:136 msgid "Hoe wordt het gedrag geregistreerd?" msgstr "How will the behaviour be recorded?" -#: observations/models.py:135 +#: observations/models.py:143 msgid "Op hoeveel dagen wordt er geobserveerd (per deelnemer)?" msgstr "How many days will observations be taken on (per participant)?" -#: observations/models.py:139 +#: observations/models.py:148 msgid "Hoeveel uur wordt er gemiddeld per dag geobserveerd?" msgstr "How many hours of observation will take place on average per day?" #: observations/templates/observations/observation_form.html:7 -#: observations/templates/observations/observation_form.html:44 -#: proposals/templates/proposals/diff/observation.html:4 -#: proposals/templates/proposals/proposal_pdf.html:297 -#: proposals/templates/proposals/proposal_pdf_empty.html:229 +#: observations/templates/observations/observation_form.html:42 +#: proposals/utils/pdf_diff_logic.py:661 msgid "Het observatieonderzoek" msgstr "Observational study" -#: observations/templates/observations/observation_form.html:28 +#: observations/templates/observations/observation_form.html:27 msgid "Details observatie" msgstr "Details of observation" -#: observations/templates/observations/observation_form.html:29 +#: observations/templates/observations/observation_form.html:28 msgid "Anonimiteit" msgstr "Anonymity" -#: observations/templates/observations/observation_form.html:30 +#: observations/templates/observations/observation_form.html:29 msgid "Toestemming" msgstr "Permission" -#: observations/templates/observations/observation_form.html:31 +#: observations/templates/observations/observation_form.html:30 msgid "Registratie gedrag" msgstr "Recording behaviour" #: observations/templates/observations/observation_update_attachments.html:7 -#: observations/templates/observations/observation_update_attachments.html:27 -#: observations/templates/observations/observation_update_attachments.html:38 +#: observations/templates/observations/observation_update_attachments.html:26 +#: observations/templates/observations/observation_update_attachments.html:41 #: proposals/templates/proposals/proposal_update_attachments.html:7 -#: proposals/templates/proposals/proposal_update_attachments.html:14 -#: proposals/templates/proposals/proposal_update_attachments.html:25 +#: proposals/templates/proposals/proposal_update_attachments.html:13 +#: proposals/templates/proposals/proposal_update_attachments.html:28 +#: proposals/templates/proposals/proposal_update_date_start.html:7 #: studies/templates/studies/study_update_attachments.html:7 -#: studies/templates/studies/study_update_attachments.html:14 -#: studies/templates/studies/study_update_attachments.html:25 +#: studies/templates/studies/study_update_attachments.html:13 +#: studies/templates/studies/study_update_attachments.html:28 msgid "Formulieren aanpassen" msgstr "Change forms" -#: observations/templates/observations/observation_update_attachments.html:30 -#: studies/templates/studies/study_update_attachments.html:17 +#: observations/templates/observations/observation_update_attachments.html:28 +#: studies/templates/studies/study_update_attachments.html:15 #, python-format msgid "" "Op deze pagina kan je de formulieren aanpassen behorende bij de aanvraag " @@ -1344,34 +1051,47 @@ msgstr "" "On this page you can edit the forms related to the proposal " "%(title)s(reference number %(ref_number)s), trajectory %(order)s." -#: observations/utils.py:8 studies/models.py:143 studies/models.py:265 -#: studies/templates/studies/study_end.html:89 +#: observations/templates/observations/observation_update_attachments.html:43 +#: proposals/templates/proposals/proposal_confirmation.html:36 +#: proposals/templates/proposals/proposal_diff.html:55 +#: proposals/templates/proposals/proposal_update_attachments.html:30 +#: proposals/templates/proposals/proposal_update_date_start.html:33 +#: reviews/templates/reviews/change_chamber_form.html:23 +#: reviews/templates/reviews/decision_form.html:92 +#: reviews/templates/reviews/review_assign_form.html:46 +#: reviews/templates/reviews/review_close_form.html:40 +#: reviews/templates/reviews/review_discontinue_form.html:70 +#: studies/templates/studies/study_update_attachments.html:30 +msgid "Terug naar de vorige pagina" +msgstr "Back to the previous page" + +#: observations/utils.py:8 studies/models.py:271 +#: studies/templates/studies/study_end.html:87 msgid "Observatieonderzoek" msgstr "Observational research" -#: observations/views.py:20 +#: observations/views.py:21 msgid "Observatie opgeslagen" msgstr "Observation saved" -#: proposals/api/views.py:28 proposals/api/views.py:130 -#: proposals/api/views.py:176 +#: proposals/api/views.py:23 proposals/api/views.py:116 +#: proposals/api/views.py:147 msgid "Datum afgerond" msgstr "Date reviewed" -#: proposals/api/views.py:32 proposals/api/views.py:77 -#: proposals/api/views.py:96 proposals/api/views.py:134 -#: proposals/api/views.py:155 +#: proposals/api/views.py:24 proposals/api/views.py:77 +#: proposals/api/views.py:90 proposals/api/views.py:117 +#: proposals/api/views.py:133 #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:71 -#: proposals/templates/proposals/vue_templates/proposal_list.html:108 +#: proposals/templates/proposals/vue_templates/proposal_list.html:116 msgid "Laatst bijgewerkt" msgstr "Last edited" -#: proposals/api/views.py:126 +#: proposals/api/views.py:114 msgid "Datum ingediend bij eindverantwoordelijke" msgstr "Date sent to supervisor" -#: proposals/forms.py:42 proposals/models.py:221 -#: proposals/forms.py:42 proposals/models.py:221 +#: proposals/forms.py:58 msgid "" "Zijn er nog andere onderzoekers bij deze aanvraag betrokken die " "niet geaffilieerd zijn aan een van de onderzoeksinstituten " @@ -1380,19 +1100,19 @@ msgstr "" "Are there any other researchers involved outside the above-" "mentioned institutes? " -#: proposals/forms.py:63 proposals/forms.py:270 proposals/validators.py:25 +#: proposals/forms.py:79 proposals/validators.py:22 msgid "Er bestaat al een aanvraag met deze titel." msgstr "There is an existing application with this title." -#: proposals/forms.py:134 +#: proposals/forms.py:144 msgid "Selecteer..." msgstr "Select..." -#: proposals/forms.py:140 +#: proposals/forms.py:153 msgid "Docent" msgstr "Professor" -#: proposals/forms.py:141 +#: proposals/forms.py:155 msgid "" "Vul hier de docent van de cursus in waarbinnen je deze portal moet " "doorlopen. De docent kan na afloop de aanvraag inkijken in de portal. De " @@ -1403,19 +1123,23 @@ msgstr "" "This application will not be published in the semipublic archive of the FEtC-" "H." -#: proposals/forms.py:189 -msgid "Je dient een eindverantwoordelijke op te geven." -msgstr "You are required to specify the researcher with final responsibility." +#: proposals/forms.py:207 +msgid "Je dient een promotor/begeleider op te geven." +msgstr "You are required to specify a promotor/supervisor." + +#: proposals/forms.py:213 +msgid "Je kunt niet jezelf als promotor/begeleider opgeven." +msgstr "You cannot submit yourself as the promotor/supervisor." -#: proposals/forms.py:204 +#: proposals/forms.py:227 msgid "Je hebt jezelf niet als onderzoekers geselecteerd." msgstr "You have not selected yourself." -#: proposals/forms.py:209 +#: proposals/forms.py:232 msgid "Je hebt geen andere onderzoekers geselecteerd." msgstr "You have not selected any other researchers." -#: proposals/forms.py:219 +#: proposals/forms.py:243 msgid "" "Dit veld is verplicht, maar je kunt later terugkomen om " "hem verder in te vullen." @@ -1423,7 +1147,7 @@ msgstr "" "This field is required, but you may choose to come back to this page later " "to fill it in." -#: proposals/forms.py:229 +#: proposals/forms.py:254 msgid "" "Indien je geen toestemming hebt van een andere ethische commissie, dien je " "het normale formulier in te vullen. Ga terug naar de startpagina, en " @@ -1436,39 +1160,23 @@ msgstr "" "page, and select \"Submit a new application that is completely new in this " "portal\" or \"from a copy of an old application.\"" -#: proposals/forms.py:256 +#: proposals/forms.py:286 msgid "Ik maak een oefenaanvraag aan" msgstr "I am creating a practice application" -#: proposals/forms.py:276 proposals/models.py:536 -#: proposals/forms.py:276 proposals/models.py:536 +#: proposals/forms.py:302 proposals/models.py:586 msgid "Te kopiëren aanvraag" msgstr "Application to be copied" -#: proposals/forms.py:278 proposals/models.py:538 -#: proposals/forms.py:278 proposals/models.py:538 +#: proposals/forms.py:304 proposals/models.py:588 msgid "Dit veld toont enkel aanvragen waar je zelf een medeuitvoerende bent." msgstr "This field shows only applications in which you are involved." -#: proposals/forms.py:318 proposals/forms.py:353 -msgid "Je kan de titel van je aanvraag nu, indien nodig, wijzigen." -msgstr "You can, if necessary, change the title of your application here." - -#: proposals/forms.py:320 proposals/forms.py:355 -msgid "" -"De titel die je hier opgeeft is zichtbaar voor de FETC-GW-leden en, wanneer " -"de aanvraag is goedgekeurd, ook voor alle medewerkers die in het archief van " -"deze portal kijken." -msgstr "" -"The title you submit here will be visible to the FEtC-H members and, if the " -"application is approved, also to employees viewing the archive of this " -"portal." - -#: proposals/forms.py:327 +#: proposals/forms.py:346 msgid "Te reviseren aanvraag" msgstr "Application to be revised" -#: proposals/forms.py:328 +#: proposals/forms.py:348 msgid "" "Dit veld toont enkel ingediende, (nog) niet goedgekeurde aanvragen waar jij " "een medeuitvoerende bent." @@ -1476,69 +1184,70 @@ msgstr "" "This field only shows submitted applications that have not been approved " "(yet) in which you are involved." -#: proposals/forms.py:362 +#: proposals/forms.py:379 msgid "Te amenderen aanvraag" msgstr "Application to be amended" -#: proposals/forms.py:363 +#: proposals/forms.py:381 msgid "" "Dit veld toont enkel goedgekeurde aanvragen waar je zelf een medeuitvoerende " "bent." msgstr "This field shows only approved applications in which you are involved." -#: proposals/forms.py:418 proposals/forms.py:548 proposals/forms.py:672 +#: proposals/forms.py:439 proposals/forms.py:598 proposals/forms.py:630 +#: proposals/forms.py:752 msgid "Dit veld is verplicht om verder te gaan." msgstr "This field is required to continue." -#: proposals/forms.py:426 +#: proposals/forms.py:449 msgid "Je dient een instelling op te geven." msgstr "You are required to specify an institution." -#: proposals/forms.py:484 +#: proposals/forms.py:515 msgid "In dit geval is een beslissing van een METC vereist" msgstr "In this case, a decision by a METC is required" -#: proposals/forms.py:492 +#: proposals/forms.py:524 msgid "Naam traject 1" msgstr "Title of trajectory 1" -#: proposals/forms.py:494 +#: proposals/forms.py:527 msgid "Naam traject 2" msgstr "Title of trajectory 2" -#: proposals/forms.py:496 +#: proposals/forms.py:530 msgid "Naam traject 3" msgstr "Title of trajectory 3" -#: proposals/forms.py:498 +#: proposals/forms.py:533 msgid "Naam traject 4" msgstr "Title of trajectory 4" -#: proposals/forms.py:500 +#: proposals/forms.py:536 msgid "Naam traject 5" msgstr "Title of trajectory 5" -#: proposals/forms.py:502 +#: proposals/forms.py:539 msgid "Naam traject 6" msgstr "Title of trajectory 6" -#: proposals/forms.py:504 +#: proposals/forms.py:542 msgid "Naam traject 7" msgstr "Title of trajectory 7" -#: proposals/forms.py:506 +#: proposals/forms.py:545 msgid "Naam traject 8" msgstr "Title of trajectory 8" -#: proposals/forms.py:508 +#: proposals/forms.py:548 msgid "Naam traject 9" msgstr "Title of trajectory 9" -#: proposals/forms.py:510 +#: proposals/forms.py:551 msgid "Naam traject 10" msgstr "Title of trajectory 10" -#: proposals/forms.py:554 +#: proposals/forms.py:606 msgid "" "Als niet dezelfde trajecten worden doorlopen, moeten er minstens twee " "verschillende trajecten zijn." @@ -1546,15 +1255,19 @@ msgstr "" "If different trajectories are used, at least two different trajectories " "should be filled in." -#: proposals/forms.py:631 +#: proposals/forms.py:641 +msgid "Nieuwe beoogde startdatum" +msgstr "New intended start date" + +#: proposals/forms.py:708 msgid "Toestemmingsverklaring voor traject {} nog niet toegevoegd." msgstr "Declaration of consent for trajectory {} not yet added." -#: proposals/forms.py:635 +#: proposals/forms.py:715 msgid "Informatiebrief voor traject {} nog niet toegevoegd." msgstr "Information letter for trajectory {} not yet added." -#: proposals/forms.py:647 +#: proposals/forms.py:729 msgid "" "De embargo-periode kan maximaal 2 jaar zijn. Kies een datum binnen 2 jaar " "van vandaag." @@ -1562,10 +1275,14 @@ msgstr "" "The embargo-period can last a maximum of 2 years. Pick a date within 2 years " "from today." -#: proposals/forms.py:678 +#: proposals/forms.py:761 msgid "Vul in in welke talen de formulieren worden vertaald." msgstr "Please fill in the languages" +#: proposals/menus.py:9 +msgid "Nieuwe aanvraag starten" +msgstr "Start a new application" + #: proposals/menus.py:13 msgid "Nieuwe aanvraag starten op basis van een kopie van een oude aanvraag" msgstr "Start a new application based on a copy of an old application" @@ -1575,78 +1292,112 @@ msgid "" "Nieuwe aanvraag starten voor (al dan niet goedgekeurde) subsidieaanvragen" msgstr "Start a new application to supplement a grant application" -#: proposals/menus.py:21 +#: proposals/menus.py:22 msgid "" "Nieuwe aanvraag starten (die al goedgekeurd is door een andere ethische " "toetsingscomissie)" msgstr "" "Start a new application (that has been approved by another ethics committee)" -#: proposals/menus.py:26 +#: proposals/menus.py:28 msgid "Nieuwe oefenaanvraag starten" msgstr "Start a new practice application" -#: proposals/menus.py:42 +#: proposals/menus.py:32 +msgid "Maak een revisie van een bestaande aanvraag" +msgstr "Create a revision for an existing application" + +#: proposals/menus.py:36 +msgid "Maak een amendement van een al goedgekeurde aanvraag" +msgstr "Create an amendment to an already approved application" + +#: proposals/menus.py:44 msgid "Nieuwe aanvraag" msgstr "New application" -#: proposals/menus.py:90 +#: proposals/menus.py:54 +msgid "Al mijn aanvragen" +msgstr "All my applications" + +#: proposals/menus.py:58 proposals/views/proposal_views.py:98 +msgid "Mijn conceptaanvragen" +msgstr "My draft applications" + +#: proposals/menus.py:62 proposals/views/proposal_views.py:157 +msgid "Mijn oefenaanvragen" +msgstr "My practice applications" + +#: proposals/menus.py:66 proposals/views/proposal_views.py:112 +msgid "Mijn ingediende aanvragen" +msgstr "My submitted applications" + +#: proposals/menus.py:70 proposals/views/proposal_views.py:126 +msgid "Mijn afgehandelde aanvragen" +msgstr "My processed applications" + +#: proposals/menus.py:74 proposals/views/proposal_views.py:140 +msgid "Mijn aanvragen als eindverantwoordelijke" +msgstr "My supervised applications" + +#: proposals/menus.py:82 +msgid "Mijn aanvragen" +msgstr "My applications" + +#: proposals/menus.py:92 msgid "Bekijk alle goedgekeurde aanvragen van de Algemene Kamer" msgstr "View all approved applications of the General Chamber" -#: proposals/menus.py:95 +#: proposals/menus.py:97 msgid "Bekijk alle goedgekeurde aanvragen van de Linguïstiek Kamer" msgstr "View all approved applications of the Linguistics Chamber" -#: proposals/mixins.py:20 -#: proposals/mixins.py:20 +#: proposals/menus.py:102 +msgid "Site-export" +msgstr "Site-export" + +#: proposals/menus.py:112 proposals/views/proposal_views.py:185 +msgid "Archief" +msgstr "Archive" + +#: proposals/mixins.py:21 #, python-format msgid "Aanvraag %(title)s bewerkt" msgstr "Application %(title)s edited" -#: proposals/models.py:143 -#: proposals/models.py:143 +#: proposals/models.py:152 msgid "Concept" msgstr "Draft" -#: proposals/models.py:146 -#: proposals/models.py:146 +#: proposals/models.py:154 msgid "Opgestuurd ter beoordeling door eindverantwoordelijke" msgstr "Sent for assessment by the researcher with final responsibility" -#: proposals/models.py:147 -#: proposals/models.py:147 +#: proposals/models.py:156 msgid "Opgestuurd ter beoordeling door FETC-GW" msgstr "Sent for assessment by FEtC-H" -#: proposals/models.py:149 proposals/models.py:150 -#: proposals/models.py:149 proposals/models.py:150 +#: proposals/models.py:157 proposals/models.py:158 msgid "Aanvraag is beoordeeld door FETC-GW" msgstr "Application has been assessed by FEtC-H" -#: proposals/models.py:156 -#: proposals/models.py:156 -msgid "in het kader van een cursus" -msgstr "in the context of a course" - -#: proposals/models.py:157 -#: proposals/models.py:157 +#: proposals/models.py:161 msgid "om de portal te exploreren" msgstr "to explore the portal" +#: proposals/models.py:162 +msgid "in het kader van een cursus" +msgstr "in the context of a course" + # Not actually used in the interface -#: proposals/models.py:169 -#: proposals/models.py:169 +#: proposals/models.py:172 msgid "Door welke comissie dient deze aanvraag te worden beoordeeld?" msgstr "Which chamber should be reviewing this application?" -#: proposals/models.py:178 -#: proposals/models.py:178 +#: proposals/models.py:179 msgid "Aan welk onderzoeksinstituut ben je verbonden?" msgstr "To which research institute are you affiliated?" -#: proposals/models.py:184 -#: proposals/models.py:184 +#: proposals/models.py:185 msgid "" "Wat is de beoogde startdatum van het onderzoek waarvoor deze aanvraag wordt " "ingediend?" @@ -1654,8 +1405,7 @@ msgstr "" "What is the desired starting date of the actual research for which this " "application is being submitted?" -#: proposals/models.py:185 -#: proposals/models.py:185 +#: proposals/models.py:188 msgid "" "NB: Voor een aanvraag van een onderzoek dat al gestart is voordat de FETC-GW " "de aanvraag heeft goedgekeurd kan geen formele goedkeuring meer gegeven " @@ -1665,8 +1415,7 @@ msgstr "" "has approved it cannot receive formal approval; in such cases, the FEtC-H " "only provides a post-hoc advice." -#: proposals/models.py:194 -#: proposals/models.py:194 +#: proposals/models.py:198 msgid "" "Wat is de titel van je aanvraag? Deze titel zal worden gebruikt in alle " "formele correspondentie." @@ -1674,8 +1423,7 @@ msgstr "" "What is the title of your application? This title will be used in all formal " "correspondence." -#: proposals/models.py:199 -#: proposals/models.py:199 +#: proposals/models.py:204 msgid "" "De titel die je hier opgeeft is zichtbaar voor de FETC-GW-leden en, wanneer " "de aanvraag is goedgekeurd, ook voor alle medewerkers die in het archief van " @@ -1687,8 +1435,7 @@ msgstr "" "portal. The title cannot be identical to that of a study you have previously " "submitted." -#: proposals/models.py:207 -#: proposals/models.py:207 +#: proposals/models.py:213 msgid "" "Geef een duidelijke, bondige beschrijving van de onderzoeksvraag of -vragen. " "Gebruik maximaal 200 woorden." @@ -1696,8 +1443,7 @@ msgstr "" "Give a clear, concise description of the research question or questions. Use " "a maximum of 200 words." -#: proposals/models.py:215 -#: proposals/models.py:215 +#: proposals/models.py:221 msgid "" "Zijn er nog andere onderzoekers bij deze aanvraag betrokken die geaffilieerd " "zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of ILS?" @@ -1705,13 +1451,33 @@ msgstr "" "Are there any other researchers involved affiliated with ICON, OFR, OGK or " "ILS?" -#: proposals/models.py:229 -#: proposals/models.py:229 -msgid "Andere betrokkenen" -msgstr "Other people involved" +#: proposals/models.py:226 +msgid "" +"Werk je samen met een onderzoeker of organisatie buiten de UU en is je " +"onderzoek niet strikt anoniem? Neem dan contact op met de privacy officer. Er moeten dan wellicht afspraken " +"worden gemaakt over de verwerking van persoonsgegevens." +msgstr "" +"Do you work with a researcher or organization outside the UU and is your " +"research not strictly anonymous? Please contact the privacy officer. Agreements may then have to be made about " +"the processing of personal data." -#: proposals/models.py:234 -#: proposals/models.py:234 +#: proposals/models.py:242 +msgid "" +"Zijn er nog andere onderzoekers bij deze aanvraag betrokken die " +"niet geaffilieerd zijn aan een van de onderzoeksinstituten " +"van de Faculteit Geestwetenschappen van de UU? Zoja, vermeld diens naam en " +"affiliatie." +msgstr "" +"Are there any other researchers involved outside the above-" +"mentioned institutes? If so, please mention their name and affiliation." + +#: proposals/models.py:252 +msgid "Naam en affiliatie van andere betrokkenen" +msgstr "Name and affiliation of other involved people" + +#: proposals/models.py:259 msgid "" "Worden de informed consent formulieren nog vertaald naar een andere taal dan " "Nederlands of Engels?" @@ -1719,36 +1485,30 @@ msgstr "" "Will the informed consent forms be translated in a language other than Dutch " "or English?" -#: proposals/models.py:241 -#: proposals/models.py:241 +#: proposals/models.py:268 msgid "Andere talen:" msgstr "Other languages:" -#: proposals/models.py:250 -#: proposals/models.py:250 +#: proposals/models.py:277 msgid "Hoe wordt dit onderzoek gefinancierd?" msgstr "How is this study funded?" -#: proposals/models.py:261 -#: proposals/models.py:261 +#: proposals/models.py:288 msgid "" "Wat is de naam van het gefinancierde project en wat is het projectnummer?" msgstr "What is the name of the funded project and what is the project number?" -#: proposals/models.py:265 -#: proposals/models.py:265 +#: proposals/models.py:292 msgid "" "De titel die je hier opgeeft zal in de formele toestemmingsbrief gebruikt " "worden." msgstr "This title will be used in the formal letter of approval." -#: proposals/models.py:271 -#: proposals/models.py:271 +#: proposals/models.py:298 msgid "Ruimte voor eventuele opmerkingen. Gebruik maximaal 1000 woorden." msgstr "Space for possible comments. Use a maximum of a 1000 words." -#: proposals/models.py:277 -#: proposals/models.py:277 +#: proposals/models.py:305 msgid "" "

    Je hebt aangegeven dat je gebruik wilt gaan maken van één van de " "faciliteiten van het ILS, namelijk de database, Zep software en/of het ILS " @@ -1771,8 +1531,7 @@ msgstr "" "> - The title of the study
    - The planned starting date
    - The " "facilities you intend to use (database, lab, Zep software)" -#: proposals/models.py:297 -#: proposals/models.py:297 +#: proposals/models.py:327 msgid "" "Als de deelnemers van je onderzoek moeten worden misleid, kan je " "ervoor kiezen je applicatie pas later op te laten nemen in het " @@ -1784,19 +1543,16 @@ msgstr "" "for users of this portal. Would you like your application to be placed under " "a temporary embargo?" -#: proposals/models.py:308 -#: proposals/models.py:308 +#: proposals/models.py:339 msgid "" "Vanaf welke datum mag je onderzoek wel in het archief worden weergegeven?" msgstr "From which date may your application be displayed in the archive?" -#: proposals/models.py:318 -#: proposals/models.py:318 +#: proposals/models.py:349 msgid "Upload hier je aanvraag (in .pdf of .doc(x)-formaat)" msgstr "Upload your application here (in .pdf or .doc(x)-format)" -#: proposals/models.py:326 -#: proposals/models.py:326 +#: proposals/models.py:357 msgid "" "Heb je formele toestemming van een ethische toetsingcommissie, uitgezonderd " "deze FETC-GW commissie?" @@ -1804,13 +1560,11 @@ msgstr "" "Do you have formal approval from an ethics committee, other than this FEtC-H " "committee?" -#: proposals/models.py:334 -#: proposals/models.py:334 +#: proposals/models.py:366 msgid "Welk instituut heeft de aanvraag goedgekeurd?" msgstr "Which institute approved the application?" -#: proposals/models.py:342 -#: proposals/models.py:342 +#: proposals/models.py:374 msgid "" "Upload hier je formele toestemmingsbrief van dit instituut (in .pdf of ." "doc(x)-formaat)" @@ -1818,26 +1572,22 @@ msgstr "" "Please upload the formal approval letter from this institute here (in .pdf " "or .doc(x)-format)" -#: proposals/models.py:350 -#: proposals/models.py:350 +#: proposals/models.py:383 msgid "Ik vul de portal in in het kader van een cursus" msgstr "I am using this portal in the context of a course" -#: proposals/models.py:355 -#: proposals/models.py:355 +#: proposals/models.py:388 msgid "Ik vul de portal in om de portal te exploreren" msgstr "I am using this portal to explore the portal" -#: proposals/models.py:367 -#: proposals/models.py:367 +#: proposals/models.py:401 msgid "" -"Kan voor alle deelnemersgroepen dezelfde informatiebrief en " -"toestemmingsverklaring gebruikt worden?" +"Kan voor alle deelnemers dezelfde informatiebrief en, indien van " +"toepassing, dezelfde toestemmingsverklaring gebruikt worden?" msgstr "" "Can the same informed consent documents be used for all participant groups?" -#: proposals/models.py:369 -#: proposals/models.py:369 +#: proposals/models.py:405 msgid "" "Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is " "sprake van in essentie hetzelfde traject, en voldoet één set documenten voor " @@ -1861,22 +1611,19 @@ msgstr "" "time. However, if separate groups receive different kinds of tasks, " "they constitute separate trajectories." -#: proposals/models.py:385 -#: proposals/models.py:385 +#: proposals/models.py:422 msgid "Hoeveel verschillende trajecten zijn er?" msgstr "How many different trajectories are there?" -#: proposals/models.py:403 -#: proposals/models.py:403 +#: proposals/models.py:441 msgid "" -"Ik heb kennis genomen van het bovenstaande en begrijp mijn " -"verantwoordelijkheden ten opzichte van de AVG." +"Ik heb mijn aanvraag en de documenten voor deelnemers besproken met de " +"privacy officer." msgstr "" -"I have read the information above and have considered my responsibilities " -"with regard to the AVG." +"I discussed my application and documents for participants with the privacy " +"officer." -#: proposals/models.py:410 -#: proposals/models.py:410 +#: proposals/models.py:450 msgid "" "Als je een Data Management Plan hebt voor deze aanvraag, kan je kiezen om " "deze hier bij te voegen. Het aanleveren van een DMP vergemakkelijkt het " @@ -1886,27 +1633,24 @@ msgstr "" "include it here. Supplying a DMP can expedite ethical assessment of " "proposals." -#: proposals/models.py:422 reviews/models.py:184 -#: proposals/models.py:422 reviews/models.py:184 +#: proposals/models.py:462 proposals/utils/pdf_diff_logic.py:999 +#: reviews/models.py:162 msgid "Ruimte voor eventuele opmerkingen" msgstr "Space for possible comments" -#: proposals/models.py:434 -#: proposals/models.py:434 +#: proposals/models.py:474 msgid "Datum bevestigingsbrief verstuurd" msgstr "Date confirmation sent" -#: proposals/models.py:439 reviews/forms.py:110 +#: proposals/models.py:479 reviews/forms.py:123 msgid "Is er een revisie geweest na het indienen van deze aanvraag?" msgstr "Has this proposal been amended after it was submitted?" -#: proposals/models.py:444 -#: proposals/models.py:444 +#: proposals/models.py:484 msgid "Leg uit" msgstr "Explain why" -#: proposals/models.py:450 -#: proposals/models.py:450 +#: proposals/models.py:491 msgid "" "Wat zijn de belangrijkste ethische kwesties in dit onderzoek en beschrijf " "kort hoe ga je daarmee omgaat. Gebruik maximaal 1000 woorden." @@ -1915,28 +1659,23 @@ msgstr "" "please describe briefly how you will address them. Use a maximum of a 1000 " "words." -#: proposals/models.py:464 -#: proposals/models.py:464 +#: proposals/models.py:505 msgid "In welke hoedanigheid ben je betrokken bij dit onderzoek?" msgstr "In what capacity are you involved in this application?" -#: proposals/models.py:472 -#: proposals/models.py:472 +#: proposals/models.py:514 msgid "Wat is je studierichting?" msgstr "What is your course of study?" -#: proposals/models.py:479 -#: proposals/models.py:479 +#: proposals/models.py:521 msgid "In welke context doe je dit onderzoek?" msgstr "In what capacity are you involved in this application?" -#: proposals/models.py:486 -#: proposals/models.py:486 +#: proposals/models.py:528 msgid "Namelijk:" msgstr "Please specify:" -#: proposals/models.py:493 -#: proposals/models.py:493 +#: proposals/models.py:536 msgid "" "Studenten (die mensgebonden onderzoek uitvoeren binnen hun studieprogramma) " "hoeven in principe geen aanvraag in te dienen bij de FETC-GW. Bespreek met " @@ -1950,8 +1689,7 @@ msgstr "" "do not not, you can terminate your proposal now. If you do, please explain " "what the reason is:" -#: proposals/models.py:510 -#: proposals/models.py:510 +#: proposals/models.py:555 msgid "" "Uitvoerenden, inclusief uzelf. Let op! De andere onderzoekers moeten " "ten minste één keer zijn ingelogd op dit portaal om ze te kunnen selecteren." @@ -1960,94 +1698,89 @@ msgstr "" "researchers need to have logged into this portal at least once, in order to " "be selectable here." -#: proposals/models.py:517 -#: proposals/models.py:517 +#: proposals/models.py:563 #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:115 -#: proposals/templates/proposals/vue_templates/proposal_list.html:166 -msgid "Eindverantwoordelijke onderzoeker" -msgstr "Researcher with final responsibility" - -#: proposals/models.py:520 -#: proposals/models.py:520 -msgid "" -"Aan het einde van de procedure kan je deze aanvraag ter\n" -" verificatie naar je eindverantwoordelijke sturen. De\n" -" eindverantwoordelijke zal de aanvraag vervolgens kunnen aanpassen " -"en\n" -" indienen bij de FETC-GW.

    NB: als je je\n" -" eindverantwoordelijke niet kunt vinden met dit veld, moeten zij\n" -" waarschijnlijk eerst één keer inloggen in deze portal. Je kunt nog " -"wel\n" -" verder met de aanvraag, maar vergeet dit veld niet in te vullen voor " -"je de\n" -" aanvraag indient." -msgstr "" -"At the end of the procedure, you can send this application to the researcher " -"with final responsibility for verification. The researcher with final " -"responsibility can then make adjustments and submit the study to the FEtC-H. " -"Note: if you cannot find your supervisor using this field, " -"they may have to log into this portal at least once with their Solis-ID. You " -"can continue filling in the application while you wait for them to do this, " -"but remember to come back and fill in this field before submitting." - -#: proposals/models.py:545 -#: proposals/models.py:545 +#: proposals/templates/proposals/vue_templates/proposal_list.html:174 +msgid "Promotor/Begeleider" +msgstr "Promotor/Supervisor" + +#: proposals/models.py:567 +msgid "" +"Je aanvraag moet, als je alles hebt ingevuld, via de portal \n" +" naar je promotor of begeleider gestuurd worden. Deze " +"persoon \n" +" is de eindverantwoordelijk onderzoeker, en zal de " +"aanvraag \n" +" vervolgens waar nodig kunnen aanpassen en indienen bij " +"de FETC-GW.\n" +"

    Belangrijk: als je je promotor " +"of \n" +" begeleider niet kunt vinden met dit veld, dan moeten " +"zij \n" +" waarschijnlijk eerst één keer inloggen in deze portal. \n" +" Je kunt nog wel verder met de aanvraag, maar vergeet dit " +"veld \n" +" niet in te vullen voor je de aanvraag indient. Je " +"aanvraag \n" +" zal dan namelijk niet in behandeling kunnen worden " +"genomen." +msgstr "" +"At the end of the procedure, you need to send this application to your " +"promotor or supervisor for verification. this person is the researcher with " +"final responsibility and can then make adjustments and submit the study to " +"the FEtC-H. Note: if you cannot find your promotor or " +"supervisor using this field, they may have to log into this portal at least " +"once with their Solis-ID. You can continue filling in the application, while " +"you wait for them to do this, but remember to come back and fill in this " +"field before submitting." + +#: proposals/models.py:594 msgid "" "Is deze aanvraag een revisie van of amendement op een ingediende aanvraag?" msgstr "" "Is this application a revision or an amendment of a previously submitted " "application?" -#: proposals/models.py:617 -#: proposals/models.py:617 +#: proposals/models.py:677 msgid "Amendement" msgstr "Amendment" -#: proposals/models.py:617 reviews/api/views.py:39 reviews/api/views.py:328 -#: proposals/models.py:617 reviews/api/views.py:39 reviews/api/views.py:328 -#: reviews/templates/reviews/committee_members_workload.html:36 -#: reviews/templates/reviews/committee_members_workload.html:82 +#: proposals/models.py:677 reviews/api/views.py:41 reviews/api/views.py:327 +#: reviews/templates/reviews/committee_members_workload.html:35 +#: reviews/templates/reviews/committee_members_workload.html:74 #: reviews/templates/reviews/review_detail_sidebar.html:106 msgid "Revisie" msgstr "Revision" -#: proposals/models.py:623 -#: proposals/models.py:623 +#: proposals/models.py:683 msgid "Normaal" msgstr "Normal" -#: proposals/models.py:628 -#: proposals/models.py:628 +#: proposals/models.py:688 msgid "Voortoetsing" msgstr "Preliminary assessment" -#: proposals/models.py:630 -#: proposals/models.py:630 +#: proposals/models.py:690 msgid "Oefening" msgstr "Practice" -#: proposals/models.py:632 -#: proposals/models.py:632 +#: proposals/models.py:692 msgid "Extern getoetst" msgstr "External approval" -#: proposals/models.py:730 -#: proposals/models.py:730 +#: proposals/models.py:777 msgid "Geen beoordeling door METC noodzakelijk" msgstr "Assessment by METC not required" -#: proposals/models.py:731 -#: proposals/models.py:731 +#: proposals/models.py:778 msgid "In afwachting beslissing METC" msgstr "Pending decision by METC" -#: proposals/models.py:732 -#: proposals/models.py:732 +#: proposals/models.py:779 msgid "Beslissing METC geüpload" msgstr "METC decision uploaded" -#: proposals/models.py:736 -#: proposals/models.py:736 +#: proposals/models.py:783 msgid "" "Vindt de dataverzameling plaats binnen het UMC Utrecht of andere instelling " "waar toetsing door een METC verplicht is gesteld?" @@ -2055,13 +1788,11 @@ msgstr "" "Will the data collection take place at the UMC Utrecht or another " "institution for which an assessment by a METC is required?" -#: proposals/models.py:750 -#: proposals/models.py:750 +#: proposals/models.py:798 msgid "Welke instelling?" msgstr "Which institution?" -#: proposals/models.py:756 -#: proposals/models.py:756 +#: proposals/models.py:805 msgid "" "Is de onderzoeksvraag medisch-wetenschappelijk van aard (zoals gedefinieerd " "door de WMO)?" @@ -2069,8 +1800,7 @@ msgstr "" "Is the nature of the research question medical (as defined by the Medical " "Research Involving Human Subjects Act (WMO))?" -#: proposals/models.py:758 -#: proposals/models.py:758 +#: proposals/models.py:809 msgid "" "De definitie van medisch-wetenschappelijk onderzoek is: Medisch-" "wetenschappelijk onderzoek is onderzoek dat als doel heeft het beantwoorden " @@ -2091,8 +1821,7 @@ msgstr "" "Committee on Research Involving Human Subjects, Definition of medical " "research, 2005, ccmo.nl)" -#: proposals/models.py:774 -#: proposals/models.py:774 +#: proposals/models.py:826 msgid "" "Je onderzoek moet beoordeeld worden door een METC, maar dient nog wel bij de " "FETC-GW te worden geregistreerd. Is dit onderzoek al aangemeld bij een METC?" @@ -2101,18 +1830,15 @@ msgstr "" "registered with the FEtC-H. Has an application for this project already been " "submitted to an METC?" -#: proposals/models.py:781 -#: proposals/models.py:781 +#: proposals/models.py:834 msgid "Is de METC al tot een beslissing gekomen?" msgstr "Has the METC already come to a decision?" -#: proposals/models.py:786 -#: proposals/models.py:786 +#: proposals/models.py:840 msgid "Upload hier de beslissing van het METC (in .pdf of .doc(x)-formaat)" msgstr "Please upload the decision of METC (in .pdf or .doc(x)-format) here" -#: proposals/models.py:824 -#: proposals/models.py:824 +#: proposals/models.py:883 #, python-brace-format msgid "WMO {title}, status {status}" msgstr "WMO {title}, status {status}" @@ -2124,369 +1850,45 @@ msgstr "Compare documents" #: proposals/templates/proposals/compare_documents.html:51 msgid "" -"\n" -" Hier kan je twee versies van een document vergelijken. " -"Standaard\n" -" geeft hij een gecombineerde versie weer, waarbij " -"tekst\n" -" die verwijderd is in het rood is gemarkeerd en nieuwe tekst\n" -" in het groen is gemarkeerd.\n" -" " +"Hier kan je twee versies van een document vergelijken. Standaard geeft hij " +"een gecombineerde versie weer, waarbij tekst die verwijderd is in het " +"rood is gemarkeerd en nieuwe tekst in het groen is gemarkeerd." msgstr "" -"\n" -" This tool allows you to compare two documents. By default,\n" -" you are presented with a combined view in " -"whichremoved\n" -" text is marked in red and added text is marked in green.\n" -" " +"This tool allows you to compare two documents. By default, you are presented " +"with a combined view where removed text is marked in red and added " +"text is marked in green." #: proposals/templates/proposals/compare_documents.html:59 msgid "" -"\n" -" Je kan ook de bestanden naast elkaar bekijken, met dezelfde\n" -" markeringen. Klik hiervoor op 'Bekijk apart'.\n" -" " +"Je kan ook de bestanden naast elkaar bekijken, met dezelfde markeringen. " +"Klik hiervoor op 'Bekijk apart'." msgstr "" -"\n" "Documents can also be viewed side by side, with markings. To do so, click " -"'View separately'.\n" -" " - -#: proposals/templates/proposals/compare_documents.html:65 -msgid "Je vergelijkt" -msgstr "Comparing:" - -#: proposals/templates/proposals/compare_documents.html:69 -msgid "Er zijn geen wijzigingen gevonden in dit document!" -msgstr "No changes were found in this document!" - -#: proposals/templates/proposals/compare_documents.html:72 -msgid "Bekijk apart" -msgstr "View separately" - -#: proposals/templates/proposals/compare_documents.html:75 -msgid "Bekijk gecombineerd" -msgstr "View combined" - -#: proposals/templates/proposals/compare_documents.html:82 -msgid "Oud" -msgstr "Old" - -#: proposals/templates/proposals/compare_documents.html:88 -msgid "Nieuw" -msgstr "New" - -#: proposals/templates/proposals/diff/intervention.html:8 -msgid "" -"De revisie bevat interventieonderzoek, terwijl de originele aanvraag dat " -"niet bevat." -msgstr "" -"This revision involves intervention research, whereas the original " -"application does not." - -#: proposals/templates/proposals/diff/intervention.html:12 -msgid "" -"De revisie bevat geen interventieonderzoek, terwijl de originele aanvraag " -"dat wel bevat." -msgstr "" -"This revision does not involve intervention research, whereas the original " -"application does include this." - -#: proposals/templates/proposals/diff/intervention.html:28 -msgid "" -"De revisie en de originele aanvraag hebben beide een interventieonderzoek, " -"maar deze zijn niet te vergelijken. Dit komt doordat de revisie een andere " -"versie van het formulier gebruikt." -msgstr "" -"This revision and the original application both involve intervention " -"research, but this aspect cannot be compared. The revision uses a newer " -"version of the form than the original." - -#: proposals/templates/proposals/diff/intervention_v1.html:8 -#: proposals/templates/proposals/diff/intervention_v2.html:8 -#: proposals/templates/proposals/diff/observation_v1.html:9 -#: proposals/templates/proposals/diff/observation_v2.html:9 -#: proposals/templates/proposals/diff/sessions.html:23 -#: proposals/templates/proposals/diff/sessions.html:42 -#: proposals/templates/proposals/diff/sessions.html:103 -#: proposals/templates/proposals/diff/sessions.html:174 -#: proposals/templates/proposals/diff/study.html:25 -#: proposals/templates/proposals/diff/study.html:151 -#: proposals/templates/proposals/diff/study.html:215 -#: proposals/templates/proposals/proposal_diff.html:53 -#: proposals/templates/proposals/proposal_diff.html:178 -#: proposals/templates/proposals/proposal_diff.html:211 -#: proposals/templates/proposals/proposal_diff.html:244 -#: proposals/templates/proposals/proposal_diff.html:268 -#: proposals/templates/proposals/proposal_diff.html:178 -#: proposals/templates/proposals/proposal_diff.html:211 -#: proposals/templates/proposals/proposal_diff.html:244 -#: proposals/templates/proposals/proposal_diff.html:268 -msgid "Originele aanvraag" -msgstr "Original application" - -#: proposals/templates/proposals/diff/intervention_v1.html:9 -#: proposals/templates/proposals/diff/intervention_v2.html:9 -#: proposals/templates/proposals/diff/observation_v1.html:10 -#: proposals/templates/proposals/diff/observation_v2.html:10 -#: proposals/templates/proposals/diff/sessions.html:24 -#: proposals/templates/proposals/diff/sessions.html:43 -#: proposals/templates/proposals/diff/sessions.html:104 -#: proposals/templates/proposals/diff/sessions.html:175 -#: proposals/templates/proposals/diff/study.html:26 -#: proposals/templates/proposals/diff/study.html:152 -#: proposals/templates/proposals/diff/study.html:216 -#: proposals/templates/proposals/proposal_diff.html:54 -#: proposals/templates/proposals/proposal_diff.html:179 -#: proposals/templates/proposals/proposal_diff.html:212 -#: proposals/templates/proposals/proposal_diff.html:245 -#: proposals/templates/proposals/proposal_diff.html:269 -#: proposals/templates/proposals/proposal_diff.html:179 -#: proposals/templates/proposals/proposal_diff.html:212 -#: proposals/templates/proposals/proposal_diff.html:245 -#: proposals/templates/proposals/proposal_diff.html:269 -msgid "Revisie/amendement" -msgstr "Revision/amendment" - -#: proposals/templates/proposals/diff/intervention_v1.html:28 -#: proposals/templates/proposals/diff/intervention_v1.html:33 -#: proposals/templates/proposals/diff/intervention_v1.html:42 -#: proposals/templates/proposals/diff/intervention_v1.html:47 -#: proposals/templates/proposals/diff/intervention_v2.html:28 -#: proposals/templates/proposals/diff/intervention_v2.html:33 -#: proposals/templates/proposals/diff/intervention_v2.html:42 -#: proposals/templates/proposals/diff/intervention_v2.html:47 -#: proposals/templates/proposals/diff/intervention_v2.html:62 -#: proposals/templates/proposals/diff/intervention_v2.html:67 -#: proposals/templates/proposals/diff/observation_v1.html:43 -#: proposals/templates/proposals/diff/observation_v1.html:48 -#: proposals/templates/proposals/diff/observation_v2.html:43 -#: proposals/templates/proposals/diff/observation_v2.html:48 -#: proposals/templates/proposals/diff/sessions.html:62 -#: proposals/templates/proposals/diff/sessions.html:67 -#: proposals/templates/proposals/diff/sessions.html:76 -#: proposals/templates/proposals/diff/sessions.html:81 -msgid "ja,nee," -msgstr "yes,no," - -#: proposals/templates/proposals/diff/intervention_v1.html:87 -#: proposals/templates/proposals/diff/intervention_v1.html:92 -#: proposals/templates/proposals/diff/intervention_v2.html:102 -#: proposals/templates/proposals/diff/intervention_v2.html:107 -#: proposals/templates/proposals/diff/observation_v1.html:29 -#: proposals/templates/proposals/diff/observation_v1.html:34 -#: proposals/templates/proposals/diff/observation_v1.html:68 -#: proposals/templates/proposals/diff/observation_v1.html:73 -#: proposals/templates/proposals/diff/observation_v1.html:81 -#: proposals/templates/proposals/diff/observation_v1.html:86 -#: proposals/templates/proposals/diff/observation_v1.html:94 -#: proposals/templates/proposals/diff/observation_v1.html:99 -#: proposals/templates/proposals/diff/observation_v1.html:108 -#: proposals/templates/proposals/diff/observation_v1.html:113 -#: proposals/templates/proposals/diff/observation_v1.html:122 -#: proposals/templates/proposals/diff/observation_v1.html:127 -#: proposals/templates/proposals/diff/observation_v2.html:29 -#: proposals/templates/proposals/diff/observation_v2.html:34 -#: proposals/templates/proposals/diff/observation_v2.html:73 -#: proposals/templates/proposals/diff/observation_v2.html:78 -#: proposals/templates/proposals/diff/observation_v2.html:93 -#: proposals/templates/proposals/diff/observation_v2.html:98 -#: proposals/templates/proposals/diff/observation_v2.html:113 -#: proposals/templates/proposals/diff/observation_v2.html:118 -#: proposals/templates/proposals/diff/observation_v2.html:132 -#: proposals/templates/proposals/diff/observation_v2.html:137 -#: proposals/templates/proposals/diff/observation_v2.html:146 -#: proposals/templates/proposals/diff/observation_v2.html:151 -#: proposals/templates/proposals/diff/sessions.html:151 -#: proposals/templates/proposals/diff/sessions.html:156 -#: proposals/templates/proposals/diff/study.html:43 -#: proposals/templates/proposals/diff/study.html:48 -#: proposals/templates/proposals/diff/study.html:63 -#: proposals/templates/proposals/diff/study.html:64 -#: proposals/templates/proposals/diff/study.html:220 -#: proposals/templates/proposals/diff/study.html:221 -#: proposals/templates/proposals/diff/study.html:262 -#: proposals/templates/proposals/diff/study.html:267 -#: proposals/templates/proposals/pdf/intervention_v1.html:16 -#: proposals/templates/proposals/pdf/intervention_v1.html:20 -#: proposals/templates/proposals/pdf/intervention_v1.html:43 -#: proposals/templates/proposals/pdf/intervention_v2.html:16 -#: proposals/templates/proposals/pdf/intervention_v2.html:20 -#: proposals/templates/proposals/pdf/intervention_v2.html:28 -#: proposals/templates/proposals/pdf/intervention_v2.html:48 -#: proposals/templates/proposals/pdf/intervention_v2.html:57 -#: proposals/templates/proposals/pdf/observation_v1.html:16 -#: proposals/templates/proposals/pdf/observation_v1.html:20 -#: proposals/templates/proposals/pdf/observation_v1.html:31 -#: proposals/templates/proposals/pdf/observation_v1.html:34 -#: proposals/templates/proposals/pdf/observation_v1.html:37 -#: proposals/templates/proposals/pdf/observation_v1.html:41 -#: proposals/templates/proposals/pdf/observation_v1.html:45 -#: proposals/templates/proposals/pdf/observation_v2.html:16 -#: proposals/templates/proposals/pdf/observation_v2.html:20 -#: proposals/templates/proposals/pdf/observation_v2.html:34 -#: proposals/templates/proposals/pdf/observation_v2.html:42 -#: proposals/templates/proposals/pdf/observation_v2.html:50 -#: proposals/templates/proposals/pdf/observation_v2.html:57 -#: proposals/templates/proposals/pdf/observation_v2.html:67 -#: proposals/templates/proposals/proposal_diff.html:95 -#: proposals/templates/proposals/proposal_diff.html:96 -#: proposals/templates/proposals/proposal_diff.html:121 -#: proposals/templates/proposals/proposal_diff.html:122 -#: proposals/templates/proposals/proposal_diff.html:216 -#: proposals/templates/proposals/proposal_diff.html:217 -#: proposals/templates/proposals/proposal_diff.html:221 -#: proposals/templates/proposals/proposal_diff.html:222 -#: proposals/templates/proposals/proposal_diff.html:249 -#: proposals/templates/proposals/proposal_diff.html:250 -#: proposals/templates/proposals/proposal_diff.html:273 -#: proposals/templates/proposals/proposal_diff.html:274 -#: proposals/templates/proposals/proposal_diff.html:121 -#: proposals/templates/proposals/proposal_diff.html:122 -#: proposals/templates/proposals/proposal_diff.html:216 -#: proposals/templates/proposals/proposal_diff.html:217 -#: proposals/templates/proposals/proposal_diff.html:221 -#: proposals/templates/proposals/proposal_diff.html:222 -#: proposals/templates/proposals/proposal_diff.html:249 -#: proposals/templates/proposals/proposal_diff.html:250 -#: proposals/templates/proposals/proposal_diff.html:273 -#: proposals/templates/proposals/proposal_diff.html:274 -#: proposals/templates/proposals/proposal_pdf.html:109 -#: proposals/templates/proposals/proposal_pdf.html:125 -#: proposals/templates/proposals/proposal_pdf.html:182 -#: proposals/templates/proposals/proposal_pdf.html:185 -#: proposals/templates/proposals/proposal_pdf.html:204 -#: proposals/templates/proposals/proposal_pdf.html:223 -#: proposals/templates/proposals/proposal_pdf.html:232 -#: proposals/templates/proposals/proposal_pdf.html:274 -#: proposals/templates/proposals/proposal_pdf.html:329 -#: proposals/templates/proposals/proposal_pdf.html:333 -#: proposals/templates/proposals/proposal_pdf.html:369 -#: proposals/templates/proposals/proposal_pdf.html:435 -#: proposals/templates/proposals/proposal_pdf.html:452 -#: proposals/templates/proposals/proposal_pdf.html:516 -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:92 -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:109 -#: proposals/templates/proposals/proposal_pdf_pre_assessment.html:75 -#: proposals/templates/proposals/proposal_pdf_pre_assessment.html:91 -#: tasks/templates/tasks/task_list.html:21 -msgid "ja,nee" -msgstr "yes,no" - -#: proposals/templates/proposals/diff/observation.html:8 -msgid "" -"De revisie bevat observatieonderzoek, terwijl de originele aanvraag dat niet " -"bevat." -msgstr "" -"This revision involves observation research, whereas the original " -"application does not." - -#: proposals/templates/proposals/diff/observation.html:12 -msgid "" -"De revisie bevat geen observatieonderzoek, terwijl de originele aanvraag dat " -"wel bevat." -msgstr "" -"This revision does not involve intervention research, whereas the original " -"application involve this." - -#: proposals/templates/proposals/diff/observation.html:28 -msgid "" -"De revisie en de originele aanvraag hebben beide een observatieonderzoek, " -"maar deze zijn niet te vergelijken. Dit komt doordat de revisie een andere " -"versie van het formulier gebruikt." -msgstr "" -"This revision and the original application both involve observation " -"research, but this aspect cannot be compared. The revision uses a newer " -"version of the form than the original." - -#: proposals/templates/proposals/diff/observation_v1.html:139 -#: proposals/templates/proposals/diff/observation_v1.html:140 -#: proposals/templates/proposals/diff/study.html:233 -#: proposals/templates/proposals/diff/study.html:239 -#: proposals/templates/proposals/diff/study.html:247 -#: proposals/templates/proposals/diff/study.html:253 -#: proposals/templates/proposals/pdf/observation_v1.html:53 -#: proposals/templates/proposals/proposal_diff.html:228 -#: proposals/templates/proposals/proposal_diff.html:232 -#: proposals/templates/proposals/proposal_diff.html:228 -#: proposals/templates/proposals/proposal_diff.html:232 -#: proposals/templates/proposals/proposal_pdf.html:189 -#: proposals/templates/proposals/proposal_pdf.html:444 -#: proposals/templates/proposals/proposal_pdf.html:447 -#: proposals/templates/proposals/proposal_pdf.html:462 -#: proposals/templates/proposals/proposal_pdf.html:467 -#: proposals/templates/proposals/proposal_pdf.html:472 -#: proposals/templates/proposals/proposal_pdf.html:486 -#: proposals/templates/proposals/proposal_pdf.html:491 -#: proposals/templates/proposals/proposal_pdf.html:507 -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:143 -#: proposals/templates/proposals/proposal_pdf_pre_assessment.html:105 -msgid "Download" -msgstr "Download" - -#: proposals/templates/proposals/diff/sessions.html:7 -#: proposals/templates/proposals/proposal_pdf.html:308 -#: proposals/templates/proposals/proposal_pdf_empty.html:279 -#: studies/templates/studies/session_start.html:7 -#: studies/templates/studies/session_start.html:17 -#: tasks/templates/tasks/task_form.html:7 -#: tasks/templates/tasks/task_form.html:30 -#: tasks/templates/tasks/task_start.html:7 -#: tasks/templates/tasks/task_start.html:28 -msgid "Het takenonderzoek en interviews" -msgstr "Task-based research and interviews" - -#: proposals/templates/proposals/diff/sessions.html:11 -msgid "" -"De revisie bevat takenonderzoek, terwijl de originele aanvraag dat niet " -"bevat." -msgstr "" -"This revision involves tasks research, whereas the original application does " -"not." - -#: proposals/templates/proposals/diff/sessions.html:15 -msgid "" -"De revisie bevat geen takenonderzoek, terwijl de originele aanvraag dat wel " -"bevat." -msgstr "" -"This revision does not involve tasks research, whereas the original " -"application does involve this." +"'View separately'." -#: proposals/templates/proposals/diff/sessions.html:170 -#: proposals/templates/proposals/proposal_pdf.html:381 -#: proposals/templates/proposals/proposal_pdf_empty.html:335 -#: tasks/templates/tasks/task_end.html:7 tasks/templates/tasks/task_end.html:18 -msgid "Overzicht van het takenonderzoek" -msgstr "Overview of task-based research" +#: proposals/templates/proposals/compare_documents.html:65 +msgid "Je vergelijkt" +msgstr "Comparing:" -#: proposals/templates/proposals/diff/study.html:9 -#: proposals/templates/proposals/proposal_pdf.html:215 -#: proposals/templates/proposals/proposal_pdf_empty.html:145 -#: studies/templates/studies/study_form.html:7 -#: studies/templates/studies/study_form.html:82 -msgid "De deelnemers" -msgstr "Participants" +#: proposals/templates/proposals/compare_documents.html:69 +msgid "Er zijn geen wijzigingen gevonden in dit document!" +msgstr "No changes were found in this document!" -#: proposals/templates/proposals/diff/study.html:14 -msgid "Dit traject is nieuw in de revisie." -msgstr "This trajectory was added in this revision." +#: proposals/templates/proposals/compare_documents.html:71 +msgid "Bekijk apart" +msgstr "View separately" -#: proposals/templates/proposals/diff/study.html:18 -msgid "Dit traject is weggehaald uit de revisie" -msgstr "This trajectory was removed in this revision." +#: proposals/templates/proposals/compare_documents.html:72 +msgid "Bekijk gecombineerd" +msgstr "View combined" -#: proposals/templates/proposals/diff/study.html:144 -#: proposals/templates/proposals/proposal_pdf.html:391 -#: proposals/templates/proposals/proposal_pdf_empty.html:343 -#: studies/templates/studies/study_end.html:7 -#: studies/templates/studies/study_end.html:28 -msgid "Overzicht en eigen beoordeling van het gehele onderzoek" -msgstr "Overview and self-assessment of the entire study" +#: proposals/templates/proposals/compare_documents.html:78 +msgid "Oud" +msgstr "Old" -#: proposals/templates/proposals/diff/study.html:206 -#: proposals/templates/proposals/proposal_pdf_empty.html:372 -msgid "Informed consent formulieren voor het onderzoek" -msgstr "Informed consent forms for the study" +#: proposals/templates/proposals/compare_documents.html:84 +msgid "Nieuw" +msgstr "New" #: proposals/templates/proposals/proposal_confirm_delete.html:6 #: proposals/templates/proposals/proposal_confirm_delete.html:12 @@ -2498,49 +1900,45 @@ msgstr "Delete application" msgid "Weet je zeker dat je de aanvraag %(title)s wilt verwijderen?" msgstr "Are you sure you want to delete the application %(title)s?" -#: proposals/templates/proposals/proposal_confirm_delete.html:19 -#: proposals/templates/proposals/vue_templates/proposal_list.html:64 -#: tasks/templates/tasks/session_confirm_delete.html:18 -#: tasks/templates/tasks/task_confirm_delete.html:17 +#: proposals/templates/proposals/proposal_confirm_delete.html:20 +#: proposals/templates/proposals/vue_templates/proposal_list.html:66 +#: tasks/templates/tasks/session_confirm_delete.html:20 +#: tasks/templates/tasks/task_confirm_delete.html:20 msgid "Verwijderen" msgstr "Delete" #: proposals/templates/proposals/proposal_confirm_delete.html:21 -#: proposals/templates/proposals/proposal_copy.html:99 -#: tasks/templates/tasks/session_confirm_delete.html:19 -#: tasks/templates/tasks/task_confirm_delete.html:18 +#: proposals/templates/proposals/proposal_copy.html:93 +#: tasks/templates/tasks/session_confirm_delete.html:21 +#: tasks/templates/tasks/task_confirm_delete.html:21 msgid "Annuleren" msgstr "Cancel" #: proposals/templates/proposals/proposal_confirmation.html:27 #, python-format msgid "" -"\n" -" Geef hieronder aan wanneer de bevestigingsbrief voor de " -"aanvraag %(title)s is verstuurd.\n" -" " +"Geef hieronder aan wanneer de bevestigingsbrief voor de aanvraag " +"%(title)s is verstuurd." msgstr "" -"\n" -" Please state when the confirmation letter for %(title)s has " -"been sent here.\n" -" " +"Please state when the confirmation letter for %(title)s has been " +"sent here. " #: proposals/templates/proposals/proposal_copy.html:8 -#: proposals/templates/proposals/proposal_copy.html:28 +#: proposals/templates/proposals/proposal_copy.html:22 msgid "Revisie starten" msgstr "Start a revision" #: proposals/templates/proposals/proposal_copy.html:10 -#: proposals/templates/proposals/proposal_copy.html:30 +#: proposals/templates/proposals/proposal_copy.html:24 msgid "Amendement aanmaken" msgstr "Create an amendment" #: proposals/templates/proposals/proposal_copy.html:12 -#: proposals/templates/proposals/proposal_copy.html:32 +#: proposals/templates/proposals/proposal_copy.html:26 msgid "Een geheel nieuwe aanvraag indienen op basis van een oude studie" msgstr "Submit an entirely new application from a copy of an old application" -#: proposals/templates/proposals/proposal_copy.html:37 +#: proposals/templates/proposals/proposal_copy.html:31 msgid "" "Je kan hier op basis van de vorige versie van een aanvraag een revisie " "starten. Alleen studies die door de commissie als 'revisie noodzakelijk' " @@ -2550,7 +1948,7 @@ msgstr "" "application. Only applications that have been marked as 'revision necessary' " "by the committee can be selected here. " -#: proposals/templates/proposals/proposal_copy.html:43 +#: proposals/templates/proposals/proposal_copy.html:37 msgid "" "Als je supervisor je heeft gevraagd revisies te maken, dien je je huidige " "versie aan te passen. (Als je dat niet kan, vraag dan aan je supervisor of " @@ -2560,7 +1958,7 @@ msgstr "" "original application. (If you can't, ask your supervisor if they have " "correctly marked your study as 'revision necessary') " -#: proposals/templates/proposals/proposal_copy.html:50 +#: proposals/templates/proposals/proposal_copy.html:44 msgid "" "Let op! Er kan maar één revisie tegelijk bestaan. Mocht je jouw aanvraag " "hier niet zien als optie om te reviseren, bekijk dan of je aanvraag niet al " @@ -2570,7 +1968,7 @@ msgstr "" "application in the list of options on this page, please check if your " "application is not already in your list of draft applications." -#: proposals/templates/proposals/proposal_copy.html:58 +#: proposals/templates/proposals/proposal_copy.html:52 msgid "" "Je kan hier op basis van een reeds goedgekeurde aanvraag een amendement " "indienen. Je studie moet eerst goedgekeurd en afgehandeld zijn voordat die " @@ -2580,7 +1978,7 @@ msgstr "" "been approved. Your application must have been approved by the committee " "before it can be selected here. " -#: proposals/templates/proposals/proposal_copy.html:64 +#: proposals/templates/proposals/proposal_copy.html:58 msgid "" "Let op! Er kan maar één amendement tegelijk bestaan. Mocht je jouw aanvraag " "hier niet zien als optie om te reviseren, bekijk dan of je aanvraag niet al " @@ -2591,14 +1989,14 @@ msgstr "" "check if your application is not already in the your list of draft " "applications." -#: proposals/templates/proposals/proposal_copy.html:74 +#: proposals/templates/proposals/proposal_copy.html:67 msgid "" "Je kan hier een aanvraag kopiëren. Alle velden kunnen na het kopiëren " "aangepast worden." msgstr "" "Here you can copy an application. All fields can be edited after copying." -#: proposals/templates/proposals/proposal_copy.html:77 +#: proposals/templates/proposals/proposal_copy.html:69 msgid "" "Deze pagina is alleen bedoeld voor het geval je een geheel nieuwe aanvraag " "gaat doen op basis van een eerder uitgevoerde aanvraag. Aanvragen t.b.v. " @@ -2607,7 +2005,7 @@ msgstr "" "This page is only intended for creating an entirely new application based on " "a previous application. Applications for grant applications cannot be copied." -#: proposals/templates/proposals/proposal_copy.html:83 +#: proposals/templates/proposals/proposal_copy.html:75 #, python-format msgid "" "Als je gevraagd is om een revisie te maken van een eerder ingediende " @@ -2616,7 +2014,7 @@ msgstr "" "If you have been asked to revise a previously submitted application, you can " "do so here. " -#: proposals/templates/proposals/proposal_copy.html:89 +#: proposals/templates/proposals/proposal_copy.html:81 #, python-format msgid "" "Indien je wijzigingen hebt in een al goedgekeurde aanvraag die daarom " @@ -2627,20 +2025,20 @@ msgstr "" "to be re-reviewed, please make an amendment here." -#: proposals/templates/proposals/proposal_copy.html:101 +#: proposals/templates/proposals/proposal_copy.html:94 msgid "Kopiëren" msgstr "Copy" #: proposals/templates/proposals/proposal_data_management.html:7 -#: proposals/utils/proposal_utils.py:121 +#: proposals/utils/proposal_utils.py:118 msgid "Datamanagement" msgstr "Data management" -#: proposals/templates/proposals/proposal_data_management.html:17 +#: proposals/templates/proposals/proposal_data_management.html:16 msgid "Datamanagement en Privacy" msgstr "Data Management and Privacy" -#: proposals/templates/proposals/proposal_data_management.html:20 +#: proposals/templates/proposals/proposal_data_management.html:18 msgid "" "De Universiteit Utrecht streeft naar integriteit, duurzaamheid, en " "transparantie in de omgang met onderzoeksdata, waaronder persoonsgegevens. " @@ -2652,13 +2050,13 @@ msgstr "" "introduction of the GDPR there are clear rules which researchers should " "follow with regard to data." -#: proposals/templates/proposals/proposal_data_management.html:24 -#: proposals/templates/proposals/proposal_pdf.html:499 -#: reviews/templatetags/documents_list.py:245 +#: proposals/templates/proposals/proposal_data_management.html:22 +#: proposals/utils/pdf_diff_logic.py:974 +#: reviews/templatetags/documents_list.py:224 msgid "Data Management Plan" msgstr "Data Management Plan" -#: proposals/templates/proposals/proposal_data_management.html:27 +#: proposals/templates/proposals/proposal_data_management.html:25 msgid "" "Een data management plan is sinds 2020 required by the Faculty of Humanities from 2020 " "onwards as well as by NWO or ERC if you are financed by these organizations. " -#: proposals/templates/proposals/proposal_data_management.html:33 +#: proposals/templates/proposals/proposal_data_management.html:32 msgid "" "De faculteit biedt uitgebreide informatie op het gebied van data management, " "waaronder ook hoe deze te " -"schrijven.
    Je kunt bij de faculteit ook je DMP laten nakijken door " -".
    Je kunt bij de faculteit ook je DMP laten nakijken " +"door
    Research Data " "Management Support of de facultaire datamanager." @@ -2691,7 +2089,7 @@ msgstr "" "target=\"_blank\">Research Data Management Support or the faculty data manager. " -#: proposals/templates/proposals/proposal_data_management.html:38 +#: proposals/templates/proposals/proposal_data_management.html:41 msgid "" "Op de website DMP-" "online vind je na het inloggen met je Solis-ID templates voor een DMP. " @@ -2703,19 +2101,19 @@ msgstr "" "Solis-ID. This is where you can find DMP templates mandated by NWO or ERC " "funding, provided by Utrecht University." -#: proposals/templates/proposals/proposal_data_management.html:43 -#: proposals/templates/proposals/proposal_data_management.html:75 +#: proposals/templates/proposals/proposal_data_management.html:46 +#: proposals/templates/proposals/proposal_data_management.html:79 msgid "Nuttige workshops:" msgstr "Recommended workshops" -#: proposals/templates/proposals/proposal_data_management.html:45 -#: proposals/templates/proposals/proposal_data_management.html:77 +#: proposals/templates/proposals/proposal_data_management.html:48 +#: proposals/templates/proposals/proposal_data_management.html:81 msgid "" "Als je dit nog niet gedaan hebt, wordt er sterk aangeraden om de volgende " "workshop te volgen:" msgstr "If you have not already done so, it is highly recommended you attend: " -#: proposals/templates/proposals/proposal_data_management.html:49 +#: proposals/templates/proposals/proposal_data_management.html:53 msgid "" "

  • de workshop Quick start to Research Data Management
  • " @@ -2723,7 +2121,7 @@ msgstr "" "
  • the workshop Quick start to Research Data Management
  • " -#: proposals/templates/proposals/proposal_data_management.html:58 +#: proposals/templates/proposals/proposal_data_management.html:61 msgid "" "Voor advies op het gebied van data management planning kun je contact " "opnemen met de datamanager GW, Frans de Liagre Böhl via datamanagement.gw@uu.nl, who is the data manager of " "the Faculty of Humanities." -#: proposals/templates/proposals/proposal_data_management.html:62 +#: proposals/templates/proposals/proposal_data_management.html:65 msgid "Privacy: AVG en GDPR" msgstr "Privacy: AVG and GDPR" -#: proposals/templates/proposals/proposal_data_management.html:64 +#: proposals/templates/proposals/proposal_data_management.html:67 msgid "" "Wanneer je persoonsgebonden data verzamelt, zorg je er voor dat je je houdt " "aan de Algemene Verordening Gegevensbescherming, of AVG. Deze wet is de " @@ -2751,7 +2149,7 @@ msgstr "" "regulation is in line with European GDPR privacy legislation." -#: proposals/templates/proposals/proposal_data_management.html:70 +#: proposals/templates/proposals/proposal_data_management.html:73 msgid "" "De autoriteit persoonsgegevens heeft de workshop Handling personal data in research " @@ -2772,7 +2170,7 @@ msgstr "" "
  • the workshop Handling personal data in research
  • " -#: proposals/templates/proposals/proposal_data_management.html:89 +#: proposals/templates/proposals/proposal_data_management.html:94 msgid "" "Voor advies op het gebied van privacy en de AVG kun je contact opnemen met " "de privacy officer van GW via privacy." @@ -2783,11 +2181,14 @@ msgstr "" "gw@uu.nl." #: proposals/templates/proposals/proposal_diff.html:11 -#: proposals/templates/proposals/proposal_diff.html:37 msgid "Overzicht van wijzigingen" msgstr "Summary of changes" -#: proposals/templates/proposals/proposal_diff.html:39 +#: proposals/templates/proposals/proposal_diff.html:38 +msgid "Overzicht van wijzigingen bij aanmelding " +msgstr "Summary of changes of application " + +#: proposals/templates/proposals/proposal_diff.html:42 msgid "" "Dit overzicht toont de gemaakte wijzigingen in de revisie/het amendement ten " "opzichte van de originele aanvraag." @@ -2795,79 +2196,26 @@ msgstr "" "This overview shows the changes made in the revision/amendment with respect " "to the original application." -#: proposals/templates/proposals/proposal_diff.html:49 #: proposals/templates/proposals/proposal_form.html:7 -#: proposals/templates/proposals/proposal_form.html:92 +#: proposals/templates/proposals/proposal_form.html:78 #: proposals/templates/proposals/proposal_form_pre_approved.html:7 -#: proposals/templates/proposals/proposal_form_pre_approved.html:81 -#: proposals/templates/proposals/proposal_pdf.html:82 -#: proposals/templates/proposals/proposal_pdf_empty.html:60 -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:69 -#: proposals/templates/proposals/proposal_pdf_pre_assessment.html:59 -#: proposals/utils/proposal_utils.py:40 proposals/utils/proposal_utils.py:55 -#: proposals/utils/validate_proposal.py:33 -#: proposals/utils/validate_proposal.py:43 -#: proposals/utils/validate_proposal.py:50 -#: proposals/utils/validate_proposal.py:57 +#: proposals/templates/proposals/proposal_form_pre_approved.html:83 +#: proposals/utils/pdf_diff_logic.py:428 proposals/utils/proposal_utils.py:47 +#: proposals/utils/proposal_utils.py:68 proposals/utils/validate_proposal.py:41 +#: proposals/utils/validate_proposal.py:51 +#: proposals/utils/validate_proposal.py:58 +#: proposals/utils/validate_proposal.py:65 msgid "Algemene informatie over de aanvraag" msgstr "General information about the application" -#: proposals/templates/proposals/proposal_diff.html:133 -#: proposals/templates/proposals/proposal_diff.html:134 -#: proposals/templates/proposals/proposal_diff.html:133 -#: proposals/templates/proposals/proposal_diff.html:134 -#: proposals/templates/proposals/proposal_pdf.html:133 -#: proposals/templates/proposals/proposal_pdf.html:520 -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:119 -#: proposals/templates/proposals/proposal_pdf_pre_assessment.html:99 -msgid "onbekend" -msgstr "unknown" - -#: proposals/templates/proposals/proposal_diff.html:174 -#: proposals/templates/proposals/proposal_diff.html:174 -#: proposals/templates/proposals/proposal_pdf.html:159 -#: proposals/templates/proposals/proposal_pdf_empty.html:104 -#: proposals/templates/proposals/proposal_pdf_pre_assessment.html:110 -#: proposals/templates/proposals/wmo_form.html:7 -#: proposals/templates/proposals/wmo_form.html:30 -msgid "" -"Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" -msgstr "" -"Ethical assessment by a Medical Ethical Testing Committee (METC) required?" - -#: proposals/templates/proposals/proposal_diff.html:207 -#: proposals/templates/proposals/proposal_diff.html:207 -#: proposals/templates/proposals/proposal_pdf.html:179 -#: proposals/templates/proposals/proposal_pdf_empty.html:120 -#: proposals/templates/proposals/wmo_application.html:7 -#: proposals/templates/proposals/wmo_application.html:27 -msgid "Aanmelding bij de METC" -msgstr "Registration with the METC" - -#: proposals/templates/proposals/proposal_diff.html:240 -#: proposals/templates/proposals/proposal_diff.html:240 -#: proposals/templates/proposals/proposal_pdf.html:201 -#: proposals/templates/proposals/proposal_pdf_empty.html:134 -#: proposals/templates/proposals/study_start.html:7 -#: proposals/templates/proposals/study_start.html:64 -#: proposals/utils/validate_proposal.py:87 -msgid "Eén of meerdere trajecten?" -msgstr "One or more trajectories?" - -#: proposals/templates/proposals/proposal_diff.html:264 -#: proposals/templates/proposals/proposal_diff.html:264 -#: proposals/templates/proposals/proposal_submit.html:179 -msgid "Concept-aanmelding versturen" -msgstr "Submit draft application" - -#: proposals/templates/proposals/proposal_form.html:72 -#: proposals/templates/proposals/proposal_form_pre_approved.html:72 -#: proposals/templates/proposals/proposal_submit.html:33 +#: proposals/templates/proposals/proposal_form.html:58 +#: proposals/templates/proposals/proposal_form_pre_approved.html:74 +#: proposals/templates/proposals/proposal_submit.html:35 msgid "Aantal woorden:" msgstr "Number of words:" -#: proposals/templates/proposals/proposal_form.html:89 -#: proposals/templates/proposals/proposal_submit.html:168 +#: proposals/templates/proposals/proposal_form.html:75 +#: proposals/templates/proposals/proposal_submit.html:163 msgid "" "Je bewerkt op het moment een oefenaanvraag. Deze kan niet ter beoordeling " "door de FETC-GW worden ingediend." @@ -2875,7 +2223,7 @@ msgstr "" "You are currently editing a practice application. These can not be submitted " "to the FETC-H for review." -#: proposals/templates/proposals/proposal_form.html:94 +#: proposals/templates/proposals/proposal_form.html:80 msgid "" "Je past nu een aanvraag aan van een student/PhD kandidaat onder jouw " "supervisie. Let er op dat je het formulier invult alsof jij die student/PhD " @@ -2885,7 +2233,7 @@ msgstr "" "supervision. Please note that this form should be filled in as if you were " "that student/PhD candidate. " -#: proposals/templates/proposals/proposal_form.html:121 +#: proposals/templates/proposals/proposal_form.html:110 msgid "" "Als de beoogde startdatum binnen twee weken van het indienen van de aanvraag " "ligt, kan de FETC geen officiële goedkeuring meer geven." @@ -2893,7 +2241,7 @@ msgstr "" "If the intended start date lies within two weeks of submission, the FETC-H " "will not be able to provide official approval for this proposal." -#: proposals/templates/proposals/proposal_form_pre_approved.html:83 +#: proposals/templates/proposals/proposal_form_pre_approved.html:85 msgid "" "Je past nu een aanvraag aan van een student/PhD kandidaat onder je " "supervisie. Let er op dat je het formulier invult alsof jij die student/PhD " @@ -2903,7 +2251,7 @@ msgstr "" "supervision. Please note that this form should be filled in as if you were " "that student/PhD candidate. " -#: proposals/templates/proposals/proposal_form_pre_approved.html:97 +#: proposals/templates/proposals/proposal_form_pre_approved.html:99 #, python-format msgid "" "Dit formulier is bedoeld voor aanvragen die al goedgekeurd zijn door een " @@ -2914,14 +2262,14 @@ msgstr "" "different committee. If this is not the case, you are required to fill in " "the full form." -#: proposals/templates/proposals/proposal_list.html:43 -#: proposals/templates/proposals/proposal_private_archive.html:43 -#: reviews/templates/reviews/action_explaination.html:19 +#: proposals/templates/proposals/proposal_list.html:37 +#: proposals/templates/proposals/proposal_private_archive.html:36 +#: reviews/templates/reviews/action_explaination.html:18 msgid "Uitleg" msgstr "Explanation" -#: proposals/templates/proposals/proposal_list.html:47 -#: proposals/templates/proposals/proposal_private_archive.html:47 +#: proposals/templates/proposals/proposal_list.html:41 +#: proposals/templates/proposals/proposal_private_archive.html:40 #, python-format msgid "" "Klik op om naar de " @@ -2930,8 +2278,9 @@ msgstr "" "Click to move on to the " "next step in the progress." -#: proposals/templates/proposals/proposal_list.html:54 -#: proposals/templates/proposals/proposal_private_archive.html:54 +#: proposals/templates/proposals/proposal_list.html:50 +#: proposals/templates/proposals/proposal_private_archive.html:49 +#: reviews/templates/reviews/action_explaination.html:28 #, python-format msgid "" "Klik op om de " @@ -2942,8 +2291,8 @@ msgstr "" "differences between a previous version (only available for revisions/" "amendments)." -#: proposals/templates/proposals/proposal_list.html:61 -#: proposals/templates/proposals/proposal_private_archive.html:61 +#: proposals/templates/proposals/proposal_list.html:59 +#: proposals/templates/proposals/proposal_private_archive.html:58 #, python-format msgid "" "Klik op om je aanvraag te " @@ -2953,7 +2302,8 @@ msgstr "" "application." #: proposals/templates/proposals/proposal_list.html:68 -#: proposals/templates/proposals/proposal_private_archive.html:68 +#: proposals/templates/proposals/proposal_private_archive.html:67 +#: reviews/templates/reviews/action_explaination.html:21 #, python-format msgid "" "Klik op om een ingediende " @@ -2963,7 +2313,16 @@ msgstr "" "application." #: proposals/templates/proposals/proposal_list.html:75 -#: proposals/templates/proposals/proposal_private_archive.html:75 +#, python-format +msgid "" +"Klik op om een revisie " +"aan te maken van je aanvraag." +msgstr "" +"Click to create a revision for " +"an application." + +#: proposals/templates/proposals/proposal_list.html:84 +#: proposals/templates/proposals/proposal_private_archive.html:76 #, python-format msgid "" "Klik op om je beslissing " @@ -2972,8 +2331,9 @@ msgstr "" "Click to make your decision " "(as a supervisor)." -#: proposals/templates/proposals/proposal_list.html:82 -#: proposals/templates/proposals/proposal_private_archive.html:82 +#: proposals/templates/proposals/proposal_list.html:93 +#: proposals/templates/proposals/proposal_private_archive.html:85 +#: reviews/templates/reviews/action_explaination.html:57 #, python-format msgid "" "Klik op om een ingediende " @@ -2982,9 +2342,9 @@ msgstr "" "Click to hide a submitted " "application from the archive." -#: proposals/templates/proposals/proposal_list.html:88 -#: proposals/templates/proposals/proposal_private_archive.html:88 -#: reviews/templates/reviews/action_explaination.html:56 +#: proposals/templates/proposals/proposal_list.html:101 +#: proposals/templates/proposals/proposal_private_archive.html:93 +#: reviews/templates/reviews/action_explaination.html:65 #, python-format msgid "" "Klik op om een ingediende " @@ -2993,135 +2353,38 @@ msgstr "" "Click to submit an application to " "the archive." -#: proposals/templates/proposals/proposal_pdf.html:44 +#: proposals/templates/proposals/proposal_pdf.html:84 #, python-format msgid "" -"FETC-GW - %(title)s (referentienummer %(reference_number)s, " -"ingediend door %(submitter)s)" +"FETC-GW - %(title)s (referentienummer %(reviewing_committee)s-" +"%(reference_number)s, ingediend door %(submitter)s)" msgstr "" -"FEtC-H - %(title)s (reference number %(reference_number)s, " -"submitted by %(submitter)s)" +"FEtC-H - %(title)s (reference number %(reviewing_committee)s-" +"%(reference_number)s, submitted by %(submitter)s)" -#: proposals/templates/proposals/proposal_pdf.html:50 +#: proposals/templates/proposals/proposal_pdf.html:90 #, python-format msgid "%(type)s van referentienummer %(reference_number)s" msgstr "%(type)s of reference number %(reference_number)s" -#: proposals/templates/proposals/proposal_pdf.html:66 +#: proposals/templates/proposals/proposal_pdf.html:104 #, python-format msgid "Referentienummer %(reference_number)s" msgstr "Reference number %(reference_number)s" -#: proposals/templates/proposals/proposal_pdf.html:70 +#: proposals/templates/proposals/proposal_pdf.html:109 msgid "Huidige staat van de aanvraag" msgstr "Current state of the application" -#: proposals/templates/proposals/proposal_pdf.html:73 -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:60 +#: proposals/templates/proposals/proposal_pdf.html:111 msgid "Indiener" msgstr "Applicant" -#: proposals/templates/proposals/proposal_pdf.html:76 -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:63 +#: proposals/templates/proposals/proposal_pdf.html:113 #: tasks/templates/tasks/task_list.html:7 msgid "Naam" msgstr "Name" -#: proposals/templates/proposals/proposal_pdf.html:194 -msgid "Niet aangeleverd" -msgstr "Not provided" - -#: proposals/templates/proposals/proposal_pdf.html:481 -#: proposals/templates/proposals/study_consent.html:138 -msgid "Extra formulieren" -msgstr "Additional forms" - -#: proposals/templates/proposals/proposal_pdf.html:513 -#: proposals/templates/proposals/proposal_pdf_empty.html:389 -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:150 -#: proposals/templates/proposals/proposal_submit.html:181 -msgid "Aanmelding versturen" -msgstr "Submit application" - -#: proposals/templates/proposals/proposal_pdf_empty.html:42 -msgid "" -"\n" -" FETC-GW - naam aanvraag (referentienummer referentienummer)\n" -" " -msgstr "" -"\n" -" FEtC-H - application name (reference number reference " -"number)\n" -" " - -#: proposals/templates/proposals/proposal_pdf_empty.html:56 -msgid "" -"\n" -" Referentienummer referentienummer\n" -" " -msgstr "" -"\n" -" Reference number reference number\n" -" " - -#: proposals/templates/proposals/proposal_pdf_empty.html:286 -#: proposals/templates/proposals/proposal_start.html:62 -#: proposals/templates/proposals/proposal_start_practice.html:63 -#: proposals/templates/proposals/study_start.html:81 -msgid "Sessie" -msgstr "Session" - -#: proposals/templates/proposals/proposal_pdf_empty.html:304 -#: proposals/templates/proposals/proposal_start.html:69 -#: proposals/templates/proposals/proposal_start_practice.html:70 -#: proposals/templates/proposals/study_start.html:88 -msgid "Taak" -msgstr "Task" - -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:42 -#, python-format -msgid "" -"\n" -" FETC-GW - Aanvraag elders al goedgekeurde aanvraag %(title)s " -"(referentienummer %(reference_number)s, ingediend door %(submitter)s)\n" -" " -msgstr "" -"\n" -" FEtC-H - Application for preapproved assessment %(title)s " -"(reference number %(reference_number)s, submitted by %(submitter)s)\n" -" " - -#: proposals/templates/proposals/proposal_pdf_pre_approved.html:56 -#: proposals/templates/proposals/proposal_pdf_pre_assessment.html:55 -#, python-format -msgid "" -"\n" -" Referentienummer %(reference_number)s\n" -" " -msgstr "" -"\n" -" Reference number %(reference_number)s\n" -" " - -#: proposals/templates/proposals/proposal_pdf_pre_assessment.html:41 -#, python-format -msgid "" -"\n" -" FETC-GW - Aanvraag voor voortoetsing %(title)s " -"(referentienummer %(reference_number)s, ingediend door %(submitter)s)\n" -" " -msgstr "" -"\n" -" FEtC-H - Application for preliminary assessment %(title)s " -"(reference number %(reference_number)s, submitted by %(submitter)s)\n" -" " - -#: proposals/templates/proposals/proposal_pdf_pre_assessment.html:130 -#: proposals/templates/proposals/proposal_submit.html:175 -msgid "Aanvraag voor voortoetsing versturen" -msgstr "Submit application for preliminary assessment" - #: proposals/templates/proposals/proposal_public_archive.html:8 #: proposals/templates/proposals/proposal_public_archive.html:14 msgid "Goedgekeurde aanvragen" @@ -3143,11 +2406,11 @@ msgstr "Approval date" msgid "FETC-GW kamer" msgstr "FEtC-H chamber" -#: proposals/templates/proposals/proposal_public_archive.html:34 +#: proposals/templates/proposals/proposal_public_archive.html:32 msgid "AK" msgstr "GC" -#: proposals/templates/proposals/proposal_public_archive.html:36 +#: proposals/templates/proposals/proposal_public_archive.html:34 msgid "LK" msgstr "LC" @@ -3156,21 +2419,17 @@ msgstr "LC" msgid "Een nieuwe aanvraag aanmelden" msgstr "Register a new application" -#: proposals/templates/proposals/proposal_start.html:26 -#: proposals/templates/proposals/proposal_start_practice.html:28 +#: proposals/templates/proposals/proposal_start.html:25 +#: proposals/templates/proposals/proposal_start_practice.html:25 msgid "" -"Het reglement van de Algemene Kamer (AK) of dat van de Linguïstiek Kamer (LK)." +"Het reglement van de FEtC-H." msgstr "" "The regulations of the General Chamber or those of the Linguistics Chamber." +"fetc-h/\" target=\"_blank\">FEtC-H ." -#: proposals/templates/proposals/proposal_start.html:35 -#: proposals/templates/proposals/proposal_start_practice.html:37 +#: proposals/templates/proposals/proposal_start.html:31 +#: proposals/templates/proposals/proposal_start_practice.html:31 msgid "" "Gebruik de juiste (meest recente) voorbeelddocumenten voor de " @@ -3180,9 +2439,9 @@ msgstr "" "en/documents-ethics-assessment-committee-humanities\" " "target=\"_blank\">model documents for informed consent." -#: proposals/templates/proposals/proposal_start.html:40 -#: proposals/templates/proposals/proposal_start_practice.html:42 -#: proposals/templates/proposals/study_consent.html:89 +#: proposals/templates/proposals/proposal_start.html:36 +#: proposals/templates/proposals/proposal_start_practice.html:36 +#: proposals/templates/proposals/study_consent.html:88 msgid "" "Studenten moeten hun begeleider vragen om deze formulieren; dezelfde " "voorbeeldteksten, maar op niet-officiële formulieren, zijn te vinden op this page, though on non-" "official documents." -#: proposals/templates/proposals/proposal_start.html:47 -#: proposals/templates/proposals/proposal_start_practice.html:49 -#: proposals/templates/proposals/study_start.html:67 +#: proposals/templates/proposals/proposal_start.html:43 +#: proposals/templates/proposals/proposal_start_practice.html:43 +#: proposals/templates/proposals/study_start.html:65 msgid "" -"\n" -" Een voorstel is opgebouwd uit (van groot naar klein) (i) " -"trajecten, (ii) sessies, (iii) taken.\n" -" " +"Een voorstel is opgebouwd uit (van groot naar klein) (i) trajecten, (ii) " +"sessies, (iii) taken." msgstr "" -"\n" "An application consists of (i) trajectories, (ii) sessions, and (iii) tasks, " -"in descending order of subdivision. " +"in descending order of subdivision. " -#: proposals/templates/proposals/proposal_start.html:53 -#: proposals/templates/proposals/proposal_start_practice.html:55 -#: proposals/templates/proposals/study_start.html:73 -#: reviews/templates/reviews/committee_members_workload.html:24 +#: proposals/templates/proposals/proposal_start.html:49 +#: proposals/templates/proposals/proposal_start_practice.html:49 +#: proposals/templates/proposals/study_start.html:71 +#: proposals/utils/pdf_diff_logic.py:337 +#: reviews/templates/reviews/committee_members_workload.html:23 msgid "Traject" msgstr "Trajectory" -#: proposals/templates/proposals/proposal_start.html:54 -#: proposals/templates/proposals/proposal_start_practice.html:56 -#: proposals/templates/proposals/study_start.html:74 +#: proposals/templates/proposals/proposal_start.html:50 +#: proposals/templates/proposals/proposal_start_practice.html:50 +#: proposals/templates/proposals/study_start.html:72 msgid "" "Als je met verschillende deelnemersgroepen werkt die een verschillend " "onderzoekstraject doorlopen waarvoor verschillende informed consent " @@ -3225,8 +2482,8 @@ msgstr "" "not follow the same instructions during your research, they traverse " "different trajectories, and require separate informed consent documents. " -#: proposals/templates/proposals/proposal_start.html:56 -#: proposals/templates/proposals/proposal_start_practice.html:58 +#: proposals/templates/proposals/proposal_start.html:54 +#: proposals/templates/proposals/proposal_start_practice.html:54 #: proposals/templates/proposals/study_start.html:76 msgid "" "Bijvoorbeeld: ouders van leerlingen 15 jaar en jonger, docenten, een " @@ -3235,15 +2492,27 @@ msgstr "" "For example: parents of children up to 15 years of age, teachers, or " "an experimental and control group that receive significantly different tasks." -#: proposals/templates/proposals/proposal_start.html:63 -#: proposals/templates/proposals/proposal_start_practice.html:64 +#: proposals/templates/proposals/proposal_start.html:60 +#: proposals/templates/proposals/proposal_start_practice.html:60 #: proposals/templates/proposals/study_start.html:82 +msgid "Sessie" +msgstr "Session" + +#: proposals/templates/proposals/proposal_start.html:61 +#: proposals/templates/proposals/proposal_start_practice.html:61 +#: proposals/templates/proposals/study_start.html:83 msgid "Alle taken/onderdelen die iemand op één dag uitvoert." msgstr "" "All tasks or procedures that a participant completes in a day combined. " -#: proposals/templates/proposals/proposal_start.html:70 -#: proposals/templates/proposals/proposal_start_practice.html:71 +#: proposals/templates/proposals/proposal_start.html:66 +#: proposals/templates/proposals/proposal_start_practice.html:66 +#: proposals/templates/proposals/study_start.html:88 +msgid "Taak" +msgstr "Task" + +#: proposals/templates/proposals/proposal_start.html:67 +#: proposals/templates/proposals/proposal_start_practice.html:67 #: proposals/templates/proposals/study_start.html:89 msgid "" "Een taak of onderdeel van je onderzoek.

    Bijvoorbeeld: het " @@ -3252,25 +2521,25 @@ msgstr "" " A task or procedure within your study.

    For example: completing " "an interview, questionnaire, or language test.

    " -#: proposals/templates/proposals/proposal_start.html:80 -#: proposals/templates/proposals/proposal_start_pre_approved.html:42 -#: proposals/templates/proposals/proposal_start_pre_assessment.html:31 +#: proposals/templates/proposals/proposal_start.html:76 +#: proposals/templates/proposals/proposal_start_pre_approved.html:37 +#: proposals/templates/proposals/proposal_start_pre_assessment.html:43 msgid "Volgende stap >>" msgstr "Next step >>" #: proposals/templates/proposals/proposal_start_practice.html:7 -#: proposals/templates/proposals/proposal_start_practice.html:14 +#: proposals/templates/proposals/proposal_start_practice.html:13 msgid "Een nieuwe aanvraag aanmelden (oefenportaal)" msgstr "Register a new application (practice portal)" -#: proposals/templates/proposals/proposal_start_practice.html:80 +#: proposals/templates/proposals/proposal_start_practice.html:75 msgid "Houd er rekening mee dat een oefenaanvraag niet ingediend kan worden." msgstr "" "Please be advised that a practice application cannot be submitted to the " "FETC-H." -#: proposals/templates/proposals/proposal_start_pre_approved.html:9 -#: proposals/templates/proposals/proposal_start_pre_approved.html:18 +#: proposals/templates/proposals/proposal_start_pre_approved.html:7 +#: proposals/templates/proposals/proposal_start_pre_approved.html:14 msgid "" "Een nieuwe aanvraag aanmelden (die al goedgekeurd is door een andere " "ethische toetsingscomissie)" @@ -3278,7 +2547,7 @@ msgstr "" "Register a new application (that has been approved by another ethics " "committee)" -#: proposals/templates/proposals/proposal_start_pre_approved.html:21 +#: proposals/templates/proposals/proposal_start_pre_approved.html:16 #, python-format msgid "" "Je wilt een nieuwe aanvraag ter toetsing bij de FETC-GW aanmelden, die al " @@ -3294,7 +2563,7 @@ msgstr "" "yourself and the committee members a great deal of time by making sure you " "are properly informed." -#: proposals/templates/proposals/proposal_start_pre_approved.html:31 +#: proposals/templates/proposals/proposal_start_pre_approved.html:26 #, python-format msgid "" "Gebruik bij het invullen s.v.p. geen afkortingen waar de FETC-GW wellicht " @@ -3317,7 +2586,7 @@ msgstr "Ethical assessment for grant application" msgid "Nieuwe FETC-aanvraag voor (al dan niet goedgekeurde) subsidieaanvragen" msgstr "Submit a new application to supplement a grant application" -#: proposals/templates/proposals/proposal_start_pre_assessment.html:19 +#: proposals/templates/proposals/proposal_start_pre_assessment.html:17 msgid "" "Soms is bij het indienen van een aanvraag bij een subsidieverstrekker een " "ethische verklaring nodig." @@ -3325,7 +2594,7 @@ msgstr "" "Sometimes grant providers will require assessment by an ethics committee as " "part of their grant application procedure." -#: proposals/templates/proposals/proposal_start_pre_assessment.html:20 +#: proposals/templates/proposals/proposal_start_pre_assessment.html:22 msgid "" "Goedgekeurde NWO-aanvragen hebben ook een ethische verklaring nodig alvorens " "een startdatum vastgesteld kan worden." @@ -3334,7 +2603,7 @@ msgstr "" "supplement a grant application once the grant has been awarded. It is " "however still required before a starting date can be determined." -#: proposals/templates/proposals/proposal_start_pre_assessment.html:23 +#: proposals/templates/proposals/proposal_start_pre_assessment.html:28 msgid "" "In deze gevallen kunnen onderzoekers de FETC-GW verzoeken om de " "onderzoeksaanvraag te laten toetsen. Dit kan via deze route van de portal" @@ -3342,7 +2611,7 @@ msgstr "" "In these cases, researchers can request an assessment of their application " "by the FEtC-H through this route" -#: proposals/templates/proposals/proposal_start_pre_assessment.html:25 +#: proposals/templates/proposals/proposal_start_pre_assessment.html:34 msgid "" "NB: De toetsing kan alleen op hoofdlijnen plaatsvinden en vervangt NIET de " "reguliere ethische toetsing van een onderzoek; elke mensgebonden studie die " @@ -3356,77 +2625,47 @@ msgstr "" "process." #: proposals/templates/proposals/proposal_submit.html:8 -#: proposals/templates/proposals/proposal_submit.html:47 -#: proposals/utils/proposal_utils.py:49 proposals/utils/proposal_utils.py:58 +#: proposals/templates/proposals/proposal_submit.html:49 +#: proposals/utils/proposal_utils.py:59 proposals/utils/proposal_utils.py:73 msgid "Aanvraag voor voortoetsing klaar voor versturen" msgstr "Application for preliminary assessment ready to submit" #: proposals/templates/proposals/proposal_submit.html:10 -#: proposals/templates/proposals/proposal_submit.html:49 +#: proposals/templates/proposals/proposal_submit.html:51 msgid "Concept-aanmelding klaar voor versturen" msgstr "Draft application ready to submit" #: proposals/templates/proposals/proposal_submit.html:12 -#: proposals/templates/proposals/proposal_submit.html:51 +#: proposals/templates/proposals/proposal_submit.html:53 msgid "Aanmelding klaar voor versturen" msgstr "Application ready to submit" -#: proposals/templates/proposals/proposal_submit.html:56 -msgid "" -"\n" -" Je aanvraag voor voortoetsing is compleet.\n" -" " -msgstr "" -"\n" -" Your application for preliminary assessment is complete.\n" -" " +#: proposals/templates/proposals/proposal_submit.html:58 +msgid "Je aanvraag voor voortoetsing is compleet." +msgstr "Your application for preliminary assessment is complete." -#: proposals/templates/proposals/proposal_submit.html:59 +#: proposals/templates/proposals/proposal_submit.html:61 #: proposals/templates/proposals/proposal_submit.html:76 msgid "" -"\n" -" Als je er zeker van bent dat je aanvraag op adequate " -"wijze is gespecifieerd kan je de aanmelding\n" -" nu ter beoordeling naar de FETC-GW versturen.\n" -" " +"Als je er zeker van bent dat je aanvraag op adequate wijze is gespecifieerd " +"kan je de aanmelding nu ter beoordeling naar de FETC-GW versturen." msgstr "" -"\n" -" If you are sure your application is adequately described, you can now " -"submit the application\n" -" to the FEtC-H for assessment.\n" -" " +"If you are sure your application is adequately described, you can now submit " +"the application to the FEtC-H for assessment." -#: proposals/templates/proposals/proposal_submit.html:65 -msgid "" -"\n" -" Je concept-aanmelding is compleet.\n" -" " -msgstr "" -"\n" -" Your draft application is complete.\n" -" " +#: proposals/templates/proposals/proposal_submit.html:66 +msgid "Je concept-aanmelding is compleet." +msgstr "Your draft application is complete." -#: proposals/templates/proposals/proposal_submit.html:68 +#: proposals/templates/proposals/proposal_submit.html:69 msgid "" -"\n" -" Je kan nu je concept-aanmelding ter beoordeling naar " -"je supervisor versturen.\n" -" " +"Je kan nu je concept-aanmelding ter beoordeling naar je supervisor versturen." msgstr "" -"\n" -" You can now send your draft application to your supervisor for " -"assessment.\n" -" " +"You can now send your draft application to your supervisor for assessment." #: proposals/templates/proposals/proposal_submit.html:73 -msgid "" -"\n" -" Je aanmelding is compleet.\n" -" " -msgstr "" -"\n" -" Your application is complete.\n" -" " +msgid "Je aanmelding is compleet." +msgstr "Your application is complete." #: proposals/templates/proposals/proposal_submit.html:83 msgid "" @@ -3448,7 +2687,7 @@ msgstr "" "start page; the draft application can be saved for any later changes and " "submission." -#: proposals/templates/proposals/proposal_submit.html:101 +#: proposals/templates/proposals/proposal_submit.html:100 #, python-format msgid "" "Je hebt nog geen toestemmingsverklaring of informatiebrief toegevoegd voor " @@ -3463,7 +2702,7 @@ msgstr "" "you can return later; your application has already been saved and can be " "found under \"My drafts\"." -#: proposals/templates/proposals/proposal_submit.html:113 +#: proposals/templates/proposals/proposal_submit.html:112 #, python-format msgid "" "Je hebt aangeven dat je interventie een extra taak heeft, maar nog geen " @@ -3474,11 +2713,11 @@ msgstr "" "the task-based research form is missing for trajectory %(study_order)s.You " "can add it on this page." -#: proposals/templates/proposals/proposal_submit.html:128 +#: proposals/templates/proposals/proposal_submit.html:125 msgid "Er zijn nog errors gevonden op de volgende pagina's:" msgstr "Errors were found on the following pages:" -#: proposals/templates/proposals/proposal_submit.html:141 +#: proposals/templates/proposals/proposal_submit.html:136 msgid "" "Dit komt waarschijnlijk doordat je nog niet alle verplichte velden heeft " "ingevuld. Je kan je aanmelding pas versturen wanneer deze fouten " @@ -3487,11 +2726,11 @@ msgstr "" "This is probably because you have not yet filled in all required fields. You " "can submit your application when these errors have been corrected." -#: proposals/templates/proposals/proposal_submit.html:149 +#: proposals/templates/proposals/proposal_submit.html:144 msgid "Controleer uw beoogde startdatum" msgstr "Check your intended start date" -#: proposals/templates/proposals/proposal_submit.html:151 +#: proposals/templates/proposals/proposal_submit.html:146 msgid "" "Omdat de beoogde startdatum binnen twee weken van vandaag ligt, kan de FETC " "helaas geen officiële goedkeuring meer geven voor deze aanvraag. Controleer " @@ -3501,7 +2740,7 @@ msgstr "" "of today, the FETC-H will not be able to provide official approval for this " "application. Please make sure the entered date is still correct." -#: proposals/templates/proposals/proposal_submit.html:155 +#: proposals/templates/proposals/proposal_submit.html:150 #, python-format msgid "" "De beoogde startdatum vindt u op deze paginathis " "page." -#: proposals/templates/proposals/proposal_submit.html:177 +#: proposals/templates/proposals/proposal_submit.html:170 +msgid "Aanvraag voor voortoetsing versturen" +msgstr "Submit application for preliminary assessment" + +#: proposals/templates/proposals/proposal_submit.html:172 msgid "Terug naar beoordeling >>" msgstr "Back to review >>" +#: proposals/templates/proposals/proposal_submit.html:174 +msgid "Concept-aanmelding versturen" +msgstr "Submit draft application" + +#: proposals/templates/proposals/proposal_submit.html:176 +#: proposals/utils/pdf_diff_logic.py:982 +msgid "Aanmelding versturen" +msgstr "Submit application" + #: proposals/templates/proposals/proposal_submitted.html:8 #: proposals/templates/proposals/proposal_submitted.html:22 msgid "Aanvraag voor voortoetsing verstuurd" @@ -3545,7 +2797,7 @@ msgstr "Your application has been submitted." msgid "Je ontvangt een e-mail ter bevestiging." msgstr "You will receive a confirmation email." -#: proposals/templates/proposals/proposal_submitted.html:40 +#: proposals/templates/proposals/proposal_submitted.html:39 #, python-format msgid "" "Klik hier om je ingediende aanvragen in te " @@ -3554,7 +2806,7 @@ msgstr "" "Click here to see your submitted " "applications." -#: proposals/templates/proposals/proposal_update_attachments.html:17 +#: proposals/templates/proposals/proposal_update_attachments.html:15 #, python-format msgid "" "Op deze pagina kan je de formulieren aanpassen behorende bij de aanvraag " @@ -3563,28 +2815,47 @@ msgstr "" "On this page you can edit the forms related to the proposal " "%(title)s(reference number %(ref_number)s)" +#: proposals/templates/proposals/proposal_update_date_start.html:13 +#: proposals/templates/proposals/proposal_update_date_start.html:31 +msgid "Startdatum aanpassen" +msgstr "Edit start date" + +#: proposals/templates/proposals/proposal_update_date_start.html:15 +#, python-format +msgid "" +"Op deze pagina kan de startdatum worden aangepast van de aanvraag %(title)s " +"(referentienummer %(ref_number)s). Let op! Als de review al " +"is afgerond, wordt de nieuwe startdatum niet automatisch weergegeven in de " +"PDF. Mocht je de PDF opnieuw willen genereren, neem hierover dan contact op " +"met" +msgstr "" +"On this page, the start date of proposal %(title)s (reference number " +"%(ref_number)s) can be edited. Note! If the review has " +"already been concluded, the new start date will not be displayed in the PDF. " +"If you would like the PDF to be generated with the new start date, please " +"reach out to " + #: proposals/templates/proposals/study_consent.html:27 msgid "Toestemmingsverklaring van de schoolleider/hoofd van het departement" msgstr "Informed consent school director/ head of the institution" -#: proposals/templates/proposals/study_consent.html:74 +#: proposals/templates/proposals/study_consent.html:72 msgid "Informed consent formulieren uploaden" msgstr "Upload Informed consent forms" -#: proposals/templates/proposals/study_consent.html:77 +#: proposals/templates/proposals/study_consent.html:74 msgid "" "Hier kan je de Informed consent formulieren uploaden voor de opgegeven " "traject(en). Optioneel kan je indien nodig maximaal 10 paar extra " -"formulieren uploaden.
    Klik hiervoor op 'Voeg extra formulieren' " +"formulieren uploaden.
    Klik hiervoor op 'Voeg extra formulieren' " "onderaan de pagina. Deze velden kan je weer weg halen door alle formulieren " "te wissen." msgstr "" -" You can upload the informed consent forms for your trajectories " -"here. If needed, you can also upload up to 10 sets of additional forms.
    These extra fields can be removed by clearing all forms in one " -"section. " +"You can upload the informed consent forms for your trajectories here. If " +"needed, you can also upload up to 10 sets of additional forms.
    These " +"extra fields can be removed by clearing all forms in one section." -#: proposals/templates/proposals/study_consent.html:85 +#: proposals/templates/proposals/study_consent.html:83 msgid "" "Gebruik de juiste (meest recente) model documents for informed consent." -#: proposals/templates/proposals/study_consent.html:95 +#: proposals/templates/proposals/study_consent.html:93 msgid "" "Let op dat je documenten geen redactionele fouten en/of taalfouten bevatten: " "een aanvraag kan hierom direct voor revisie worden teruggestuurd." @@ -3604,7 +2875,7 @@ msgstr "" "grammatical errors. Your application may be sent straight back for revision " "because of these." -#: proposals/templates/proposals/study_consent.html:98 +#: proposals/templates/proposals/study_consent.html:96 msgid "" "Bij ontvangst worden alle bestandsnamen gewijzigd, zet hier dus geen " "belangrijke informatie in." @@ -3612,7 +2883,7 @@ msgstr "" "Files are renamed upon arrival, so please do not put information in the " "filename that you later rely on." -#: proposals/templates/proposals/study_consent.html:104 +#: proposals/templates/proposals/study_consent.html:103 msgid "" "Omdat er in één of meer trajecten onderzoek wordt uitgevoerd op een externe " "locatie waar toestemming voor vereist is, vragen we daar om een tweede set " @@ -3628,10 +2899,21 @@ msgstr "" "head of department of a medical institution. If applicable, please include " "the information letter for parents or guardians." -#: proposals/templates/proposals/study_consent.html:132 +#: proposals/templates/proposals/study_consent.html:136 msgid "Voeg extra formulieren toe" msgstr "Add additional forms" +#: proposals/templates/proposals/study_consent.html:142 +msgid "Extra formulieren" +msgstr "Additional forms" + +#: proposals/templates/proposals/study_start.html:7 +#: proposals/templates/proposals/study_start.html:63 +#: proposals/utils/pdf_diff_logic.py:530 +#: proposals/utils/validate_proposal.py:95 +msgid "Eén of meerdere trajecten?" +msgstr "One or more trajectories?" + #: proposals/templates/proposals/study_start.html:13 msgid "" "Geef elk traject hieronder een behulpzame naam van maximaal 15 karakters." @@ -3653,12 +2935,20 @@ msgstr "" "You can now describe the nature of each trajectory of the study on " "the following pages." -#: proposals/templates/proposals/translated_consent_forms.html:25 -#: proposals/utils/validate_proposal.py:223 +#: proposals/templates/proposals/table_with_header_diff.html:11 +msgid "Originele aanvraag" +msgstr "Original application" + +#: proposals/templates/proposals/table_with_header_diff.html:12 +msgid "Revisie/amendement" +msgstr "Revision/amendment" + +#: proposals/templates/proposals/translated_consent_forms.html:24 +#: proposals/utils/validate_proposal.py:224 msgid "Vertaling informed consent formulieren" msgstr "Translation of informed consent forms" -#: proposals/templates/proposals/translated_consent_forms.html:29 +#: proposals/templates/proposals/translated_consent_forms.html:26 msgid "" "Documenten moet in het Nederlands of in het Engels worden ingediend. Echter, " "om je deelnemers op een adequate manier te informeren kan het noodzakelijk " @@ -3679,67 +2969,77 @@ msgstr "" "can be done after approval, or during a minimal revision." #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:43 -#: proposals/templates/proposals/vue_templates/proposal_list.html:73 +#: proposals/templates/proposals/vue_templates/proposal_list.html:75 msgid "Inzien" msgstr "Show" #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:50 -#: proposals/templates/proposals/vue_templates/proposal_list.html:87 +#: proposals/templates/proposals/vue_templates/proposal_list.html:95 msgid "Soort aanvraag" msgstr "Type of application" #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:57 #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:65 -#: proposals/templates/proposals/vue_templates/proposal_list.html:94 #: proposals/templates/proposals/vue_templates/proposal_list.html:102 +#: proposals/templates/proposals/vue_templates/proposal_list.html:110 msgid "Besloten op" msgstr "Concluded on" #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:78 -#: proposals/templates/proposals/vue_templates/proposal_list.html:115 +#: proposals/templates/proposals/vue_templates/proposal_list.html:123 msgid "Status" msgstr "State" #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:110 -#: proposals/templates/proposals/vue_templates/proposal_list.html:161 +#: proposals/templates/proposals/vue_templates/proposal_list.html:169 msgid "Nog niet ingediend" msgstr "Not yet submitted" #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:129 -#: proposals/templates/proposals/vue_templates/proposal_list.html:180 +#: proposals/templates/proposals/vue_templates/proposal_list.html:188 msgid "Route:" msgstr "Route:" #: proposals/templates/proposals/vue_templates/proposal_archive_list.html:136 -#: proposals/templates/proposals/vue_templates/proposal_list.html:187 +#: proposals/templates/proposals/vue_templates/proposal_list.html:195 #: reviews/templates/reviews/vue_templates/decision_list.html:185 #: reviews/templates/reviews/vue_templates/decision_list_reviewer.html:128 -#: reviews/templates/reviews/vue_templates/review_list.html:184 +#: reviews/templates/reviews/vue_templates/review_list.html:190 msgid "Indieners" msgstr "Applicants" -#: proposals/templates/proposals/vue_templates/proposal_list.html:41 +#: proposals/templates/proposals/vue_templates/proposal_list.html:43 #: reviews/templates/reviews/vue_templates/decision_list.html:68 #: reviews/templates/reviews/vue_templates/decision_list.html:71 msgid "Beslissen" msgstr "Decide" -#: proposals/templates/proposals/vue_templates/proposal_list.html:60 +#: proposals/templates/proposals/vue_templates/proposal_list.html:62 msgid "Naar volgende stap" msgstr "To next step" -#: proposals/templates/proposals/vue_templates/proposal_list.html:80 +#: proposals/templates/proposals/vue_templates/proposal_list.html:82 msgid "Verberg" -msgstr "Hide" +msgstr "" -#: proposals/templates/proposals/vue_templates/proposal_list.html:139 +#: proposals/templates/proposals/vue_templates/proposal_list.html:89 +msgid "Maak revisie" +msgstr "Create revision" + +#: proposals/templates/proposals/vue_templates/proposal_list.html:147 #: reviews/templates/reviews/vue_templates/decision_list.html:141 #: reviews/templates/reviews/vue_templates/decision_list_reviewer.html:83 -#: reviews/templates/reviews/vue_templates/review_list.html:139 +#: reviews/templates/reviews/vue_templates/review_list.html:145 msgid "Revisie/amendement van" msgstr "Revision/amendment of" -#: proposals/templates/proposals/wmo_application.html:33 +#: proposals/templates/proposals/wmo_application.html:7 +#: proposals/templates/proposals/wmo_application.html:26 +#: proposals/utils/pdf_diff_logic.py:522 +msgid "Aanmelding bij de METC" +msgstr "Registration with the METC" + +#: proposals/templates/proposals/wmo_application.html:34 msgid "" "Zolang je aanvraag nog niet is beoordeeld door de METC, kan je niet verder " "in het aanmeldingsproces." @@ -3748,145 +3048,210 @@ msgstr "" "the application process." #: proposals/templates/proposals/wmo_check.html:7 -#: proposals/templates/proposals/wmo_check.html:26 +#: proposals/templates/proposals/wmo_check.html:27 msgid "WMO-check" msgstr "WMO check" -#: proposals/templates/proposals/wmo_check.html:31 +#: proposals/templates/proposals/wmo_check.html:37 msgid "Opnieuw beginnen" msgstr "Start again" -#: proposals/utils/proposal_utils.py:42 proposals/utils/validate_proposal.py:69 -#: proposals/utils/validate_proposal.py:76 +#: proposals/templates/proposals/wmo_form.html:7 +#: proposals/templates/proposals/wmo_form.html:30 +#: proposals/utils/pdf_diff_logic.py:497 +msgid "" +"Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" +msgstr "" +"Ethical assessment by a Medical Ethical Testing Committee (METC) required?" + +#: proposals/utils/pdf_diff_logic.py:93 +msgid "" +"Dit onderdeel is nieuw in de revisie en bestond niet in de originele " +"aanvraag." +msgstr "" +"This section was added in the revision, and did not feature in the original " +"application." + +#: proposals/utils/pdf_diff_logic.py:100 +msgid "" +"Dit onderdeel bestond in de originele aanvraag, maar niet meer in de revisie." +msgstr "" +"This section was present in the original application, but was removed for " +"the revision." + +#: proposals/utils/pdf_diff_logic.py:248 reviews/models.py:111 +msgid "Onbekend" +msgstr "Unknown" + +#: proposals/utils/pdf_diff_logic.py:291 +msgid "Download" +msgstr "Download" + +#: proposals/utils/pdf_diff_logic.py:294 +msgid "Niet aangeleverd" +msgstr "Not provided" + +#: proposals/utils/pdf_diff_logic.py:317 tasks/templates/tasks/task_end.html:7 +#: tasks/templates/tasks/task_end.html:16 +msgid "Overzicht van het takenonderzoek" +msgstr "Overview of task-based research" + +#: proposals/utils/pdf_diff_logic.py:330 proposals/utils/pdf_diff_logic.py:357 +#: proposals/utils/pdf_diff_logic.py:366 proposals/utils/pdf_diff_logic.py:390 +msgid "Traject " +msgstr "Trajectory " + +#: proposals/utils/pdf_diff_logic.py:360 proposals/utils/pdf_diff_logic.py:393 +msgid "sessie " +msgstr "session " + +#: proposals/utils/pdf_diff_logic.py:373 proposals/utils/pdf_diff_logic.py:401 +msgid "Sessie " +msgstr "Session " + +#: proposals/utils/pdf_diff_logic.py:395 proposals/utils/pdf_diff_logic.py:403 +msgid ", taak " +msgstr ", task " + +#: proposals/utils/pdf_diff_logic.py:548 +#: studies/templates/studies/study_form.html:7 +#: studies/templates/studies/study_form.html:80 +msgid "De deelnemers" +msgstr "Participants" + +#: proposals/utils/pdf_diff_logic.py:752 +#: studies/templates/studies/session_start.html:7 +#: studies/templates/studies/session_start.html:16 +#: tasks/templates/tasks/task_form.html:7 +#: tasks/templates/tasks/task_form.html:27 +#: tasks/templates/tasks/task_start.html:7 +#: tasks/templates/tasks/task_start.html:27 +msgid "Het takenonderzoek en interviews" +msgstr "Task-based research and interviews" + +#: proposals/utils/pdf_diff_logic.py:840 +#: studies/templates/studies/study_end.html:7 +#: studies/templates/studies/study_end.html:27 +msgid "Overzicht en eigen beoordeling van het gehele onderzoek" +msgstr "Overview and self-assessment of the entire study" + +#: proposals/utils/pdf_diff_logic.py:950 +msgid "Extra formulieren " +msgstr "Additional forms " + +#: proposals/utils/proposal_utils.py:51 proposals/utils/validate_proposal.py:77 +#: proposals/utils/validate_proposal.py:84 msgid "Ethische toetsing nodig door een METC?" msgstr "Ethical assessment by a METC necessary?" -#: proposals/utils/proposal_utils.py:68 +#: proposals/utils/proposal_utils.py:87 msgid "Algemeen" msgstr "General" -#: proposals/utils/proposal_utils.py:73 +#: proposals/utils/proposal_utils.py:91 msgid "METC" msgstr "METC" -#: proposals/utils/proposal_utils.py:87 +#: proposals/utils/proposal_utils.py:98 msgid "Trajecten" msgstr "Trajectories" -#: proposals/utils/proposal_utils.py:100 +#: proposals/utils/proposal_utils.py:108 msgid "Uploaden" msgstr "Upload" -#: proposals/utils/proposal_utils.py:107 +#: proposals/utils/proposal_utils.py:111 msgid "Vertaling" msgstr "Translation" -#: proposals/utils/proposal_utils.py:114 +#: proposals/utils/proposal_utils.py:115 msgid "Formulieren" msgstr "Forms" -#: proposals/utils/proposal_utils.py:122 +#: proposals/utils/proposal_utils.py:119 msgid "Versturen" msgstr "Submit" -#: proposals/utils/proposal_utils.py:416 -#: proposals/utils/proposal_utils.py:416 +#: proposals/utils/proposal_utils.py:417 msgid "FETC-GW: gereviseerde aanvraag gebruikt labfaciliteiten" msgstr "FEtC-H: A revised application uses lab facilities" -#: proposals/utils/proposal_utils.py:418 -#: proposals/utils/proposal_utils.py:418 +#: proposals/utils/proposal_utils.py:419 msgid "FETC-GW: nieuwe aanvraag gebruikt labfaciliteiten" msgstr "FEtC-H: New application uses lab facilities" -#: proposals/utils/validate_proposal.py:98 +#: proposals/utils/validate_proposal.py:106 msgid "De deelnemers (traject {})" msgstr "Participants (trajectory {})" -#: proposals/utils/validate_proposal.py:106 +#: proposals/utils/validate_proposal.py:114 msgid "De onderzoekstype(n) (traject {})" msgstr "Type(s) of research (trajectory {})" -#: proposals/utils/validate_proposal.py:119 -#: proposals/utils/validate_proposal.py:128 +#: proposals/utils/validate_proposal.py:124 +#: proposals/utils/validate_proposal.py:133 msgid "Het interventieonderzoek (traject {})" msgstr "Intervention study (trajectory {})" -#: proposals/utils/validate_proposal.py:143 -#: proposals/utils/validate_proposal.py:152 +#: proposals/utils/validate_proposal.py:145 +#: proposals/utils/validate_proposal.py:154 msgid "Het observatieonderzoek (traject {})" msgstr "Observational study (trajectory {})" -#: proposals/utils/validate_proposal.py:163 +#: proposals/utils/validate_proposal.py:165 msgid "Het takenonderzoek (traject {})" msgstr "Task-based research: trajectory {}" -#: proposals/utils/validate_proposal.py:178 +#: proposals/utils/validate_proposal.py:180 msgid "Het takenonderzoek: sessie {} (traject {})" msgstr "Task-based research: session {} trajectory {}" -#: proposals/utils/validate_proposal.py:195 +#: proposals/utils/validate_proposal.py:197 msgid "Het takenonderzoek: sessie {} taak {} (traject {})" msgstr "Task-based research: session {} task {} (trajectory {})" -#: proposals/utils/validate_proposal.py:212 +#: proposals/utils/validate_proposal.py:214 msgid "Overzicht van takenonderzoek: sessie {} (traject {})" msgstr "Overview of task-based research: session {} (trajectory {})" -#: proposals/utils/validate_proposal.py:230 +#: proposals/utils/validate_proposal.py:231 msgid "AVG en Data Management" msgstr "AVG and Data Management" -#: proposals/validators.py:33 -msgid "" -"Je dient kennis genomen te hebben van de AVG om jouw aanvraag in te dienen" -msgstr "" -"You must confirm your understanding of the AVG before you can submit your " -"application." - -#: proposals/views/proposal_views.py:43 -#: proposals/views/proposal_views.py:43 +#: proposals/views/proposal_views.py:63 msgid "Publiek archief" msgstr "Public archive" -#: proposals/views/proposal_views.py:44 -#: proposals/views/proposal_views.py:44 +#: proposals/views/proposal_views.py:64 msgid "Dit overzicht toont alle goedgekeurde aanvragen." msgstr "This overview shows all approved applications." -#: proposals/views/proposal_views.py:63 -#: proposals/views/proposal_views.py:63 +#: proposals/views/proposal_views.py:83 msgid "Mijn aanvraag" msgstr "My application" -#: proposals/views/proposal_views.py:64 -#: proposals/views/proposal_views.py:64 +#: proposals/views/proposal_views.py:84 msgid "Dit overzicht toont al je aanvragen." msgstr "This overview shows all your applications." -#: proposals/views/proposal_views.py:77 -#: proposals/views/proposal_views.py:77 +#: proposals/views/proposal_views.py:99 msgid "Dit overzicht toont al je nog niet ingediende aanvragen." msgstr "This overview shows all the applications you have not yet submitted." -#: proposals/views/proposal_views.py:89 -#: proposals/views/proposal_views.py:89 +#: proposals/views/proposal_views.py:113 msgid "Dit overzicht toont al je ingediende aanvragen." msgstr "This overview shows all the applications you have submitted." -#: proposals/views/proposal_views.py:101 -#: proposals/views/proposal_views.py:101 +#: proposals/views/proposal_views.py:127 msgid "Dit overzicht toont al je beoordeelde aanvragen." msgstr "This overview shows all your applications that have been assessed." -#: proposals/views/proposal_views.py:114 -#: proposals/views/proposal_views.py:114 +#: proposals/views/proposal_views.py:142 msgid "" "Dit overzicht toont alle aanvragen waarvan je eindverantwoordelijke bent." msgstr "This overview shows all your supervised applications." -#: proposals/views/proposal_views.py:127 -#: proposals/views/proposal_views.py:127 +#: proposals/views/proposal_views.py:159 msgid "" "Dit overzicht toont alle oefenaanvragen waar je als student, onderzoeker of " "eindverantwoordelijke bij betrokken bent." @@ -3894,342 +3259,294 @@ msgstr "" "This overview shows all practice applications in which you are involved as a " "student, researcher or accountable researcher." -#: proposals/views/proposal_views.py:242 +#: proposals/views/proposal_views.py:279 msgid "Aanvraag verwijderd" msgstr "Application deleted" -#: proposals/views/proposal_views.py:380 +#: proposals/views/proposal_views.py:452 msgid "Wijzigingen opgeslagen" msgstr "Changes saved" -#: proposals/views/proposal_views.py:481 +#: proposals/views/proposal_views.py:556 msgid "Aanvraag gekopieerd" msgstr "Application copied" -#: proposals/views/study_views.py:61 +#: proposals/views/study_views.py:62 msgid "Consent opgeslagen" msgstr "Consent saved" -#: proposals/views/wmo_views.py:52 +#: proposals/views/wmo_views.py:56 msgid "WMO-gegevens opgeslagen" msgstr "WMO information saved" -#: proposals/views/wmo_views.py:65 +#: proposals/views/wmo_views.py:69 msgid "WMO-gegevens bewerkt" msgstr "WMO information edited" -#: proposals/views/wmo_views.py:148 +#: proposals/views/wmo_views.py:156 msgid "Je onderzoek hoeft niet te worden beoordeeld door de METC." msgstr "Your application does not require assessment by an METC." -#: proposals/views/wmo_views.py:155 +#: proposals/views/wmo_views.py:164 #, python-brace-format msgid "" "Neem contact op met {secretary} om de twijfels weg te " "nemen." msgstr "Contact {secretary} to make sure." -#: proposals/views/wmo_views.py:161 +#: proposals/views/wmo_views.py:171 msgid "Je onderzoek zal moeten worden beoordeeld door de METC." msgstr "Your application will require assessment by an METC." -#: reviews/api/views.py:31 reviews/api/views.py:320 +#: reviews/api/views.py:33 reviews/api/views.py:319 #: reviews/templates/reviews/vue_templates/decision_list.html:111 #: reviews/templates/reviews/vue_templates/decision_list_reviewer.html:61 #: reviews/templates/reviews/vue_templates/review_list.html:116 msgid "Stadium" msgstr "Stage" -#: reviews/api/views.py:35 reviews/api/views.py:324 reviews/models.py:45 +#: reviews/api/views.py:37 reviews/api/views.py:323 reviews/models.py:31 #: reviews/templates/reviews/vue_templates/decision_list.html:178 #: reviews/templates/reviews/vue_templates/decision_list_reviewer.html:121 -#: reviews/templates/reviews/vue_templates/review_list.html:177 +#: reviews/templates/reviews/vue_templates/review_list.html:183 msgid "Route" msgstr "Route" -#: reviews/api/views.py:53 reviews/api/views.py:284 reviews/api/views.py:346 +#: reviews/api/views.py:55 reviews/api/views.py:284 reviews/api/views.py:345 msgid "Start datum" msgstr "Start date review" -#: reviews/forms.py:14 reviews/models.py:142 -msgid "korte (2-weken) route" -msgstr "short (2-week) route" +#: reviews/forms.py:16 +msgid "korte route of revisie (2-weken)" +msgstr "short route or revision (2-weeks)" -#: reviews/forms.py:15 reviews/models.py:141 -msgid "lange (4-weken) route" -msgstr "long (4-week) route" +#: reviews/forms.py:17 +msgid "lange route (4-weken)" +msgstr "long route (4-weeks)" -#: reviews/forms.py:16 -msgid "direct naar revisie" -msgstr "straight to revision" +#: reviews/forms.py:18 +msgid "Direct terug naar aanvrager (Nog niet in behandeling)" +msgstr "Return directly to applicant (not yet under review)" + +#: reviews/forms.py:34 reviews/menus.py:67 reviews/mixins.py:173 +msgid "Algemene Kamer" +msgstr "General Chamber" + +#: reviews/forms.py:35 reviews/menus.py:77 reviews/mixins.py:176 +msgid "Linguïstiek Kamer" +msgstr "Linguistics Chamber" -#: reviews/forms.py:64 +#: reviews/forms.py:68 msgid "Selecteer de commissieleden" msgstr "Select committee members" -#: reviews/forms.py:73 +#: reviews/forms.py:78 msgid "Er moet tenminste één beoordelaar geselecteerd worden." msgstr "You must select at least one reviewer." -#: reviews/forms.py:107 +#: reviews/forms.py:119 msgid "Voeg deze aanvraag toe aan het archief" msgstr "Add this application to the archive" -#: reviews/forms.py:113 +#: reviews/forms.py:127 msgid "Opmerkingen over revisie" msgstr "Comments about this revision" -#: reviews/forms.py:120 +#: reviews/forms.py:133 msgid "Bevestig beëindiging" msgstr "Confirm termination of this review" -#: reviews/forms.py:153 +#: reviews/forms.py:167 msgid "Start datum periode:" msgstr "Start date period:" -#: reviews/forms.py:154 +#: reviews/forms.py:168 msgid "Eind datum periode:" msgstr "End date period:" -#: reviews/menus.py:37 reviews/views.py:241 +#: reviews/menus.py:19 reviews/views.py:73 +msgid "Mijn openstaande besluiten" +msgstr "My pending decisions" + +#: reviews/menus.py:23 +msgid "Al mijn besluiten" +msgstr "All my decisions" + +#: reviews/menus.py:27 +msgid "Alle openstaande besluiten commissieleden" +msgstr "All pending decisions committee members" + +#: reviews/menus.py:32 +msgid "Alle openstaande besluiten eindverantwoordelijken" +msgstr "All pending decisions supervisors" + +#: reviews/menus.py:37 reviews/views.py:230 +msgid "Nog af te handelen aanvragen" +msgstr "Applications waiting for conclusion" + +#: reviews/menus.py:42 reviews/views.py:242 msgid "Aanvragen in revisie" msgstr "Applications in revision" -#: reviews/menus.py:42 reviews/views.py:253 +#: reviews/menus.py:47 reviews/views.py:254 msgid "Alle lopende aanvragen" msgstr "All running applications" -#: reviews/menus.py:52 +#: reviews/menus.py:52 reviews/views.py:280 +msgid "Alle ingezonden aanvragen" +msgstr "All submitted applications" + +#: reviews/menus.py:57 msgid "Overzicht werkverdeling commissieleden" msgstr "Overview workload committee members" -#: reviews/models.py:17 +#: reviews/models.py:12 msgid "Beoordeling door eindverantwoordelijke" msgstr "Assessment by researcher with final responsibility" -#: reviews/models.py:18 +#: reviews/models.py:13 msgid "Aanstelling commissieleden" msgstr "Appointment of committee members" -#: reviews/models.py:19 +#: reviews/models.py:14 msgid "Beoordeling door commissie" msgstr "Assessment by committee" -#: reviews/models.py:20 +#: reviews/models.py:15 msgid "Afsluiting door secretaris" msgstr "Conclusion by secretary" -#: reviews/models.py:21 +#: reviews/models.py:16 msgid "Afgesloten" msgstr "Concluded" -#: reviews/models.py:33 +#: reviews/models.py:19 msgid "Goedkeuring door FETC-GW" msgstr "Approval by FEtC-H" -#: reviews/models.py:34 +#: reviews/models.py:20 msgid "Revisie noodzakelijk" msgstr "Revision necessary" -#: reviews/models.py:35 +#: reviews/models.py:21 msgid "Afwijzing door FETC-GW" msgstr "Rejection by FEtC-H" -#: reviews/models.py:36 +#: reviews/models.py:22 msgid "Open review met lange (4-weken) route" msgstr "Open review on long (4-week) route" -#: reviews/models.py:37 +#: reviews/models.py:23 msgid "Laat opnieuw beoordelen door METC" msgstr "Submit for reassessment by METC" -#: reviews/models.py:38 +#: reviews/models.py:24 msgid "Positief advies van FETC-GW, post-hoc" msgstr "Post hoc positive advice by FEtC-H" -#: reviews/models.py:39 +#: reviews/models.py:25 msgid "Negatief advies van FETC-GW, post-hoc" msgstr "Post hoc negative advice by FETC-H" -#: reviews/models.py:40 +#: reviews/models.py:26 msgid "Niet verder in behandeling genomen" msgstr "Not to be assessed further" -#: reviews/models.py:51 reviews/models.py:178 -#: reviews/models.py:51 reviews/models.py:178 +#: reviews/models.py:32 reviews/models.py:157 #: reviews/templates/reviews/review_table.html:9 msgid "Beslissing" msgstr "Decision" -#: reviews/models.py:126 -#: reviews/models.py:126 -msgid "Onbekend" -msgstr "Unknown" +#: reviews/models.py:123 +msgid "lange (4-weken) route" +msgstr "long (4-week) route" + +#: reviews/models.py:124 +msgid "korte (2-weken) route" +msgstr "short (2-week) route" -#: reviews/models.py:143 -#: reviews/models.py:143 +#: reviews/models.py:125 msgid "nog geen route" msgstr "no route assigned" -#: reviews/models.py:172 -#: reviews/models.py:172 +#: reviews/models.py:152 msgid "goedgekeurd" msgstr "endorsed" -#: reviews/models.py:173 -#: reviews/models.py:173 +#: reviews/models.py:153 msgid "niet goedgekeurd" msgstr "not endorsed" -#: reviews/models.py:174 -#: reviews/models.py:174 +#: reviews/models.py:154 msgid "revisie noodzakelijk" msgstr "revision necessary" -#: reviews/templates/reviews/action_explaination.html:22 -#, python-format -msgid "" -"\n" -" Klik op om een " -"ingediende aanvraag in te zien.\n" -" " -msgstr "" -"\n" -" Click to view a submitted " -"application.\n" -" " - -#: reviews/templates/reviews/action_explaination.html:27 -#, python-format -msgid "" -"\n" -" Klik op om de verschillen met de voorgaande\n" -" versie te zien (alleen beschikbaar voor revisies/" -"amendementen).\n" -" " -msgstr "" -"\n" -" Click to show " -"differences between a previous version (only available for revisions/" -"amendments).\n" -" " - -#: reviews/templates/reviews/action_explaination.html:33 +#: reviews/templates/reviews/action_explaination.html:36 #, python-format msgid "" -"\n" -" Klik op " -"om alle details en beoordelingen van\n" -" een ingediende aanvraag te zien.\n" -" " +"Klik op om alle details " +"en beoordelingen van een ingediende aanvraag te zien." msgstr "" -"\n" -" Click to view " -"details of a submitted application.\n" -" " +"Click to view details " +"of a submitted application." -#: reviews/templates/reviews/action_explaination.html:39 +#: reviews/templates/reviews/action_explaination.html:44 #, python-format msgid "" -"\n" -" Klik op om " -"je beslissing door te geven.\n" -" " +"Klik op om je beslissing " +"door te geven." msgstr "" -"\n" -" Click to make your " -"decision.\n" -" " +"Click to make your decision " +"(as a supervisor)." -#: reviews/templates/reviews/action_explaination.html:46 +#: reviews/templates/reviews/action_explaination.html:53 msgid "Uitleg secretaris" msgstr "Explanation for secretary" -#: reviews/templates/reviews/action_explaination.html:50 -#, python-format -msgid "" -"\n" -" Klik op " -"om een ingediende aanvraag te verbergen uit het\n" -" archief.\n" -" " -msgstr "" -"\n" -" Click to hide a submitted " -"application from the archive.\n" -" " - -#: reviews/templates/reviews/action_explaination.html:62 +#: reviews/templates/reviews/action_explaination.html:73 #, python-format msgid "" -"\n" -" Klik op om beoordelaars aan te stellen.\n" -" " +"Klik op om " +"beoordelaars aan te stellen." msgstr "" -"\n" -" Click to assign " -"reviewers.\n" -" " +"Click to assign " +"reviewers." -#: reviews/templates/reviews/action_explaination.html:67 +#: reviews/templates/reviews/action_explaination.html:80 #, python-format msgid "" -"\n" -" Klik op om een aanvraag\n" -" te verplaatsen naar een andere kamer.\n" -" " +"Klik op om een aanvraag te verplaatsen naar een andere kamer." msgstr "" -"\n" -" Click on to move an application \n" -" to a different chamber.\n" -" " +"Click on to move an application to a different chamber." -#: reviews/templates/reviews/action_explaination.html:73 +#: reviews/templates/reviews/action_explaination.html:88 #, python-format msgid "" -"\n" -" Klik op " -"om een aanvraag af te sluiten.\n" -" " +"Klik op om een aanvraag af " +"te sluiten." msgstr "" -"\n" -" Click on " -"to conclude an application.\n" -" " +"Click on to conclude an " +"application." -#: reviews/templates/reviews/action_explaination.html:78 +#: reviews/templates/reviews/action_explaination.html:95 #, python-format msgid "" -"\n" -" Klik op om aan te geven dat de\n" -" bevestigingsbrief is verstuurd.\n" -" " +"Klik op om aan te " +"geven dat de bevestigingsbrief is verstuurd." msgstr "" -"\n" -" Click on to note that the\n" -" confirmation letter has been sent.\n" -" " +"Click on to note " +"that the confirmation letter has been sent." -#: reviews/templates/reviews/action_explaination.html:84 +#: reviews/templates/reviews/action_explaination.html:103 #, python-format msgid "" -"\n" -" Klik op om de opgegeven datum\n" -" van de bevestigingsbrief te veranderen.\n" -" " +"Klik op om de " +"opgegeven datum van de bevestigingsbrief te veranderen." msgstr "" -"\n" -" Click on to change the date of \n" -" the confirmation letter.\n" -" " +"Click on to " +"change the date of the confirmation letter." #: reviews/templates/reviews/auto_review.html:3 msgid "Uitkomst automatische review" @@ -4253,13 +3570,13 @@ msgid "Redenen" msgstr "Reasons" #: reviews/templates/reviews/change_chamber_form.html:7 -#: reviews/templates/reviews/change_chamber_form.html:14 +#: reviews/templates/reviews/change_chamber_form.html:13 msgid "Beoordelende kamer wijzigen" msgstr "Change reviewing chamber" -#: reviews/templates/reviews/change_chamber_form.html:18 -#: reviews/templates/reviews/review_assign_form.html:48 -#: reviews/templates/reviews/review_discontinue_form.html:74 +#: reviews/templates/reviews/change_chamber_form.html:21 +#: reviews/templates/reviews/review_assign_form.html:49 +#: reviews/templates/reviews/review_discontinue_form.html:73 msgid "OK" msgstr "OK" @@ -4272,49 +3589,49 @@ msgstr "%(committee)s workload overview" msgid "Lopende reviews" msgstr "Ongoing reviews" -#: reviews/templates/reviews/committee_members_workload.html:23 -#: reviews/templates/reviews/committee_members_workload.html:78 +#: reviews/templates/reviews/committee_members_workload.html:22 +#: reviews/templates/reviews/committee_members_workload.html:70 #: reviews/templates/reviews/review_table.html:8 #: reviews/templates/reviews/vue_templates/decision_list_reviewer.html:68 msgid "Reviewer" msgstr "Reviewer" -#: reviews/templates/reviews/committee_members_workload.html:38 -#: reviews/templates/reviews/committee_members_workload.html:80 +#: reviews/templates/reviews/committee_members_workload.html:37 +#: reviews/templates/reviews/committee_members_workload.html:72 msgid "Korte route" msgstr "Short route" -#: reviews/templates/reviews/committee_members_workload.html:40 +#: reviews/templates/reviews/committee_members_workload.html:39 msgid "Lange route" msgstr "Long route" -#: reviews/templates/reviews/committee_members_workload.html:63 +#: reviews/templates/reviews/committee_members_workload.html:57 msgid "Werkverdeling overzicht van afgelopen periode" msgstr "Workload overview of past period" -#: reviews/templates/reviews/committee_members_workload.html:65 +#: reviews/templates/reviews/committee_members_workload.html:58 msgid "" "Vul hieronder een start- en einddatum in voor de periode van dit overzicht." msgstr "Select a start- and enddate for the period of the overview below." -#: reviews/templates/reviews/committee_members_workload.html:72 +#: reviews/templates/reviews/committee_members_workload.html:64 msgid "Periode toepassen" msgstr "Apply period" -#: reviews/templates/reviews/committee_members_workload.html:79 +#: reviews/templates/reviews/committee_members_workload.html:71 msgid "Totaal" msgstr "Total" -#: reviews/templates/reviews/committee_members_workload.html:81 +#: reviews/templates/reviews/committee_members_workload.html:73 msgid "Lange Route" msgstr "Long route" #: reviews/templates/reviews/decision_form.html:7 -#: reviews/templates/reviews/decision_form.html:17 +#: reviews/templates/reviews/decision_form.html:16 msgid "Aanvraag beoordelen" msgstr "Assess the application" -#: reviews/templates/reviews/decision_form.html:24 +#: reviews/templates/reviews/decision_form.html:21 #, python-format msgid "" "Je kunt nu een go of no-go geven voor de aanvraag %(title)s, " @@ -4322,16 +3639,15 @@ msgid "" "target=\"_blank\">hier in te zien (downloadt als PDF)." msgstr "" " You can now give a go or no-go for the application %(title)s, " -"%(refnum)s in %(chamber)s.\n" -" You can see the details of this application here (downloads as PDF)." +"%(refnum)s in %(chamber)s. You can see the details of this application here (downloads as PDF)." -#: reviews/templates/reviews/decision_form.html:32 +#: reviews/templates/reviews/decision_form.html:29 #, python-format -msgid "Je kunt nu de aanvraag %(title)s bekijken.
    " -msgstr "You can now (re)view this application here: %(title)s." +msgid "Je kunt nu de aanvraag %(title)s bekijken.
    " +msgstr "You can now (re)view this application here: %(title)s.
    " -#: reviews/templates/reviews/decision_form.html:37 +#: reviews/templates/reviews/decision_form.html:35 msgid "" "Als de aanvraag (incl. geïnformeerde toestemmingsformulieren) in orde is, " "klik dan op ‘goedgekeurd’ en ‘Beslissing opslaan’ hieronder; dan wordt de " @@ -4341,7 +3657,7 @@ msgstr "" "'endorsed' and 'Save decision' below; the application will then be submitted " "to the FEtC-H. " -#: reviews/templates/reviews/decision_form.html:44 +#: reviews/templates/reviews/decision_form.html:42 msgid "" "Als de aanvraag nog niet in orde is, dan zijn er twee mogelijkheden om de " "aanvraag aan te passen:" @@ -4349,10 +3665,10 @@ msgstr "" "If the application is not yet in order, there are two methods to amend the " "study: " -#: reviews/templates/reviews/decision_form.html:51 +#: reviews/templates/reviews/decision_form.html:49 #, python-format msgid "" -"door de supervisor (jijzelf)
    Als supervisor kan je deze aanvraag Als supervisor kan je deze aanvraag hier aanpassen. Daarna word je " "teruggeleid naar deze pagina en kun je hieronder de aanvraag goedkeuren; dat " "betekent dat de aanvraag wordt ingediend bij de FETC-GW." @@ -4362,20 +3678,20 @@ msgstr "" "which, you will be redirected back to this page and you can approve the " "application; this means that the application is submitted to the FEtC-H. " -#: reviews/templates/reviews/decision_form.html:59 +#: reviews/templates/reviews/decision_form.html:58 msgid "" -"door de indiener (je student of promovendus)
    Indien je wilt dat de " +"door de indiener (je student of promovendus)
    Indien je wilt dat de " "indiener de aanvraag zelf aanpast voordat je de studie kunt goedkeuren en " "daarmee bij de FETC-GW indient, selecteer dan 'revisie noodzakelijk' of " "‘niet goedgekeurd’ hieronder, voeg eventuele opmerkingen toe, en klik op " "'Beslissing opslaan'. Zodra je dit gedaan hebt kan de indiener weer " -"aanpassingen doen.
    " +"aanpassingen doen.
    " msgstr "" "by the submitter (your student or PhD candidate)
    If you want the " "submitter to amend the application before you approve it (and thereby submit " "it to the FEtC-H), select 'revision necessary' or 'not endorsed' below, add " "any comments, and click 'Save decision'. Once you have done this, the " -"submitter can make changes again.
    " +"submitter can make changes again.
    " #: reviews/templates/reviews/decision_form.html:70 msgid "" @@ -4388,225 +3704,176 @@ msgstr "" #: reviews/templates/reviews/decision_form.html:80 #, python-format msgid "" -"\n" -" Dit is een revisie van of amendement op een " -"vorige aanvraag. De verschillen met de vorige\n" -" aanvraag zijn hier " -"in te zien.\n" -" " +"Dit is een revisie van of amendement op een vorige aanvraag. De verschillen " +"met de vorige aanvraag zijn hier in te zien." msgstr "" -"\n" -" This is a revision or amendment of a previous application. You can check " -"the differences compared to the previous application here.\n" -" " +"This is a revision or amendment of a previous application. You can check the " +"differences compared to the previous application here." -#: reviews/templates/reviews/decision_form.html:93 +#: reviews/templates/reviews/decision_form.html:95 msgid "Beslissing opslaan" msgstr "Save decision" -#: reviews/templates/reviews/documents_list.html:36 -#: reviews/templates/reviews/documents_list.html:38 +#: reviews/templates/reviews/documents_list.html:26 +#: reviews/templates/reviews/documents_list.html:28 msgid "Data Management Plan wijzigen" msgstr "Edit Data Management Plan" -#: reviews/templates/reviews/documents_list.html:44 -#: reviews/templates/reviews/documents_list.html:46 +#: reviews/templates/reviews/documents_list.html:33 +#: reviews/templates/reviews/documents_list.html:35 msgid "Documenten wijzigen" msgstr "Edit documents" #: reviews/templates/reviews/review_assign_form.html:7 -#: reviews/templates/reviews/review_assign_form.html:32 +#: reviews/templates/reviews/review_assign_form.html:29 msgid "Commissieleden aanstellen" msgstr "Appoint committee members" -#: reviews/templates/reviews/review_assign_form.html:36 +#: reviews/templates/reviews/review_assign_form.html:31 #, python-format msgid "" "

    Kies hier de geschikte route en commissieleden voor de aanvraag " "%(title)s. klik hier voor een " -"overzicht van de werkverdeling van deze commissie. " +"overzicht van de werkverdeling van deze commissie.

    " msgstr "" "

    Choose the appropriate route and committee members for the application " "%(title)s here. Click here to see " -"an overview of the workload for each committee member. " +"an overview of the workload for each committee member.

    " #: reviews/templates/reviews/review_close_form.html:7 -#: reviews/templates/reviews/review_close_form.html:25 -#: reviews/templates/reviews/review_close_form.html:43 +#: reviews/templates/reviews/review_close_form.html:24 +#: reviews/templates/reviews/review_close_form.html:41 msgid "Review afsluiten" msgstr "Conclude review" -#: reviews/templates/reviews/review_close_form.html:28 +#: reviews/templates/reviews/review_close_form.html:26 #, python-format msgid "" -"\n" -" Sluit hier de beoordeling van de aanvraag %(title)s af. Hieronder volgen de individuele\n" -" beslissingen.\n" -" " +"Sluit hier de beoordeling van de aanvraag %(title)s af. Hieronder " +"volgen de individuele beslissingen." msgstr "" -"\n" -"\tConclude the review of application %(title)s here. The individual " -"decisions follow below.\n" -"\t" +"Conclude the review of application %(title)s here. The individual " +"decisions follow below." -#: reviews/templates/reviews/review_close_form.html:33 +#: reviews/templates/reviews/review_close_form.html:31 msgid "Individuele beslissingen" msgstr "Individual decisions" -#: reviews/templates/reviews/review_close_form.html:35 +#: reviews/templates/reviews/review_close_form.html:33 msgid "Uiteindelijk besluit" msgstr "Final decision" -#: reviews/templates/reviews/review_detail.html:11 +#: reviews/templates/reviews/review_closed.html:11 +#: reviews/templates/reviews/review_closed.html:20 +msgid "Aanvraag al beoordeeld" +msgstr "Application has already been reviewed" + +#: reviews/templates/reviews/review_closed.html:24 #, python-format msgid "" -"\n" -" Details van besluitvorming bij aanmelding %(proposal)s\n" -" " +"Je hebt deze aanvraag al beoordeeld. Controleer of dit inderdaad de aanvraag " +"is die je wilde beoordelen. Op deze " +"pagina vind je alle aanvragen waarvan je de eindverantwoordelijke bent." msgstr "" -"\n" -"Details on the review process of application %(proposal)s\n" -" " +"You have already reviewed this request. Please check if this is indeed the " +"application you wanted to review. On this " +"page, you can find all your supervised applications." -#: reviews/templates/reviews/review_detail.html:21 -#, python-format +#: reviews/templates/reviews/review_closed.html:29 msgid "" -"\n" -" Details van besluitvorming bij aanmelding " -"%(proposal)s\n" -" " +"Wil je je beoordeling veranderen? Neem dan contact op met de secretaris van de FETC." msgstr "" -"\n" -"Details on the review process of application %(proposal)s\n" -" " +"Do you want to change your decision? Please contact the secretary of the FEtC-H." + +#: reviews/templates/reviews/review_detail.html:11 +#, python-format +msgid "Details van besluitvorming bij aanmelding %(proposal)s" +msgstr "Details on the review process of application %(proposal)s" + +#: reviews/templates/reviews/review_detail.html:21 +#, python-format +msgid "Details van besluitvorming bij aanmelding %(proposal)s" +msgstr "Details on the review process of application %(proposal)s" -#: reviews/templates/reviews/review_detail.html:36 +#: reviews/templates/reviews/review_detail.html:33 msgid "Reviewers" msgstr "Reviewers" -#: reviews/templates/reviews/review_detail.html:39 +#: reviews/templates/reviews/review_detail.html:35 msgid "Handelingen" msgstr "Actions" -#: reviews/templates/reviews/review_detail.html:47 +#: reviews/templates/reviews/review_detail.html:40 msgid "Geen handelingen beschikbaar" msgstr "No actions available" -#: reviews/templates/reviews/review_detail_sidebar.html:22 +#: reviews/templates/reviews/review_detail_sidebar.html:18 msgid "Referentie" msgstr "Reference" -#: reviews/templates/reviews/review_detail_sidebar.html:25 +#: reviews/templates/reviews/review_detail_sidebar.html:19 msgid "Commissie" msgstr "Committee" -#: reviews/templates/reviews/review_detail_sidebar.html:30 +#: reviews/templates/reviews/review_detail_sidebar.html:23 #, python-format -msgid "%(r_or_a)s van
    %(parent)s" -msgstr "%(r_or_a)s of
    %(parent)s" +msgid "%(r_or_a)s van
    %(parent)s" +msgstr "%(r_or_a)s of
    %(parent)s" -#: reviews/templates/reviews/review_detail_sidebar.html:40 +#: reviews/templates/reviews/review_detail_sidebar.html:36 msgid "Aanvrager(s)" msgstr "Applicant" -#: reviews/templates/reviews/review_detail_sidebar.html:50 +#: reviews/templates/reviews/review_detail_sidebar.html:43 msgid "Supervisor" msgstr "" -#: reviews/templates/reviews/review_detail_sidebar.html:54 +#: reviews/templates/reviews/review_detail_sidebar.html:46 #, python-format -msgid "" -"\n" -" Reviewronde gestart op
    %(date_start)s.\n" -" " -msgstr "" -"\n" -" Reviewing round started on %(date_start)s.\n" -" " +msgid "Reviewronde gestart op
    %(date_start)s." +msgstr "Reviewing round started on
    %(date_start)s." -#: reviews/templates/reviews/review_detail_sidebar.html:60 +#: reviews/templates/reviews/review_detail_sidebar.html:54 #, python-format -msgid "" -"\n" -" Reviewronde beëindigd op
    %(date_end)s.\n" -" " -msgstr "" -"\n" -" Reviewing round ended on %(date_end)s.\n" -" " +msgid "Reviewronde beëindigd op
    %(date_end)s." +msgstr "Reviewing round ended on
    %(date_end)s." -#: reviews/templates/reviews/review_detail_sidebar.html:67 +#: reviews/templates/reviews/review_detail_sidebar.html:63 #, python-format -msgid "" -"\n" -" Afhandeling:
    %(continuation)s.\n" -" " -msgstr "" -"\n" -" Continuation: %(continuation)s.\n" -" " +msgid "Afhandeling:
    %(continuation)s." +msgstr "Continuation:
    %(continuation)s." -#: reviews/templates/reviews/review_detail_sidebar.html:73 +#: reviews/templates/reviews/review_detail_sidebar.html:71 #, python-format -msgid "" -"\n" -" Bevestiging verzonden op
    %(date_confirmed)s.\n" -" " -msgstr "" -"\n" -" Confirmation sent on %(date_confirmed)s.\n" -" " +msgid "Bevestiging verzonden op
    %(date_confirmed)s." +msgstr "Confirmation sent on
    %(date_confirmed)s." #: reviews/templates/reviews/review_detail_sidebar.html:77 #, python-format -msgid "" -"\n" -" Opmerkingen:
    %(comments)s.\n" -" " -msgstr "" -"\n" -" Comments: %(comments)s.\n" -" " +msgid "Opmerkingen:
    %(comments)s." +msgstr "Comments:
    %(comments)s." -#: reviews/templates/reviews/review_detail_sidebar.html:87 -msgid "" -"\n" -" Dit is een aanvraag voor voortoetsing.\n" -" " -msgstr "" -"\n" -" This is an application for preliminary assessment.\n" -" " +#: reviews/templates/reviews/review_detail_sidebar.html:89 +msgid "Dit is een aanvraag voor voortoetsing." +msgstr "This is an application for preliminary assessment" -#: reviews/templates/reviews/review_detail_sidebar.html:96 +#: reviews/templates/reviews/review_detail_sidebar.html:98 msgid "Dit is een beslissing van een eindverantwoordelijke" msgstr "This is a supervisor review" -#: reviews/templates/reviews/review_detail_sidebar.html:107 -msgid "" -"\n" -" Deze aanvraag heeft een revisie gehad tijdens het " -"beslisproces.\n" -" " +#: reviews/templates/reviews/review_detail_sidebar.html:108 +msgid "Deze aanvraag heeft een revisie gehad tijdens het beslisproces." msgstr "" -"\n" -" A revision was made to this application after it was submitted to " -"the FEtC-H .\n" -" " +"A revision was made to this application after it was submitted to the FEtC-H" -#: reviews/templates/reviews/review_detail_sidebar.html:111 -msgid "" -"\n" -" Er zijn de volgende opmerkingen bijgevoegd:
    \n" -" " -msgstr "" -"\n" -" The following comments have been provided:
    \n" -" " +#: reviews/templates/reviews/review_detail_sidebar.html:114 +msgid "Er zijn de volgende opmerkingen bijgevoegd:
    " +msgstr "The following comments have been provided:
    " -#: reviews/templates/reviews/review_detail_sidebar.html:119 +#: reviews/templates/reviews/review_detail_sidebar.html:122 msgid "Documenten" msgstr "Documents" @@ -4614,11 +3881,11 @@ msgstr "Documents" msgid "Beoordeling beëindigen" msgstr "Terminate review" -#: reviews/templates/reviews/review_discontinue_form.html:32 +#: reviews/templates/reviews/review_discontinue_form.html:29 msgid "Afhandeling definitief beëindigen" msgstr "Terminate this review" -#: reviews/templates/reviews/review_discontinue_form.html:36 +#: reviews/templates/reviews/review_discontinue_form.html:31 msgid "" "Als een aanvraag definitief niet meer door de FETC-GW afgehandeld gaat " "worden, en deze in de weg staat, kan er voor gekozen worden deze te " @@ -4627,7 +3894,7 @@ msgstr "" "If a proposal will not be further assessed by the FEtC-H and its open review " "is getting in the way, it can be terminated using this form." -#: reviews/templates/reviews/review_discontinue_form.html:43 +#: reviews/templates/reviews/review_discontinue_form.html:38 msgid "" "Een beëindigde aanvraag verschijnt niet meer in de pagina's van de " "secretaris en beoordelaars. Deze aanvraag kan ook niet meer gereviseerd " @@ -4639,11 +3906,11 @@ msgstr "" "however it may still be copied. A terminated application still shows up in " "the list \"all submitted applications\" for future reference." -#: reviews/templates/reviews/review_discontinue_form.html:54 +#: reviews/templates/reviews/review_discontinue_form.html:48 msgid "Attentie" msgstr "Warning" -#: reviews/templates/reviews/review_discontinue_form.html:56 +#: reviews/templates/reviews/review_discontinue_form.html:49 msgid "" "Deze aanvraag heeft op dit moment geen lopende beoordeling. Om deze aanvraag " "definitief te beëindigen, moeten we de uitkomst van laatste beoordeling (zie " @@ -4655,11 +3922,11 @@ msgstr "" "left sidebar. Please keep in mind that this can be confusing to the " "submitter." -#: reviews/templates/reviews/review_discontinue_form.html:64 +#: reviews/templates/reviews/review_discontinue_form.html:57 msgid "Aanvraag" msgstr "Application" -#: reviews/templates/reviews/review_discontinue_form.html:65 +#: reviews/templates/reviews/review_discontinue_form.html:58 #, python-format msgid "%(title)s door %(author)s" msgstr "%(title)s by %(author)s" @@ -4682,7 +3949,7 @@ msgid "Verplaats naar andere kamer" msgstr "Move study to different reviewing chamber" #: reviews/templates/reviews/vue_templates/review_list.html:95 -#: reviews/utils/review_actions.py:281 +#: reviews/utils/review_actions.py:264 msgid "Verberg aanvraag uit het archief" msgstr "Remove this application from the archive" @@ -4690,154 +3957,149 @@ msgstr "Remove this application from the archive" msgid "Plaats aanvraag in archief" msgstr "Add this application to the archive" -#: reviews/templatetags/documents_list.py:145 +#: reviews/templates/reviews/vue_templates/review_list.html:122 +msgid "Reviewronde beëindigd: " +msgstr "Reviewing round ended: " + +#: reviews/templatetags/documents_list.py:138 msgid "Hoofdtraject" msgstr "Main trajectory" -#: reviews/templatetags/documents_list.py:147 +#: reviews/templatetags/documents_list.py:140 msgid "Traject {}: {}" msgstr "Trajectory {}: {}" -#: reviews/templatetags/documents_list.py:158 +#: reviews/templatetags/documents_list.py:150 msgid "Extra documenten {}" msgstr "Extra documents {}" -#: reviews/templatetags/documents_list.py:213 +#: reviews/templatetags/documents_list.py:196 msgid "Aanmelding" msgstr "Application" -#: reviews/templatetags/documents_list.py:215 +#: reviews/templatetags/documents_list.py:198 msgid "Aanvraag in PDF-vorm" msgstr "Application in PDF format" -#: reviews/templatetags/documents_list.py:228 +#: reviews/templatetags/documents_list.py:210 msgid "Eerdere goedkeuring" msgstr "Prior approval" -#: reviews/templatetags/documents_list.py:236 +#: reviews/templatetags/documents_list.py:217 msgid "Aanvraag bij voortoetsing" msgstr "Application for preliminary assessment" -#: reviews/templatetags/documents_list.py:257 +#: reviews/templatetags/documents_list.py:240 msgid "Beslissing METC" msgstr "Decision by METC" -#: reviews/templatetags/documents_list.py:282 +#: reviews/templatetags/documents_list.py:262 msgid "Informed consent" msgstr "Informed consent" -#: reviews/templatetags/documents_list.py:283 +#: reviews/templatetags/documents_list.py:263 msgid "Informatiebrief" msgstr "Information letter" -#: reviews/templatetags/documents_list.py:284 +#: reviews/templatetags/documents_list.py:265 msgid "Consent declaratie directeur/departementshoofd" msgstr "Declaration of consent school director/head of the department" -#: reviews/templatetags/documents_list.py:286 +#: reviews/templatetags/documents_list.py:270 msgid "Informatiebrief directeur/departementshoofd" msgstr "Information letter school director/head of the department" -#: reviews/templatetags/documents_list.py:288 +#: reviews/templatetags/documents_list.py:274 msgid "Informatiebrief ouders" msgstr "Information letter for the parents" -#: reviews/templatetags/documents_list.py:296 +#: reviews/templatetags/documents_list.py:282 msgid "Toestemmingsdocument observatie" msgstr "Consent document for observation" -#: reviews/utils/review_actions.py:129 +#: reviews/utils/review_actions.py:118 msgid "Geef jouw beslissing en/of commentaar door" msgstr "Provide feedback on this proposal" -#: reviews/utils/review_actions.py:155 -msgid "Deze aanvraag afsluiten" -msgstr "Conclude this application" +#: reviews/utils/review_actions.py:141 +msgid "Deze versie afhandelen" +msgstr "Conclude this version" -#: reviews/utils/review_actions.py:185 +#: reviews/utils/review_actions.py:169 msgid "Beëindig definitief de afhandeling van deze aanvraag" msgstr "Discontinue assessment of this application" -#: reviews/utils/review_actions.py:215 +#: reviews/utils/review_actions.py:197 msgid "Verander aangestelde commissieleden" msgstr "Change appointment of committee members" -#: reviews/utils/review_actions.py:245 +#: reviews/utils/review_actions.py:229 msgid "Datum van bevestigingsbrief aanpassen" msgstr "Change date of confirmation letter" -#: reviews/utils/review_actions.py:283 +#: reviews/utils/review_actions.py:266 msgid "Plaats aanvraag in het archief." msgstr "Add this application to the archive" -#: reviews/utils/review_utils.py:54 -#: reviews/utils/review_utils.py:54 +#: reviews/utils/review_actions.py:283 +msgid "Startdatum wijzigen" +msgstr "Edit start date" + +#: reviews/utils/review_utils.py:65 msgid "FETC-GW {}: bevestiging indienen concept-aanmelding" msgstr "FEtC-H {}: confirmation of draft application submission" -#: reviews/utils/review_utils.py:74 -#: reviews/utils/review_utils.py:74 +#: reviews/utils/review_utils.py:108 msgid "FETC-GW {}: beoordelen als eindverantwoordelijke" msgstr "FEtC-H {}: assess as researcher with final responsibility" -#: reviews/utils/review_utils.py:124 -#: reviews/utils/review_utils.py:124 +#: reviews/utils/review_utils.py:168 msgid "FETC-GW {}: aanmelding ontvangen" msgstr "FEtC-H {}: application received" -#: reviews/utils/review_utils.py:218 -#: reviews/utils/review_utils.py:218 +#: reviews/utils/review_utils.py:293 msgid "FETC-GW {}: nieuwe aanvraag voor voortoetsing" msgstr "FEtC-H {}: new application for preliminary assessment" -#: reviews/utils/review_utils.py:232 -#: reviews/utils/review_utils.py:232 +#: reviews/utils/review_utils.py:314 msgid "FETC-GW {}: bevestiging indienen aanvraag voor voortoetsing" msgstr "" "FEtC-H {}: confirmation of submission of application for preliminary " "assessment" -#: reviews/utils/review_utils.py:281 -#: reviews/utils/review_utils.py:281 +#: reviews/utils/review_utils.py:370 msgid "FETC-GW {}: nieuwe aanvraag ingediend" msgstr "FEtC-H {}: new application submitted" -#: reviews/utils/review_utils.py:296 -#: reviews/utils/review_utils.py:296 +#: reviews/utils/review_utils.py:387 msgid "FETC-GW {}: nieuwe beoordeling toegevoegd" msgstr "FEtC-H {}: new decision added" -#: reviews/utils/review_utils.py:312 -#: reviews/utils/review_utils.py:312 +#: reviews/utils/review_utils.py:432 msgid "FETC-GW {}: eindverantwoordelijke heeft je aanvraag beoordeeld" msgstr "FEtC-H {}: a supervisor has reviewed your application" -#: reviews/utils/review_utils.py:338 -#: reviews/utils/review_utils.py:338 +#: reviews/utils/review_utils.py:459 msgid "De aanvraag bevat het gebruik van wilsonbekwame volwassenen." msgstr "" "The application contains the participation of adults incapable of informed " "consent." -#: reviews/utils/review_utils.py:341 -#: reviews/utils/review_utils.py:341 +#: reviews/utils/review_utils.py:463 msgid "De aanvraag bevat het gebruik van misleiding." msgstr "The application contains the use of misrepresentation." -#: reviews/utils/review_utils.py:344 -#: reviews/utils/review_utils.py:344 +#: reviews/utils/review_utils.py:468 msgid "" "Er bestaat een hiërarchische relatie tussen de onderzoeker(s) en deelnemer(s)" msgstr "" "A hierarchal relationship between researcher(s) and participant(s) exists." -#: reviews/utils/review_utils.py:347 -#: reviews/utils/review_utils.py:347 +#: reviews/utils/review_utils.py:473 msgid "Het onderzoek verzamelt bijzondere persoonsgegevens." msgstr "This study collects special or sensitive personal details." -#: reviews/utils/review_utils.py:350 -#: reviews/utils/review_utils.py:350 +#: reviews/utils/review_utils.py:478 msgid "" "Het onderzoek selecteert deelnemers op bijzondere kenmerken die wellicht " "verhoogde kwetsbaarheid met zich meebrengen." @@ -4845,8 +4107,7 @@ msgstr "" "The study selects participants based on particular characteristics which " "might entail increased vulnerability." -#: reviews/utils/review_utils.py:356 -#: reviews/utils/review_utils.py:356 +#: reviews/utils/review_utils.py:488 msgid "" "De onderzoeker geeft aan dat (of twijfelt erover of) het onderzoek op " "onderdelen of als geheel zodanig belastend is dat deze ondanks de verkregen " @@ -4856,8 +4117,7 @@ msgstr "" "study, in part or in its entirety, is so burdensome that despite acquiring " "informed consent it might raise questions." -#: reviews/utils/review_utils.py:360 -#: reviews/utils/review_utils.py:360 +#: reviews/utils/review_utils.py:496 msgid "" "De onderzoeker geeft aan dat (of twijfelt erover of) de risico's op " "psychische of fysieke schade bij deelname aan het onderzoek meer dan " @@ -4867,8 +4127,7 @@ msgstr "" "psychological or physical harm in participating in the study are more than " "minimal." -#: reviews/utils/review_utils.py:367 -#: reviews/utils/review_utils.py:367 +#: reviews/utils/review_utils.py:507 #, python-brace-format msgid "" "De totale duur van de taken in sessie {s}, exclusief pauzes en andere niet-" @@ -4879,16 +4138,14 @@ msgstr "" "non-task elements ({d} minutes) is greater than the task duration limit " "({max_d} minutes) for the age group {ag}." -#: reviews/utils/review_utils.py:384 -#: reviews/utils/review_utils.py:384 +#: reviews/utils/review_utils.py:533 #, python-brace-format msgid "Het onderzoek observeert deelnemers in de volgende setting: {s}" msgstr "" "The application contains sessions with participants in the following " "setting: {s}" -#: reviews/utils/review_utils.py:388 -#: reviews/utils/review_utils.py:388 +#: reviews/utils/review_utils.py:541 msgid "" "Het onderzoek observeert deelnemers in een niet-publieke ruimte en werkt met " "informed consent achteraf." @@ -4896,8 +4153,7 @@ msgstr "" "The study observes participants in a non-public space and works with " "retrospective informed consent." -#: reviews/utils/review_utils.py:390 -#: reviews/utils/review_utils.py:390 +#: reviews/utils/review_utils.py:547 msgid "" "De onderzoeker begeeft zich \"under cover\" in een beheerde niet-publieke " "ruimte (bijv. een digitale gespreksgroep), en neemt actief aan de discussie " @@ -4907,79 +4163,81 @@ msgstr "" "(e.g. a digital discussion group), and takes part actively in the discussion " "and/or collects data which can be traced back to individuals." -#: reviews/utils/review_utils.py:395 -#: reviews/utils/review_utils.py:395 +#: reviews/utils/review_utils.py:554 msgid "De aanvraag bevat het gebruik van {}" msgstr "The application makes use of {}" -#: reviews/utils/review_utils.py:416 -#: reviews/utils/review_utils.py:416 +#: reviews/utils/review_utils.py:580 msgid "" "De aanvraag bevat psychofysiologische metingen bij kinderen onder de {} jaar." msgstr "" "The application contains psychophysiological measurements on children under " "{} year(s) old." -#: reviews/views.py:60 +#: reviews/views.py:63 msgid "Mijn besluiten" msgstr "My results" -#: reviews/views.py:82 +#: reviews/views.py:85 msgid "Openstaande besluiten commissieleden" msgstr "Pending decisions committee members" -#: reviews/views.py:200 +#: reviews/views.py:203 msgid "Openstaande besluiten eindverantwoordelijken" msgstr "Pending decisions supervisors" -#: studies/forms.py:41 +#: reviews/views.py:600 +msgid "" +"Deze aanvraag is al beoordeeld, dus je kan je beoordeling niet meer " +"toevoegen/aanpassen" +msgstr "" +"This application has already been assessed, so you cannot add/change your " +"assessment" + +#: studies/forms.py:50 msgid "" "Maakt jouw onderzoek gebruik van wilsonbekwame (volwassen) deelnemers?" msgstr "" "Does your research make use of (adult) participants incapable of " "informed consent?" -#: studies/forms.py:83 +#: studies/forms.py:98 msgid "Je dient minimaal een bijzonder kenmerk te selecteren." msgstr "You are required to select at least one special characteristic." -#: studies/forms.py:85 +#: studies/forms.py:105 msgid "Je dient minimaal één type gegevens te selecteren." msgstr "You are required to select at least one characteristic." -#: studies/forms.py:92 +#: studies/forms.py:121 msgid "Leg uit wat de hiërarchische relatie is." msgstr "Explain the nature of this hierarchal relationship." -#: studies/forms.py:122 +#: studies/forms.py:158 msgid "Je dient minstens één van de opties te selecteren" msgstr "You must select at least one of the options" -#: studies/models.py:54 +#: studies/models.py:53 msgid "{}-{} jaar" msgstr "{}-{} years old" -#: studies/models.py:56 +#: studies/models.py:55 msgid "{} jaar en ouder" msgstr "{} years old and above" -#: studies/models.py:128 studies/templates/studies/study_form.html:26 +#: studies/models.py:131 studies/templates/studies/study_form.html:26 msgid "Werving" msgstr "Recruitment" -#: studies/models.py:145 studies/models.py:268 -msgid "Taakonderzoek en interviews" -msgstr "Task-based research and interviews" - -#: studies/models.py:150 +#: studies/models.py:144 msgid "Naam traject" msgstr "Trajectory title" -#: studies/models.py:157 +#: studies/models.py:148 msgid "Uit welke leeftijdscategorie(ën) bestaat je deelnemersgroep?" msgstr "What is/are the age category/ies of your participants?" -#: studies/models.py:158 +#: studies/models.py:150 msgid "" "De beoogde leeftijdsgroep kan zijn 5-7 jarigen. Dan moet je hier hier 4-5 én " "6-11 invullen." @@ -4987,14 +4245,14 @@ msgstr "" "If the intended age group is 5-7 year-olds, for example, then you should " "fill in 4-5 and 6-11." -#: studies/models.py:161 +#: studies/models.py:156 msgid "" "Maakt je onderzoek gebruik van wilsonbekwame (volwassen) deelnemers?" msgstr "" "Does your application contain the use of (adult) participants incapable of informed consent?" -#: studies/models.py:163 +#: studies/models.py:160 msgid "" "Wilsonbekwame volwassenen zijn volwassenen waarvan redelijkerwijs mag worden " "aangenomen dat ze onvoldoende kunnen inschatten wat hun eventuele deelname " @@ -5010,11 +4268,11 @@ msgstr "" "express their own opinion). Here informed consent should always be obtained " "from a relevant representative." -#: studies/models.py:176 +#: studies/models.py:173 msgid "Worden er bijzondere persoonsgegevens verzameld?" msgstr "Will you collect any special or sensitive personal details?" -#: studies/models.py:177 +#: studies/models.py:175 msgid "" "zie de Richtlijnen" @@ -5023,12 +4281,12 @@ msgstr "" "nl/en/knowledgebase/documents-ethics-assessment-committee-" "humanities\">regulations." -#: studies/models.py:186 +#: studies/models.py:185 msgid "Geef aan welke bijzondere persoonsgegevens worden verzameld:" msgstr "" "Please select which kinds of special personal details may be collected:" -#: studies/models.py:191 +#: studies/models.py:190 msgid "" "Deelnemers kunnen geïncludeerd worden op bepaalde bijzondere kenmerken. Is " "dit in jouw onderzoek bij (een deel van) de deelnemers het geval?" @@ -5036,7 +4294,7 @@ msgstr "" "Participants can be included based on particular characteristics. Is this " "the case with (some of) the participants in this application?" -#: studies/models.py:193 +#: studies/models.py:194 msgid "" "In de meeste gevallen kun je dit soort gegevens alleen verzamelen als je " "daar toestemming voor hebt: zie de privacy officer before submitting your " "application." -#: studies/models.py:206 +#: studies/models.py:208 msgid "" "Selecteer de medische gegevens van je proefpersonen die worden verzameld" msgstr "Select the medical details of your participants that are recorded" -#: studies/models.py:212 +#: studies/models.py:214 msgid "" "Is het, om de onderzoeksvraag beantwoord te krijgen, noodzakelijk om het " "geselecteerde type deelnemer aan het onderzoek te laten meedoen?" @@ -5069,7 +4327,7 @@ msgstr "" "In order to answer the research question, is it necessary for the selected " "type of participants to participate in the study?" -#: studies/models.py:215 +#: studies/models.py:219 msgid "" "Is het bijvoorbeeld noodzakelijk om kinderen te testen, of zou je de vraag " "ook kunnen beantwoorden door volwassen deelnemers te testen?" @@ -5077,15 +4335,15 @@ msgstr "" "For example, is it necessary to test children, or would it be possible to " "answer the research question by testing adults?" -#: studies/models.py:222 +#: studies/models.py:227 msgid "Leg uit waarom" msgstr "Explain why" -#: studies/models.py:226 +#: studies/models.py:229 msgid "Hoe worden de deelnemers geworven?" msgstr "How will the participants be recruited?" -#: studies/models.py:229 +#: studies/models.py:234 #, python-brace-format msgid "" "Er zijn specifieke voorbeelddocumenten voor het gebruik van " @@ -5094,12 +4352,12 @@ msgstr "" "There are specific template documents for using Amazon Mechanical Turk/" "Prolific here." -#: studies/models.py:236 +#: studies/models.py:243 msgid "Welke vergoeding krijgt de deelnemer voor hun deelname?" msgstr "" "What compensation will participants receive for taking part in this study?" -#: studies/models.py:237 +#: studies/models.py:245 msgid "" "Het standaardbedrag voor vergoeding aan de deelnemers is €10,- per uur. " "Minderjarigen mogen geen geld ontvangen, maar wel een cadeautje." @@ -5107,22 +4365,26 @@ msgstr "" "The standard sum for compensation of participants is €10 per hour. Minors " "are not permitted to receive money, but can be given a gift." -#: studies/models.py:249 +#: studies/models.py:257 msgid "" "Bestaat een hiërarchische relatie tussen onderzoeker(s) en deelnemer(s)?" msgstr "" "Does a hierarchal relationship between researcher(s) and participant(s) " "exist?" -#: studies/models.py:255 +#: studies/models.py:264 msgid "Zo ja, wat is de relatie (bijv. docent-student)?" msgstr "If so, what is the nature of the relationship (e.g. teacher-student)?" -#: studies/models.py:273 +#: studies/models.py:272 +msgid "Taakonderzoek en interviews" +msgstr "Task-based research and interviews" + +#: studies/models.py:276 msgid "Hoeveel sessies met taakonderzoek zullen de deelnemers doorlopen?" msgstr "How many sessions of tasks will the participants take part in?" -#: studies/models.py:276 +#: studies/models.py:283 msgid "" "Wanneer je bijvoorbeeld eerst de deelnemer een taak/aantal taken laat doen " "tijdens een eerste bezoek aan het lab en je laat de deelnemer nog een keer " @@ -5136,7 +4398,7 @@ msgstr "" "experiment to consist of two sessions. If multiple tasks are executed on the " "same day, with breaks in between, this is still considered to be one session." -#: studies/models.py:283 +#: studies/models.py:293 msgid "" "Is er binnen bovenstaand onderzoekstraject sprake van misleiding van de " "deelnemer?" @@ -5144,7 +4406,7 @@ msgstr "" "Does the above research trajectory involve misrepresentation to the " "participant?" -#: studies/models.py:285 +#: studies/models.py:297 msgid "" "Misleiding is het doelbewust verschaffen van inaccurate informatie over het " "doel en/of belangrijke aspecten van de gang van zaken tijdens het onderzoek. " @@ -5161,7 +4423,7 @@ msgstr "" "crucial memory task without announcing it, or giving false feedback. Fillers " "do not count as misrepresentation." -#: studies/models.py:296 +#: studies/models.py:311 msgid "" "Geef een toelichting en beschrijf hoe en wanneer de deelnemer zal worden " "gedebrieft." @@ -5169,7 +4431,7 @@ msgstr "" "Give an explanation and describe how and when the participant will be " "debriefed." -#: studies/models.py:300 +#: studies/models.py:318 msgid "" "Bevat bovenstaand onderzoekstraject elementen die tijdens de " "deelname niet-triviale negatieve emoties kunnen opwekken? Denk hierbij " @@ -5182,11 +4444,11 @@ msgstr "" "consider emotionally probing questions, insulting utterances, negative " "feedback, and frustrating, difficult, (very) long and/or (very) boring tasks." -#: studies/models.py:309 +#: studies/models.py:328 msgid "Licht je antwoord toe." msgstr "Explain your answer." -#: studies/models.py:312 +#: studies/models.py:331 msgid "" "Bevat bovenstaand onderzoekstraject elementen die tijdens de deelname " "zodanig belastend zijn dat deze ondanks de verkregen informed consentmeer " @@ -5241,7 +4503,7 @@ msgstr "" "em> minimal? I.e. is the chance of and/or magnitude of potential damage to " "participants clearly above that of the \"background risk\"?" -#: studies/models.py:340 +#: studies/models.py:372 msgid "" "Achtergrondrisico is datgene dat gezonde, gemiddelde burgers in de relevante " "leeftijdscategorie normaalgesproken in het dagelijks leven ten deel valt. " @@ -5268,16 +4530,16 @@ msgstr "" "evaluation, intelligence test, or heart rate measurement after physical " "exercise, all of which performed under professional supervision." -#: studies/models.py:445 +#: studies/models.py:479 #, python-format msgid "Study details for proposal %s" msgstr "Study details for proposal %s" -#: studies/models.py:450 +#: studies/models.py:484 msgid "Maak je gebruik van passieve informed consent?" msgstr "Will you use passive informed consent?" -#: studies/models.py:451 +#: studies/models.py:487 msgid "" "Wanneer je kinderen via een instelling (dus ook school) werft en je de " "ouders niet laat ondertekenen, maar in plaats daarvan de leiding van die " @@ -5293,7 +4555,7 @@ msgstr "" "a>." # studies/models.py:229 -#: studies/models.py:461 +#: studies/models.py:500 msgid "" "Licht je antwoord toe. Wij willen je wijzen op het reglement, sectie 3.1 'd' " "en 'e'. Passive consent is slechts in enkele gevallen toegestaan en draagt " @@ -5303,16 +4565,16 @@ msgstr "" "'d' and 'e'. Passive consent is allowed under certain situations but is not " "preferred by the committee." -#: studies/models.py:477 +#: studies/models.py:517 msgid "Upload hier de toestemmingsverklaring (in .pdf of .doc(x)-formaat)" msgstr "" "Please upload the declaration of consent here (in .pdf or .doc(x)-format)" -#: studies/models.py:485 +#: studies/models.py:525 msgid "Upload hier de informatiebrief (in .pdf of .doc(x)-formaat)" msgstr "Please upload the information letter here (in .pdf or .doc(x)-format)" -#: studies/models.py:494 +#: studies/models.py:534 msgid "" "Upload hier de toestemmingsverklaring voor de leiding of het management van " "de instelling (in .pdf of .doc(x)-format)" @@ -5320,7 +4582,7 @@ msgstr "" "Please upload the declaration of consent for the management of the school or " "institution (in .pdf or .doc(x)-format)" -#: studies/models.py:497 +#: studies/models.py:539 msgid "" "Upload indien mogelijk een ondertekende versie van het document. Upload als " "deze nog niet bestaat een blanco versie, en stuur de ondertekende versie " @@ -5331,7 +4593,7 @@ msgstr "" "and follow up by sending a signed copy to the secretary of the FEtC-H once " "available." -#: studies/models.py:504 +#: studies/models.py:547 msgid "" "Upload hier de informatiebrief voor de leiding of het management van de " "instelling (in .pdf of .doc(x)-formaat)" @@ -5339,7 +4601,7 @@ msgstr "" "Please upload the the information letter for the management of the school or " "institution (in .pdf or .doc(x)-format)" -#: studies/models.py:513 +#: studies/models.py:557 msgid "" "Upload hier de informatiebrief voor de ouders of verzorgers (in .pdf of ." "doc(x)-formaat)" @@ -5347,66 +4609,52 @@ msgstr "" "Please upload the the information letter for parents or guardians here (in ." "pdf or .doc(x)-format)" -#: studies/templates/studies/session_start.html:21 +#: studies/templates/studies/session_start.html:19 msgid "" -"\n" -" In de volgende vragen gaan we nader in op wat je in jouw " -"onderzoek van je deelnemers zal verlangen. Daarbij gelden de volgende " -"definities:\n" -" " +"In de volgende vragen gaan we nader in op wat je in jouw onderzoek van je " +"deelnemers zal verlangen. Daarbij gelden de volgende definities:" msgstr "" -"\n" -" The following questions probe further into the demands of your task-" -"based study on your participants. The following definitions will apply:\n" -" " +"The following questions probe further into the demands of your task-based " +"study on your participants. The following definitions will apply:" -#: studies/templates/studies/session_start.html:26 +#: studies/templates/studies/session_start.html:24 msgid "" -"\n" -" Sessie: Het geheel van de voor je onderzoek " -"benodigde betrokkenheid die je op één dag van een deelnemer vraagt. Bij een " +"Sessie: Het geheel van de voor je onderzoek benodigde " +"betrokkenheid die je op één dag van een deelnemer vraagt. Bij een " "labonderzoek is dat bijvoorbeeld alles wat er van onderzoekswege gebeurt " "vanaf het moment dat je de deelnemer ontvangt tot het moment dat je afscheid " "neemt, inclusief de benodigde pauzes. En bij een internet-vragenlijst is dat " "alles wat er van onderzoekswege gebeurt vanaf het welkomstscherm tot de " "afronding van de (reeks) vragenlijst(en), wederom inclusief benodigde " "pauzes. Bij veldwerk is dat de tijd dat je met de deelnemer in interactie " -"bent op één dag.\n" -" " -msgstr "" -"\n" -" Session: The entirety of the commitment which you " -"require of a participant in one day. In lab-based research, for example, " -"that means everything which happens as part of the research from the moment " -"you welcome the participant to the moment you part company from them, " -"including any necessary breaks. In an internet survey this means everything " -"which happens as part of the research from the welcome screen to the " -"conclusion of the (series of) survey(s), again including any necessary " -"breaks. For fieldwork, it refers to the time that you interact with the " -"participant on one day.\n" -" " - -#: studies/templates/studies/session_start.html:31 -msgid "" -"\n" -" Taak: Een coherente verzameling handelingen " -"die je via een gesproken of geschreven taak-instructie aan de deelnemer " -"oplegt, en ook als zodanig als 'taak' in een artikel zou beschrijven " -"(bijvoorbeeld: \"Beluister de volgende 200 zinnetjes en druk op een knop als " -"je een fout ontdekt\", \"Vul persoonlijkheidsvragenlijst X in\", \"Speel 10 " -"minuten met je kind zoals je dat thuis doet\", “houd 1 week een dagboek bij " -"van jouw media-gebruik”, “wil je je gender identiteit beschrijven”, “maak " -"foto’s van plekken in jouw leefomgeving die je bedreigend en inspirerend " -"vindt”, “zoek en deel met ons 10 foto’s uit jouw prive-archief om je " -"levensverhaal te kunnen vertellen”). Indien de specifieke opdracht aan de " -"deelnemer per item varieert (bijvoorbeeld: \"bij een Nederlandse zin " -"beoordeel je de betekenis, bij een Engelse zin de grammatica\"), beschouw " -"dit dan gewoon als één taak.\n" -" " -msgstr "" -"\n" -" Task: This refers to a coherent collection of actions " -"which you instruct the participant to perform via a spoken or written set of " +"bent op één dag." +msgstr "" +"Session: The entirety of the commitment which you require " +"of a participant in one day. In lab-based research, for example, that means " +"everything which happens as part of the research from the moment you welcome " +"the participant to the moment you part company from them, including any " +"necessary breaks. In an internet survey this means everything which happens " +"as part of the research from the welcome screen to the conclusion of the " +"(series of) survey(s), again including any necessary breaks. For fieldwork, " +"it refers to the time that you interact with the participant on one day." + +#: studies/templates/studies/session_start.html:29 +msgid "" +"Taak: Een coherente verzameling handelingen die je via een " +"gesproken of geschreven taak-instructie aan de deelnemer oplegt, en ook als " +"zodanig als 'taak' in een artikel zou beschrijven (bijvoorbeeld: \"Beluister " +"de volgende 200 zinnetjes en druk op een knop als je een fout ontdekt\", " +"\"Vul persoonlijkheidsvragenlijst X in\", \"Speel 10 minuten met je kind " +"zoals je dat thuis doet\", “houd 1 week een dagboek bij van jouw media-" +"gebruik”, “wil je je gender identiteit beschrijven”, “maak foto’s van " +"plekken in jouw leefomgeving die je bedreigend en inspirerend vindt”, “zoek " +"en deel met ons 10 foto’s uit jouw prive-archief om je levensverhaal te " +"kunnen vertellen”). Indien de specifieke opdracht aan de deelnemer per item " +"varieert (bijvoorbeeld: \"bij een Nederlandse zin beoordeel je de betekenis, " +"bij een Engelse zin de grammatica\"), beschouw dit dan gewoon als één taak." +msgstr "" +"Task: This refers to a coherent collection of actions which " +"you instruct the participant to perform via a spoken or written set of " "instructions, and which would also be described as a 'task' in an article (e." "g. \"Listen to the following 200 sentences and press a button when you hear " "a mistake\", \"Fill in personality questionnaire X\", \"Play with your child " @@ -5422,102 +4670,62 @@ msgstr "" "For each session we will ask the same questions in the following pages." #: studies/templates/studies/study_design.html:7 -#: studies/templates/studies/study_design.html:17 +#: studies/templates/studies/study_design.html:16 msgid "De onderzoekstype(n)" msgstr "Type(s) of research" -#: studies/templates/studies/study_design.html:21 +#: studies/templates/studies/study_design.html:19 msgid "" -"\n" -" De FETC-GW onderscheidt 3 typen onderzoek (die evt. ook " -"samen in één aanvraag voor kunnen komen):\n" -" " +"De FETC-GW onderscheidt 3 typen onderzoek (die evt. ook samen in één " +"aanvraag voor kunnen komen):" msgstr "" -"\n" -" The FEtC-H distinguishes 3 types of research (which may all be used " -"within one application):\n" -" " +"The FEtC-H distinguishes 3 types of research (which may all be used within " +"one application):" -#: studies/templates/studies/study_design.html:28 +#: studies/templates/studies/study_design.html:26 msgid "" -"\n" -" Interventieonderzoek:
    \n" -" De onderzoeker manipuleert d.m.v. een " -"interventie de context waarin de deelnemers in hun normale leven " -"doen wat ze normaliter ook doen.
    \n" -" De effecten kunnen gelijktijdig en/of achteraf " -"worden geobserveerd.\n" -" " +"Interventieonderzoek:
    De onderzoeker manipuleert d.m." +"v. een interventie de context waarin de deelnemers in hun normale " +"leven doen wat ze normaliter ook doen.
    De effecten kunnen " +"gelijktijdig en/of achteraf worden geobserveerd." msgstr "" -"\n" -" Interventional research:
    \n" -" The researcher uses an intervention to " -"manipulate the context in which participants do what they would otherwise " -"also do in their daily lives.
    Effects may be measured immediately or " -"after the fact.\n" -" " +"Interventional research:
    The researcher uses an " +"intervention to manipulate the context in which participants do " +"what they would otherwise also do in their daily lives.
    Effects may be " +"measured immediately or after the fact." #: studies/templates/studies/study_design.html:37 msgid "" -"\n" -" Observatieonderzoek:
    \n" -" De onderzoeker observeert deelnemers in hun " -"normale leven, maar grijpt hier niet op in.\n" -" " +"Observatieonderzoek:
    De onderzoeker observeert " +"deelnemers in hun normale leven, maar grijpt hier niet op in." msgstr "" -"\n" -" Observational research:
    \n" -"The researcher observes participants in their daily lives, but does not " -"interfere.\n" -" " +"Observational research:
    The researcher observes " +"participants in their daily lives, but does not interfere." -#: studies/templates/studies/study_design.html:45 +#: studies/templates/studies/study_design.html:46 msgid "" -"\n" -" Taakonderzoek en Interviews:\n" -" De onderzoeker\n" -"
      \n" -"
    • legt deelnemers een taak op (bijv. " -"vragenlijst, experiment) of
    • \n" -"
    • neemt een interview af, of
    • \n" -"
    • vraagt deelnemer deel te nemen aan een " -"focusgroep.
    • \n" -"

    \n" -" Onderzoek in het ILS-lab is vanwege de locatie " -"per definitie altijd taakonderzoek (óók als de deelnemers na ontvangst " -"alleen maar worden geobserveerd).\n" -" " +"Taakonderzoek en Interviews:
    De onderzoeker
      " +"
    • legt deelnemers een taak op (bijv. vragenlijst, experiment) of
    • " +"
    • neemt een interview af, of
    • vraagt deelnemer deel te nemen aan " +"een focusgroep.

    Onderzoek in het ILS-lab is vanwege de " +"locatie per definitie altijd taakonderzoek (óók als de deelnemers na " +"ontvangst alleen maar worden geobserveerd)." msgstr "" -"\n" -" Task-based research and interviews:
    \n" -" The researcher\n" -"
      \n" -"
    • gives participants a task to fulfil " -"(such as a questionnaire or experiment), or
    • \n" -"
    • interviews participants, or
    • \n" -"
    • asks participants to partake in a focus " -"group.
    • \n" -"

    \n" -" Research that takes place at the ILS-labs is " -"always categorized as task-based research due to the location (even if " -"participants are only observed after their arrival).\n" -" " - -#: studies/templates/studies/study_design.html:63 +"Task-based research and interviews:
    The researcher
      " +"
    • gives participants a task to fulfil (such as a questionnaire or " +"experiment), or
    • interviews participants, or
    • asks " +"participants to partake in a focus group.

    Research that " +"takes place at the ILS-labs is always categorized as task-based research " +"due to the location (even if participants are only observed after their " +"arrival)." + +#: studies/templates/studies/study_design.html:67 msgid "" -"\n" -" Om welk type onderzoek gaat het hier?\n" -" Je kan meerdere opties aankruisen.\n" -" " +"Om welk type onderzoek gaat het hier? Je kan meerdere opties aankruisen." msgstr "" -"\n" -" What type of research will be used here?\n" -" You can select multiple options.\n" -" " +"What type of research will be used here? You can select multiple options." -#: studies/templates/studies/study_design.html:79 +#: studies/templates/studies/study_design.html:83 msgid "" "Dit is bijvoorbeeld het geval wanneer je een observatiedeel combineert met " "een taakonderzoeksdeel, of met een interventiedeel (in dezelfde sessie, of " @@ -5534,167 +4742,121 @@ msgstr "" "otherwise would not be carried out) you should specify this separately as " "task-based research." -#: studies/templates/studies/study_design.html:95 +#: studies/templates/studies/study_design.html:99 msgid "" -"\n" -" Voor elk door jou aangekruiste type onderzoek kan je " -"op de hiernavolgende pagina's\n" -" de relevante informatie verschaffen.\n" -" " +"Voor elk door jou aangekruiste type onderzoek kan je op de hiernavolgende " +"pagina's de relevante informatie verschaffen." msgstr "" -"\n" -" For each type of research selected you can supply the relevant " -"information\n" -" on the following pages.\n" -" " +"For each type of research selected you can supply the relevant information " +"on the following pages." -#: studies/templates/studies/study_end.html:32 +#: studies/templates/studies/study_end.html:30 #, python-format -msgid "" -"\n" -" Deelnemers uit de leeftijdscategorieën " -"%(age_groups)s\n" -" " -msgstr "" -"\n" -" Participants from the age categories %(age_groups)s\n" -" " +msgid "Deelnemers uit de leeftijdscategorieën %(age_groups)s" +msgstr "Participants from the age categories %(age_groups)s" -#: studies/templates/studies/study_end.html:36 +#: studies/templates/studies/study_end.html:34 #, python-format -msgid "" -"\n" -" en met de bijzondere kenmerken %(traits)s\n" -" " -msgstr "" -"\n" -" and with the following special characteristics %(traits)s\n" -" " +msgid "en met de bijzondere kenmerken %(traits)s" +msgstr "and with the following special characteristics %(traits)s" -#: studies/templates/studies/study_end.html:40 -msgid "" -"\n" -" zonder bijzondere kenmerken\n" -" " -msgstr "" -"\n" -" without any special characteristics\n" -" " +#: studies/templates/studies/study_end.html:38 +msgid "zonder bijzondere kenmerken" +msgstr "without any special characteristics" -#: studies/templates/studies/study_end.html:45 -msgid "" -"\n" -" en zijnde wilsonbekwaam\n" -" " -msgstr "" -"\n" -" who are also incapable of giving informed consent\n" -" " +#: studies/templates/studies/study_end.html:43 +msgid "en zijnde wilsonbekwaam" +msgstr "who are also incapable of giving informed consent" -#: studies/templates/studies/study_end.html:49 -msgid "" -"\n" -" zullen aan de volgende onderdelen meedoen:\n" -" " -msgstr "" -"\n" -" will participate in the following parts:\n" -" " +#: studies/templates/studies/study_end.html:47 +msgid "zullen aan de volgende onderdelen meedoen:" +msgstr "will participate in the following parts:" -#: studies/templates/studies/study_end.html:61 +#: studies/templates/studies/study_end.html:59 msgid "Interventie bewerken" msgstr "Edit intervention" -#: studies/templates/studies/study_end.html:68 +#: studies/templates/studies/study_end.html:66 msgid "Aantal sessies (per week)" msgstr "Number of session (per week)" -#: studies/templates/studies/study_end.html:69 +#: studies/templates/studies/study_end.html:67 msgid "Duur per sessie (in minuten)" msgstr "Session duration (in minutes)" -#: studies/templates/studies/study_end.html:70 +#: studies/templates/studies/study_end.html:68 msgid "Controlegroep?" msgstr "Control group?" -#: studies/templates/studies/study_end.html:78 +#: studies/templates/studies/study_end.html:76 +#: studies/templates/studies/study_end.html:114 +#: studies/templates/studies/study_end.html:115 #: studies/templates/studies/study_end.html:116 #: studies/templates/studies/study_end.html:117 -#: studies/templates/studies/study_end.html:118 -#: studies/templates/studies/study_end.html:119 msgid "ja, nee" msgstr "yes, no" -#: studies/templates/studies/study_end.html:92 +#: studies/templates/studies/study_end.html:90 msgid "Observatie bewerken" msgstr "Edit observation" -#: studies/templates/studies/study_end.html:99 +#: studies/templates/studies/study_end.html:97 msgid "Aantal dagen" msgstr "Number of days" -#: studies/templates/studies/study_end.html:100 +#: studies/templates/studies/study_end.html:98 msgid "Duur per sessie (in uren)" msgstr "Duration per session (in hours)" -#: studies/templates/studies/study_end.html:101 +#: studies/templates/studies/study_end.html:99 msgid "Anoniem?" msgstr "Anonymous?" -#: studies/templates/studies/study_end.html:102 +#: studies/templates/studies/study_end.html:100 msgid "Doelgroep?" msgstr "Target group?" -#: studies/templates/studies/study_end.html:103 +#: studies/templates/studies/study_end.html:101 msgid "Niet openbaar?" msgstr "Non-public?" -#: studies/templates/studies/study_end.html:104 +#: studies/templates/studies/study_end.html:102 msgid "Toestemming nodig?" msgstr "Permission necessary?" -#: studies/templates/studies/study_end.html:106 +#: studies/templates/studies/study_end.html:104 msgid "Instantie" msgstr "Institution" -#: studies/templates/studies/study_end.html:108 +#: studies/templates/studies/study_end.html:106 #: tasks/templates/tasks/task_list.html:9 msgid "Registratie via" msgstr "Recording via" -#: studies/templates/studies/study_end.html:133 +#: studies/templates/studies/study_end.html:129 msgid "Takenonderzoek met de volgende opbouw:" msgstr "Task-based research structured as follows:" -#: studies/templates/studies/study_end.html:142 +#: studies/templates/studies/study_end.html:138 #: tasks/templates/tasks/session_confirm_delete.html:6 -#: tasks/templates/tasks/session_confirm_delete.html:14 +#: tasks/templates/tasks/session_confirm_delete.html:12 msgid "Sessie verwijderen" msgstr "Delete session" -#: studies/templates/studies/study_end.html:146 -#: tasks/templates/tasks/task_end.html:23 +#: studies/templates/studies/study_end.html:143 +#: tasks/templates/tasks/task_end.html:20 msgid "Deze sessie bestaat uit de volgende taken:" msgstr "This session consists of the following tasks:" -#: studies/templates/studies/study_end.html:156 +#: studies/templates/studies/study_end.html:153 msgid "" -"\n" -" Beantwoord op basis van dit overzicht de volgende " -"vragen,\n" -" en ga daarbij uit van het naar verwachting meest " -"kwetsbare c.q.\n" -" minst belastbare (bijv. jongste) geselecteerde " -"deelnemerstype\n" -" dat dit traject doorloopt.\n" -" " +"Beantwoord op basis van dit overzicht de volgende vragen, en ga daarbij uit " +"van het naar verwachting meest kwetsbare c.q. minst belastbare (bijv. " +"jongste) geselecteerde deelnemerstype dat dit traject doorloopt." msgstr "" -"\n" -" On the basis of this overview answer the following questions\n" -" with respect to those participants who are most vulnerable or least\n" -" able to bear any burden (e.g. the youngest) to follow this\n" -" trajectory.\n" -" " +"On the basis of this overview answer the following questions with respect to " +"those participants who are most vulnerable or least able to bear any burden " +"(e.g. the youngest) to follow this trajectory." #: studies/templates/studies/study_form.html:22 msgid "De leeftijdsgroep van je deelnemers" @@ -5720,42 +4882,26 @@ msgstr "Compensation" msgid "Hiërarchie" msgstr "Hierarchy" -#: studies/templates/studies/study_form.html:90 +#: studies/templates/studies/study_form.html:85 #, python-format msgid "" -"\n" -" Let op! Je hebt de vraag 'In " -"welke hoedanigheid ben je betrokken bij deze aanvraag?' nog niet " -"ingevuld, waardoor deze pagina nog kan veranderen op basis van je antwoord.\n" -" " +"Let op! Je hebt de vraag 'In welke hoedanigheid ben je " +"betrokken bij deze aanvraag?' nog niet ingevuld, waardoor deze pagina " +"nog kan veranderen op basis van je antwoord." msgstr "" -"\n" -" Warning! The question 'In welke " -"hoedanigheid ben je betrokken bij deze aanvraag?' has not been answered " -"yet. This page might change depending on your answer.\n" -" " +"Warning! The question 'In what capacity are you involved " +"in this application?' has not been answered yet. This page might change " +"depending on your answer." #: studies/templates/studies/study_title.html:6 #, python-format -msgid "" -"\n" -" Traject %(order)s (%(name)s)\n" -" " -msgstr "" -"\n" -" Trajectory %(order)s (%(name)s)\n" -" " +msgid "Traject %(order)s (%(name)s)" +msgstr "Trajectory %(order)s (%(name)s)" #: studies/templates/studies/study_title.html:10 #, python-format -msgid "" -"\n" -" Traject %(order)s\n" -" " -msgstr "" -"\n" -" Trajectory %(order)s\n" -" " +msgid "Traject %(order)s" +msgstr "Trajectory %(order)s" #: studies/templatetags/describe_documents.py:23 msgid "bestand" @@ -5785,7 +4931,7 @@ msgstr "information letter for parents" msgid "data management plan" msgstr "data management plan" -#: studies/templatetags/describe_documents.py:62 +#: studies/templatetags/describe_documents.py:64 msgid "" "\n" " {} bij {} van aanvraag {}-{}: {}\n" @@ -5795,7 +4941,7 @@ msgstr "" "{} of {} in application {}-{}: {}\n" " " -#: studies/templatetags/describe_documents.py:71 +#: studies/templatetags/describe_documents.py:76 msgid "" "\n" " {} van aanvraag {}-{}: {}\n" @@ -5805,48 +4951,48 @@ msgstr "" "{} of application {}-{}: {}\n" " " -#: studies/utils.py:63 +#: studies/utils.py:67 msgid "Deelnemers" msgstr "Participants" -#: studies/utils.py:69 +#: studies/utils.py:73 msgid "Onderzoekstype(n)" msgstr "Type(s) of research" -#: studies/utils.py:84 +#: studies/utils.py:88 msgid "Overzicht" msgstr "Overview" -#: studies/utils.py:92 +#: studies/utils.py:96 msgid "Traject {}" msgstr "Trajectory {}" -#: studies/views/session_views.py:22 +#: studies/views/session_views.py:24 #, python-format msgid "%(sessions_number)s sessie(s) voor studie %(title)s aangemaakt" msgstr "%(sessions_number)s sessions for application %(title)s created" -#: studies/views/study_views.py:29 +#: studies/views/study_views.py:36 msgid "Studie opgeslagen" msgstr "Application saved" -#: studies/views/study_views.py:63 +#: studies/views/study_views.py:70 msgid "Traject opgeslagen" msgstr "Trajectory saved" -#: tasks/forms.py:17 +#: tasks/forms.py:19 msgid "Is deze sessie een kopie van een voorgaande sessie?" msgstr "Is this session a copy of a previous session?" -#: tasks/forms.py:18 +#: tasks/forms.py:20 msgid "Na het kopiëren zijn alle velden bewerkbaar." msgstr "All fields can be edited after copying." -#: tasks/forms.py:23 +#: tasks/forms.py:26 msgid "Te kopiëren sessie" msgstr "Session to be copied" -#: tasks/forms.py:101 tasks/models.py:137 +#: tasks/forms.py:125 tasks/models.py:144 msgid "" "Wat is de duur van deze taak van begin tot eind in minuten, " "dus vanaf het moment dat de taak van start gaat tot en met het einde van de " @@ -5860,7 +5006,7 @@ msgstr "" "criterion), indicate the maximum duration that can reasonably be " "expected." -#: tasks/forms.py:181 +#: tasks/forms.py:217 msgid "Totale sessieduur moet minstens gelijk zijn aan netto sessieduur." msgstr "" "The total duration of the session must be at least as long as the net " @@ -5871,7 +5017,7 @@ msgid "Hoeveel taken worden er binnen deze sessie bij de deelnemer afgenomen?" msgstr "" "How many tasks will each participant have to carry out in this session?" -#: tasks/models.py:17 +#: tasks/models.py:21 msgid "" "Wanneer je bijvoorbeeld eerst de deelnemer observeert en de deelnemer " "vervolgens een vragenlijst afneemt, dan vul je hierboven \"2\" in. " @@ -5883,7 +5029,7 @@ msgstr "" "session debriefing and a short (<3 minute) exit interview are not counted as " "tasks." -#: tasks/models.py:24 +#: tasks/models.py:30 #, python-format msgid "" "De totale geschatte netto taakduur van je sessie komt op basis van je opgave " @@ -5897,19 +5043,19 @@ msgstr "" "task, breaks between tasks, and debriefing? (in case of a lab visit from " "entering the lab until leaving)" -#: tasks/models.py:84 +#: tasks/models.py:88 msgid "Sessie {}" msgstr "Session {}" -#: tasks/models.py:98 +#: tasks/models.py:102 msgid "Vastlegging gedrag" msgstr "Registration of behaviour" -#: tasks/models.py:121 +#: tasks/models.py:125 msgid "Wat is de naam van de taak?" msgstr "What is the title of the task?" -#: tasks/models.py:127 +#: tasks/models.py:132 msgid "" "Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort uit hoe deze " "taak (en de eventuele manipulaties daarbinnen) aan de beantwoording van jouw " @@ -5925,7 +5071,7 @@ msgstr "" "participant. The committee members need to be in the clear on your exact " "plans." -#: tasks/models.py:149 +#: tasks/models.py:158 msgid "" "Hoe wordt het gedrag of de toestand van de deelnemer bij deze taak " "vastgelegd?" @@ -5933,7 +5079,7 @@ msgstr "" "How will the behaviour or the state of the participant be recorded in this " "task?" -#: tasks/models.py:150 +#: tasks/models.py:161 msgid "" "Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het " "gebruik van de term ‘anoniem’ of ‘geanonimiseerd’ in je documenten " @@ -5951,11 +5097,11 @@ msgstr "" "versie-1.1_21dec2021.pdf' target='_blank'>Guidelines for Informed Consent, " "‘Audio and Video’ (in Dutch)." -#: tasks/models.py:164 +#: tasks/models.py:176 msgid "Kies het soort meting" msgstr "Select the type of measurement" -#: tasks/models.py:175 +#: tasks/models.py:188 msgid "" "Krijgt de deelnemer tijdens of na deze taak feedback op hun gedrag of " "toestand?" @@ -5963,54 +5109,37 @@ msgstr "" "Will the participant receive feedback on their behaviour or state during or " "after this task?" -#: tasks/models.py:182 +#: tasks/models.py:196 msgid "Beschrijf hoe de feedback wordt gegeven." msgstr "Describe how the feedback will be given." -#: tasks/models.py:206 +#: tasks/models.py:220 msgid "Taak {} in sessie {}" msgstr "Task {} in session {}" #: tasks/templates/tasks/session_title.html:6 #, python-format -msgid "" -"\n" -" Traject %(study_order)s (%(study_name)s), sessie %(order)s\n" -" " +msgid "Traject %(study_order)s (%(study_name)s), sessie %(order)s" msgstr "" -"\n" -" Trajectory %(study_order)s (%(study_name)s), session %(order)s\n" -" " +"Trajectory %(study_order)s (%(study_name)s), session %(order)s" #: tasks/templates/tasks/session_title.html:12 #, python-format -msgid "" -"\n" -" Traject %(study_order)s (%(study_name)s)\n" -" " -msgstr "" -"\n" -" Trajectory %(study_order)s (%(study_name)s)\n" -" " +msgid "Traject %(study_order)s (%(study_name)s)" +msgstr "Trajectory %(study_order)s (%(study_name)s)" #: tasks/templates/tasks/session_title.html:18 #, python-format -msgid "" -"\n" -" Sessie %(order)s\n" -" " -msgstr "" -"\n" -" Session %(order)s\n" -" " +msgid "Sessie %(order)s" +msgstr "Session %(order)s" #: tasks/templates/tasks/task_confirm_delete.html:6 -#: tasks/templates/tasks/task_confirm_delete.html:13 -#: tasks/templates/tasks/task_list.html:29 +#: tasks/templates/tasks/task_confirm_delete.html:12 +#: tasks/templates/tasks/task_list.html:32 msgid "Taak verwijderen" msgstr "Delete task" -#: tasks/templates/tasks/task_end.html:27 +#: tasks/templates/tasks/task_end.html:24 msgid "Beantwoord op basis van dit overzicht de volgende vragen:" msgstr "Answer the following questions on the basis of this overview:" @@ -6022,6 +5151,10 @@ msgstr "Net duration (in minutes)" msgid "Feedback?" msgstr "Feedback?" +#: tasks/templates/tasks/task_list.html:21 +msgid "ja,nee" +msgstr "yes,no" + #: tasks/templates/tasks/task_list.html:27 msgid "Taak bewerken" msgstr "Edit task" @@ -6034,40 +5167,30 @@ msgstr "We will ask the same questions for each task on the next few pages." #: tasks/templates/tasks/task_title.html:6 #, python-format msgid "" -"\n" -" Traject %(study_order)s (%(study_name)s), sessie " -"%(session_order)s, taak %(order)s\n" -" " +"Traject %(study_order)s (%(study_name)s), sessie %(session_order)s, " +"taak %(order)s" msgstr "" -"\n" -" Trajectory %(study_order)s (%(study_name)s), session " -"%(session_order)s, task %(order)s\n" -" " +"Trajectory %(study_order)s (%(study_name)s), session " +"%(session_order)s, task %(order)s" #: tasks/templates/tasks/task_title.html:12 #, python-format -msgid "" -"\n" -" Sessie %(session_order)s, taak %(order)s\n" -" " -msgstr "" -"\n" -" Session %(session_order)s, task %(order)s\n" -" " +msgid "Sessie %(session_order)s, taak %(order)s" +msgstr "Session %(session_order)s, task %(order)s" -#: tasks/utils.py:32 +#: tasks/utils.py:36 msgid "Takenonderzoek" msgstr "Task-based research" -#: tasks/utils.py:40 +#: tasks/utils.py:45 msgid "Het takenonderzoek: sessie {}" msgstr "Task-based research: session {}" -#: tasks/utils.py:47 +#: tasks/utils.py:54 msgid "Overzicht van takenonderzoek: sessie {}" msgstr "Overview of task-based research: session {}" -#: tasks/utils.py:62 +#: tasks/utils.py:71 msgid "Het takenonderzoek: sessie {} taak {}" msgstr "Task-based research: session {} task {}" @@ -6075,19 +5198,19 @@ msgstr "Task-based research: session {} task {}" msgid "Sessie verwijderd" msgstr "Session deleted" -#: tasks/views/session_views.py:55 +#: tasks/views/session_views.py:56 #, python-format msgid "%(tasks_number)s ta(a)k(en) aangemaakt" msgstr "%(tasks_number)s task(s) created" -#: tasks/views/session_views.py:131 +#: tasks/views/session_views.py:135 msgid "Taken toevoegen beëindigd" msgstr "Finished adding tasks" -#: tasks/views/task_views.py:21 +#: tasks/views/task_views.py:22 msgid "Taak bewerkt" msgstr "Task edited" -#: tasks/views/task_views.py:50 +#: tasks/views/task_views.py:56 msgid "Taak verwijderd" msgstr "Task deleted" diff --git a/main/admin.py b/main/admin.py index 482305b6c..38eb225d0 100644 --- a/main/admin.py +++ b/main/admin.py @@ -23,30 +23,43 @@ class GenericGroup(GroupAdmin): @admin.register(Faculty) class FacultyAdmin(admin.ModelAdmin): - list_display = ('saml_name', 'name', 'name_nl', 'name_en', 'internal_name',) - list_display_links = ('saml_name',) - filter_horizontal = ('users',) + list_display = ( + "saml_name", + "name", + "name_nl", + "name_en", + "internal_name", + ) + list_display_links = ("saml_name",) + filter_horizontal = ("users",) @admin.register(Setting) class SettingAdmin(admin.ModelAdmin): - list_display = ('order', 'description', 'is_local', 'needs_details', 'needs_supervision', 'requires_review', 'is_school',) - list_display_links = ('description', ) - ordering = ['order'] + list_display = ( + "order", + "description", + "is_local", + "needs_details", + "needs_supervision", + "requires_review", + "is_school", + ) + list_display_links = ("description",) + ordering = ["order"] @admin.register(SystemMessage) class SystemMessageAdmin(admin.ModelAdmin): - list_display = ('level', 'message', 'not_before', 'not_after') - list_display_links = ('message', ) - ordering = ['not_before', 'not_after'] - formfield_overrides = { - CharField: {'widget': Textarea} - } + list_display = ("level", "message", "not_before", "not_after") + list_display_links = ("message",) + ordering = ["not_before", "not_after"] + formfield_overrides = {CharField: {"widget": Textarea}} class FacultyInline(admin.TabularInline): """Adds a 'Faculty' field to the User admin""" + model = Faculty.users.through can_delete = False verbose_name_plural = "faculties" @@ -57,4 +70,4 @@ class CustomUserAdmin(UserAdmin): inlines = [FacultyInline] -admin.site.register(get_user_model(), CustomUserAdmin) \ No newline at end of file +admin.site.register(get_user_model(), CustomUserAdmin) diff --git a/main/error_views.py b/main/error_views.py index bf45a6b55..e17c83b97 100644 --- a/main/error_views.py +++ b/main/error_views.py @@ -3,19 +3,20 @@ def error_400(request, exception): - return render(request, 'error/400.html', status=400) + return render(request, "error/400.html", status=400) def error_403(request, exception): - return render(request, 'error/403.html', status=403) + return render(request, "error/403.html", status=403) def error_404(request, exception): - return render(request, 'error/404.html', status=404) + return render(request, "error/404.html", status=404) def error_500(request): - return render(request, 'error/500.html', status=500) + return render(request, "error/500.html", status=500) + def csrf_failure(request, reason=""): - return render(request, 'error/403_csrf.html', status=403) + return render(request, "error/403_csrf.html", status=403) diff --git a/main/fixtures/groups.json b/main/fixtures/groups.json index e3f8daf4d..de1159e26 100644 --- a/main/fixtures/groups.json +++ b/main/fixtures/groups.json @@ -30,5 +30,21 @@ }, "model": "auth.group", "pk": 4 + }, + { + "fields": { + "name": "Voorzitter", + "permissions": [] + }, + "model": "auth.group", + "pk": 5 + }, + { + "fields": { + "name": "Privacy officer", + "permissions": [] + }, + "model": "auth.group", + "pk": 6 } ] \ No newline at end of file diff --git a/main/forms/conditional_form.py b/main/forms/conditional_form.py index dcb0a054d..4794df4bc 100644 --- a/main/forms/conditional_form.py +++ b/main/forms/conditional_form.py @@ -5,51 +5,63 @@ class ConditionalModelForm(forms.ModelForm): - def check_empty(self, cleaned_data, f1, error_message=''): + def check_empty(self, cleaned_data, f1, error_message=""): is_required = False if not error_message: - error_message = _('Dit veld is verplicht.') + error_message = _("Dit veld is verplicht.") if cleaned_data.get(f1) is None: is_required = True - self.add_error(f1, forms.ValidationError(error_message, code='required')) + self.add_error(f1, forms.ValidationError(error_message, code="required")) return is_required - def check_dependency(self, cleaned_data, f1, f2, f1_value=True, error_message=''): + def check_dependency(self, cleaned_data, f1, f2, f1_value=True, error_message=""): is_required = False if not error_message: - error_message = _('Dit veld is verplicht.') + error_message = _("Dit veld is verplicht.") if cleaned_data.get(f1) == f1_value and is_empty(cleaned_data.get(f2)): is_required = True - self.add_error(f2, forms.ValidationError(error_message, code='required')) + self.add_error(f2, forms.ValidationError(error_message, code="required")) return is_required - def check_dependency_list(self, cleaned_data, f1, f2, f1_value_list, error_message=''): + def check_dependency_list( + self, cleaned_data, f1, f2, f1_value_list, error_message="" + ): is_required = False if not error_message: - error_message = _('Dit veld is verplicht.') + error_message = _("Dit veld is verplicht.") if cleaned_data.get(f1) in f1_value_list and is_empty(cleaned_data.get(f2)): is_required = True - self.add_error(f2, forms.ValidationError(error_message, code='required')) + self.add_error(f2, forms.ValidationError(error_message, code="required")) return is_required - def check_dependency_singular(self, cleaned_data, f1, f1_field, f2, error_message=''): + def check_dependency_singular( + self, cleaned_data, f1, f1_field, f2, error_message="" + ): is_required = False if not error_message: - error_message = _('Dit veld is verplicht.') + error_message = _("Dit veld is verplicht.") if cleaned_data.get(f1): - if getattr(cleaned_data.get(f1), f1_field) and is_empty(cleaned_data.get(f2)): + if getattr(cleaned_data.get(f1), f1_field) and is_empty( + cleaned_data.get(f2) + ): is_required = True - self.add_error(f2, forms.ValidationError(error_message, code='required')) + self.add_error( + f2, forms.ValidationError(error_message, code="required") + ) return is_required - def check_dependency_multiple(self, cleaned_data, f1, f1_field, f2, error_message=''): + def check_dependency_multiple( + self, cleaned_data, f1, f1_field, f2, error_message="" + ): is_required = False if not error_message: - error_message = _('Dit veld is verplicht.') + error_message = _("Dit veld is verplicht.") if cleaned_data.get(f1): for item in cleaned_data.get(f1): if getattr(item, f1_field) and is_empty(cleaned_data.get(f2)): is_required = True - self.add_error(f2, forms.ValidationError(error_message, code='required')) + self.add_error( + f2, forms.ValidationError(error_message, code="required") + ) break return is_required diff --git a/main/forms/mixins.py b/main/forms/mixins.py index d7925ca29..7c5575e15 100644 --- a/main/forms/mixins.py +++ b/main/forms/mixins.py @@ -10,6 +10,7 @@ class SoftValidationMixin: This mixin will allow a form to submit even if specified fields have validator errors. """ + _soft_validation_fields = [] def __init__(self, *args, **kwargs): @@ -17,7 +18,7 @@ def __init__(self, *args, **kwargs): # If we have an existing instance and we're not POSTing, # run a initial clean - if self.instance.pk and 'data' not in kwargs: + if self.instance.pk and "data" not in kwargs: self.initial_clean() def initial_clean(self): @@ -27,7 +28,7 @@ def initial_clean(self): self._errors = ErrorDict() reset_cleaned = False - if not hasattr(self, 'cleaned_data'): + if not hasattr(self, "cleaned_data"): reset_cleaned = True self.cleaned_data = {} @@ -50,8 +51,8 @@ def _initial_clean_fields(self): val = field.clean(value, value) else: val = field.clean(value) - if hasattr(self, 'clean_%s' % field): - val = getattr(self, 'clean_%s' % field)() + if hasattr(self, "clean_%s" % field): + val = getattr(self, "clean_%s" % field)() self.cleaned_data[field_name] = val except ValidationError as e: @@ -73,14 +74,11 @@ def mark_soft_required(self, data, *fields): for field in fields: if field not in self.fields: raise ImproperlyConfigured( - "{} is not a field of {}!".format( - field, - self.__class__.__name__ - ) + "{} is not a field of {}!".format(field, self.__class__.__name__) ) if field not in data or not data[field]: - self.add_error(field, _('Dit veld is verplicht.')) + self.add_error(field, _("Dit veld is verplicht.")) def _initial_post_clean(self): opts = self._meta @@ -99,7 +97,9 @@ def _initial_post_clean(self): exclude.append(name) try: - self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude) + self.instance = construct_instance( + self, self.instance, opts.fields, opts.exclude + ) except ValidationError as e: self._update_errors(e) @@ -113,8 +113,11 @@ def _initial_post_clean(self): @property def _hard_errors(self): - return [x for x in self.errors.items() if x[0] not in - self.get_soft_validation_fields()] + return [ + x + for x in self.errors.items() + if x[0] not in self.get_soft_validation_fields() + ] def get_soft_validation_fields(self): return self._soft_validation_fields @@ -129,9 +132,10 @@ def save(self, commit=True): """ if self._hard_errors: raise ValueError( - "The %s could not be %s because the data didn't validate." % ( + "The %s could not be %s because the data didn't validate." + % ( self.instance._meta.object_name, - 'created' if self.instance._state.adding else 'changed', + "created" if self.instance._state.adding else "changed", ) ) if commit: diff --git a/main/management/commands/add_ldap_users.py b/main/management/commands/add_ldap_users.py index 6d08b0889..9de261c6e 100644 --- a/main/management/commands/add_ldap_users.py +++ b/main/management/commands/add_ldap_users.py @@ -3,13 +3,13 @@ class Command(BaseCommand): - help = 'Adds users from the LDAP backend' + help = "Adds users from the LDAP backend" def add_arguments(self, parser): - parser.add_argument('usernames', nargs='+', type=str) + parser.add_argument("usernames", nargs="+", type=str) def handle(self, *args, **options): - for username in options['usernames']: + for username in options["usernames"]: user = LDAPBackend().populate_user(username) if user is None: - raise CommandError('No user named {}'.format(username)) + raise CommandError("No user named {}".format(username)) diff --git a/main/management/commands/load_fixtures.py b/main/management/commands/load_fixtures.py new file mode 100644 index 000000000..617f1ea53 --- /dev/null +++ b/main/management/commands/load_fixtures.py @@ -0,0 +1,47 @@ +from django.core.management.base import BaseCommand, CommandError +from django.core.management import call_command +from django.conf import settings + +import os + + +def list_fixtures_in_dir(rel_path): + files = os.listdir(rel_path) + # Sort the list alphabetically for consistent load-order + files.sort() + + def is_fixture(fn): + return fn.lower()[-5:] == ".json" + + return [os.path.join(rel_path, fn) for fn in files if is_fixture(fn)] + + +fixture_dirs = { + "main": list_fixtures_in_dir("main/fixtures/"), + "proposals": list_fixtures_in_dir("proposals/fixtures/"), + "studies": list_fixtures_in_dir("studies/fixtures/"), + "tasks": list_fixtures_in_dir("tasks/fixtures/"), + "observations": list_fixtures_in_dir("observations/fixtures/"), +} + + +class Command(BaseCommand): + help = "Loads fixtures for development in the correct order." + + def add_arguments(self, parser): + parser.add_argument("--force", action="store_true") + + def handle(self, *args, **kwargs): + if not settings.DEBUG and not kwargs["force"]: + raise CommandError( + "Refusing to execute command unless DEBUG = True in settings.py" + ) + + print("Loading fixtures...") + + for app, locations in fixture_dirs.items(): + print(f"for {app}") + for loc in locations: + call_command("loaddata", loc) + + print("Done!") diff --git a/main/management/commands/rename_app.py b/main/management/commands/rename_app.py index ffbe5870e..c35177e47 100644 --- a/main/management/commands/rename_app.py +++ b/main/management/commands/rename_app.py @@ -14,13 +14,11 @@ class Command(BaseCommand): - help = ( - 'Renames a Django Application. Usage rename_app [old_name] [new_name]' - ) + help = "Renames a Django Application. Usage rename_app [old_name] [new_name]" def add_arguments(self, parser): - parser.add_argument('old_name', nargs=1, type=str) - parser.add_argument('new_name', nargs=1, type=str) + parser.add_argument("old_name", nargs=1, type=str) + parser.add_argument("new_name", nargs=1, type=str) def handle(self, old_name, new_name, *args, **options): with connection.cursor() as cursor: @@ -28,14 +26,13 @@ def handle(self, old_name, new_name, *args, **options): new_name = new_name[0] cursor.execute( - "SELECT * FROM django_content_type " - f"where app_label='{new_name}'" + "SELECT * FROM django_content_type " f"where app_label='{new_name}'" ) has_already_been_ran = cursor.fetchone() if has_already_been_ran: logger.info( - 'Rename has already been done, exiting without ' - 'making any changes' + "Rename has already been done, exiting without " + "making any changes" ) return None @@ -57,6 +54,4 @@ def handle(self, old_name, new_name, *args, **options): try: cursor.execute(query) except ProgrammingError: - logger.warning( - 'Rename query failed: "%s"', query, exc_info=True - ) + logger.warning('Rename query failed: "%s"', query, exc_info=True) diff --git a/main/menus.py b/main/menus.py index a0bda8acc..ebf35c80c 100644 --- a/main/menus.py +++ b/main/menus.py @@ -3,17 +3,16 @@ from django.conf import settings from menu import Menu, MenuItem -Menu.add_item("home", MenuItem(_('Startpagina'), - reverse('main:home'), - exact_url=True - )) +Menu.add_item("home", MenuItem(_("Startpagina"), reverse("main:home"), exact_url=True)) -Menu.add_item("footer", MenuItem(_('Log in'), - settings.LOGIN_URL, - check=lambda x: not x.user.is_authenticated - )) +Menu.add_item( + "footer", + MenuItem( + _("Log in"), settings.LOGIN_URL, check=lambda x: not x.user.is_authenticated + ), +) -Menu.add_item("footer", MenuItem(_('Log uit'), - reverse('logout'), - check=lambda x: x.user.is_authenticated - )) \ No newline at end of file +Menu.add_item( + "footer", + MenuItem(_("Log uit"), reverse("logout"), check=lambda x: x.user.is_authenticated), +) diff --git a/main/migrations/0001_initial.py b/main/migrations/0001_initial.py index fa4cb736b..62d6689c8 100644 --- a/main/migrations/0001_initial.py +++ b/main/migrations/0001_initial.py @@ -5,23 +5,29 @@ class Migration(migrations.Migration): - - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Setting', + name="Setting", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('order', models.PositiveIntegerField(unique=True)), - ('description', models.CharField(max_length=200)), - ('needs_details', models.BooleanField(default=False)), - ('needs_supervision', models.BooleanField(default=False)), - ('requires_review', models.BooleanField(default=False)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("order", models.PositiveIntegerField(unique=True)), + ("description", models.CharField(max_length=200)), + ("needs_details", models.BooleanField(default=False)), + ("needs_supervision", models.BooleanField(default=False)), + ("requires_review", models.BooleanField(default=False)), ], options={ - 'ordering': ['order'], + "ordering": ["order"], }, ), ] diff --git a/main/migrations/0002_auto_20161013_1959.py b/main/migrations/0002_auto_20161013_1959.py index bc1e7259a..dd9ece7fd 100644 --- a/main/migrations/0002_auto_20161013_1959.py +++ b/main/migrations/0002_auto_20161013_1959.py @@ -5,20 +5,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('main', '0001_initial'), + ("main", "0001_initial"), ] operations = [ migrations.AddField( - model_name='setting', - name='description_en', + model_name="setting", + name="description_en", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='setting', - name='description_nl', + model_name="setting", + name="description_nl", field=models.CharField(max_length=200, null=True), ), ] diff --git a/main/migrations/0003_auto_20170601_0816.py b/main/migrations/0003_auto_20170601_0816.py index 35ebf5f29..a38ba3f27 100644 --- a/main/migrations/0003_auto_20170601_0816.py +++ b/main/migrations/0003_auto_20170601_0816.py @@ -5,19 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('main', '0002_auto_20161013_1959'), + ("main", "0002_auto_20161013_1959"), ] operations = [ migrations.AlterModelOptions( - name='setting', - options={'ordering': ['order'], 'verbose_name': 'Setting'}, + name="setting", + options={"ordering": ["order"], "verbose_name": "Setting"}, ), migrations.AddField( - model_name='setting', - name='is_local', + model_name="setting", + name="is_local", field=models.BooleanField(default=False), ), ] diff --git a/main/migrations/0004_setting_is_school.py b/main/migrations/0004_setting_is_school.py index b79465b91..f4d8e4a6f 100644 --- a/main/migrations/0004_setting_is_school.py +++ b/main/migrations/0004_setting_is_school.py @@ -6,15 +6,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('main', '0003_auto_20170601_0816'), + ("main", "0003_auto_20170601_0816"), ] operations = [ migrations.AddField( - model_name='setting', - name='is_school', + model_name="setting", + name="is_school", field=models.BooleanField(default=False), ), ] diff --git a/main/migrations/0005_auto_20180829_1540.py b/main/migrations/0005_auto_20180829_1540.py index c0e187dfb..cbb55706b 100644 --- a/main/migrations/0005_auto_20180829_1540.py +++ b/main/migrations/0005_auto_20180829_1540.py @@ -6,15 +6,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('main', '0004_setting_is_school'), + ("main", "0004_setting_is_school"), ] operations = [ migrations.AlterField( - model_name='setting', - name='is_school', - field=models.BooleanField(default=False, verbose_name='Needs external permission'), + model_name="setting", + name="is_school", + field=models.BooleanField( + default=False, verbose_name="Needs external permission" + ), ), ] diff --git a/main/migrations/0006_systemmessage.py b/main/migrations/0006_systemmessage.py index 9eba70356..6777ca43c 100644 --- a/main/migrations/0006_systemmessage.py +++ b/main/migrations/0006_systemmessage.py @@ -4,20 +4,32 @@ class Migration(migrations.Migration): - dependencies = [ - ('main', '0005_auto_20180829_1540'), + ("main", "0005_auto_20180829_1540"), ] operations = [ migrations.CreateModel( - name='SystemMessage', + name="SystemMessage", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('message', models.CharField(max_length=200)), - ('level', models.IntegerField(choices=[(1, 'Urgent'), (2, 'Attention'), (3, 'Info')])), - ('not_before', models.DateTimeField()), - ('not_after', models.DateTimeField()), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("message", models.CharField(max_length=200)), + ( + "level", + models.IntegerField( + choices=[(1, "Urgent"), (2, "Attention"), (3, "Info")] + ), + ), + ("not_before", models.DateTimeField()), + ("not_after", models.DateTimeField()), ], ), ] diff --git a/main/migrations/0007_auto_20210528_1331.py b/main/migrations/0007_auto_20210528_1331.py index 69c1c3102..858aab1df 100644 --- a/main/migrations/0007_auto_20210528_1331.py +++ b/main/migrations/0007_auto_20210528_1331.py @@ -4,20 +4,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('main', '0006_systemmessage'), + ("main", "0006_systemmessage"), ] operations = [ migrations.AddField( - model_name='systemmessage', - name='message_en', + model_name="systemmessage", + name="message_en", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='systemmessage', - name='message_nl', + model_name="systemmessage", + name="message_nl", field=models.CharField(max_length=200, null=True), ), ] diff --git a/main/migrations/0008_auto_20220926_0929.py b/main/migrations/0008_auto_20220926_0929.py index acb7cfe83..aa5f7bd65 100644 --- a/main/migrations/0008_auto_20220926_0929.py +++ b/main/migrations/0008_auto_20220926_0929.py @@ -4,25 +4,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('main', '0007_auto_20210528_1331'), + ("main", "0007_auto_20210528_1331"), ] operations = [ migrations.AlterField( - model_name='systemmessage', - name='message', + model_name="systemmessage", + name="message", field=models.TextField(), ), migrations.AlterField( - model_name='systemmessage', - name='message_en', + model_name="systemmessage", + name="message_en", field=models.TextField(null=True), ), migrations.AlterField( - model_name='systemmessage', - name='message_nl', + model_name="systemmessage", + name="message_nl", field=models.TextField(null=True), ), ] diff --git a/main/migrations/0009_faculty_samluserproxy.py b/main/migrations/0009_faculty_samluserproxy.py index 5b931532c..e6a1ba5a6 100644 --- a/main/migrations/0009_faculty_samluserproxy.py +++ b/main/migrations/0009_faculty_samluserproxy.py @@ -6,37 +6,48 @@ class Migration(migrations.Migration): - dependencies = [ - ('auth', '0012_alter_user_first_name_max_length'), + ("auth", "0012_alter_user_first_name_max_length"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('main', '0008_auto_20220926_0929'), + ("main", "0008_auto_20220926_0929"), ] operations = [ migrations.CreateModel( - name='SamlUserProxy', - fields=[ - ], + name="SamlUserProxy", + fields=[], options={ - 'proxy': True, - 'indexes': [], - 'constraints': [], + "proxy": True, + "indexes": [], + "constraints": [], }, - bases=('auth.user',), + bases=("auth.user",), managers=[ - ('objects', django.contrib.auth.models.UserManager()), + ("objects", django.contrib.auth.models.UserManager()), ], ), migrations.CreateModel( - name='Faculty', + name="Faculty", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255)), - ('name_nl', models.CharField(max_length=255, null=True)), - ('name_en', models.CharField(max_length=255, null=True)), - ('saml_name', models.CharField(max_length=255)), - ('users', models.ManyToManyField(related_name='faculties', to=settings.AUTH_USER_MODEL)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), + ("name_nl", models.CharField(max_length=255, null=True)), + ("name_en", models.CharField(max_length=255, null=True)), + ("saml_name", models.CharField(max_length=255)), + ( + "users", + models.ManyToManyField( + related_name="faculties", to=settings.AUTH_USER_MODEL + ), + ), ], ), ] diff --git a/main/migrations/0010_faculty_internal_name.py b/main/migrations/0010_faculty_internal_name.py index 868019fef..44a541b32 100644 --- a/main/migrations/0010_faculty_internal_name.py +++ b/main/migrations/0010_faculty_internal_name.py @@ -4,15 +4,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('main', '0009_faculty_samluserproxy'), + ("main", "0009_faculty_samluserproxy"), ] operations = [ migrations.AddField( - model_name='faculty', - name='internal_name', - field=models.CharField(choices=[('humanities', 'Humanities'), ('other', 'Other')], default='other', max_length=50), + model_name="faculty", + name="internal_name", + field=models.CharField( + choices=[("humanities", "Humanities"), ("other", "Other")], + default="other", + max_length=50, + ), ), ] diff --git a/main/models.py b/main/models.py index 05f9105a2..bf94d82b0 100644 --- a/main/models.py +++ b/main/models.py @@ -3,42 +3,35 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ -YES = 'Y' -NO = 'N' -DOUBT = '?' -YES_NO_DOUBT = ( - (YES, _('ja')), - (NO, _('nee')), - (DOUBT, _('twijfel')), -) + +class YesNoDoubt(models.TextChoices): + YES = "Y", _("ja") + NO = "N", _("nee") + DOUBT = "?", _("twijfel") class SystemMessage(models.Model): - URGENT = 1 - ATTENTION = 2 - INFO = 3 - # Not translated, as it's backend only - LEVELS = ( - (URGENT, "Urgent"), - (ATTENTION, "Attention"), - (INFO, "Info") - ) + class Levels(models.IntegerChoices): + # Not translated, as it's backend only + URGENT = 1, "Urgent" + ATTENTION = 2, "Attention" + INFO = 3, "Info" message = models.TextField() - level = models.IntegerField(choices=LEVELS) + level = models.IntegerField(choices=Levels.choices) not_before = models.DateTimeField() not_after = models.DateTimeField() @property def css_class(self): - if self.level == self.URGENT: - return 'failed' - if self.level == self.ATTENTION: - return 'warning' - if self.level == self.INFO: - return 'info' + if self.level == self.Levels.URGENT: + return "failed" + if self.level == self.Levels.ATTENTION: + return "warning" + if self.level == self.Levels.INFO: + return "info" - return '' + return "" class Setting(models.Model): @@ -53,8 +46,8 @@ class Setting(models.Model): is_school = models.BooleanField("Needs external permission", default=False) class Meta: - ordering = ['order'] - verbose_name = _('Setting') + ordering = ["order"] + verbose_name = _("Setting") def __str__(self): return self.description @@ -63,29 +56,33 @@ def __str__(self): class SettingModel(models.Model): setting = models.ManyToManyField( Setting, - verbose_name=_('Geef aan waar de dataverzameling plaatsvindt'), - blank=True, # TODO: mark this as soft required in ALL forms + verbose_name=_("Geef aan waar de dataverzameling plaatsvindt"), + blank=True, # TODO: mark this as soft required in ALL forms ) setting_details = models.CharField( - _('Namelijk'), + _("Namelijk"), max_length=200, blank=True, ) supervision = models.BooleanField( - _('Vindt het afnemen van de taak plaats onder het toeziend oog \ -van de leraar of een ander persoon die bevoegd is?'), + _( + "Vindt het afnemen van de taak plaats onder het toeziend oog \ +van de leraar of een ander persoon die bevoegd is?" + ), null=True, blank=True, ) leader_has_coc = models.BooleanField( - _('Is de testleider in het bezit van een VOG?'), - help_text=_('Iedereen die op een school werkt moet in het bezit \ + _("Is de testleider in het bezit van een VOG?"), + help_text=_( + 'Iedereen die op een school werkt moet in het bezit \ zijn van een Verklaring Omtrent Gedrag (VOG, zie \ https://www.justis.nl/producten/vog/). \ Het is de verantwoordelijkheid van de school om hierom te vragen. \ De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers \ - waarschuwen dat de school om een VOG kan vragen.'), + waarschuwen dat de school om een VOG kan vragen.' + ), null=True, blank=True, ) @@ -95,7 +92,7 @@ class Meta: def settings_contains_schools(self): """If the current settings contains any that are marked as schools.""" - return self.setting.filter(is_school=True).exists(); + return self.setting.filter(is_school=True).exists() def settings_requires_review(self): """If the current settings contain any that requires review""" @@ -115,10 +112,7 @@ class InternalNames(models.TextChoices): max_length=255, ) - users = models.ManyToManyField( - get_user_model(), - related_name='faculties' - ) + users = models.ManyToManyField(get_user_model(), related_name="faculties") internal_name = models.CharField( max_length=50, @@ -135,6 +129,7 @@ class SamlUserProxy(User): It's not a replacement User model. It may be used elsewhere in code, but why would you? """ + class Meta: proxy = True diff --git a/main/serializers.py b/main/serializers.py index 83b3132c2..6b31fac13 100644 --- a/main/serializers.py +++ b/main/serializers.py @@ -5,6 +5,6 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ['pk', 'fullname', 'first_name', 'last_name', 'email'] + fields = ["pk", "fullname", "first_name", "last_name", "email"] - fullname = serializers.CharField(source='get_full_name') + fullname = serializers.CharField(source="get_full_name") diff --git a/main/static/main/style.css b/main/static/main/style.css index 03ab362f2..0925d92d7 100644 --- a/main/static/main/style.css +++ b/main/static/main/style.css @@ -86,6 +86,10 @@ form label { background-color: orange; } +.proposals-diff th, .proposals-diff td { + padding: 10px; +} + /* Form specifics */ input[name=title] { width: 20em; diff --git a/main/templates/auth/user_detail.html b/main/templates/auth/user_detail.html index 2fd0f3175..6da2e6410 100644 --- a/main/templates/auth/user_detail.html +++ b/main/templates/auth/user_detail.html @@ -6,111 +6,102 @@ {% load i18n %} {% load datatables %} -{% block header_title %} - {{ user_object.get_full_name }} - {{ block.super }} -{% endblock %} +{% block header_title %}{{ user_object.get_full_name }} - {{ block.super }}{% endblock %} {% block content %}
    -

    - {{ user_object.get_full_name }} -

    +

    {{ user_object.get_full_name }}

    - - + + - - + + - +
    - {% trans 'Gebruiksersnaam' %} - - {{ user_object.username }} - {% trans 'Gebruiksersnaam' %}{{ user_object.username }}
    - {% trans 'E-mail' %} - - {{ user_object.email }} - {% trans 'E-mail' %}{{ user_object.email }}
    {% get_verbose_field_name "auth" "user" "date_joined" as date_joined_trans %} {{ date_joined_trans|capfirst }} - {{ user_object.date_joined }} - {{ user_object.date_joined }}

    {% trans 'Ingediende aanvragen' %}

    - - - - - - - - - - - - + + + + + + + + + + + - {% for review in reviews %} - - - - - - - - - + + + + + + + + - + - - {% endfor %} + + + {% endfor %}
    {% trans "Referentienummer" %}{% trans "Eindverantwoordelijke" %}{% trans "Titel aanvraag" %}{% trans "Fase" %}{% trans "Datum ingediend" %}{% trans "Gewenste einddatum" %}{% trans "Mijn besluit" %}{% trans "Afhandeling" %}{% trans "Acties" %}
    {% trans "Referentienummer" %}{% trans "Eindverantwoordelijke" %}{% trans "Titel aanvraag" %}{% trans "Fase" %}{% trans "Datum ingediend" %}{% trans "Gewenste einddatum" %}{% trans "Mijn besluit" %}{% trans "Afhandeling" %}{% trans "Acties" %}
    {{ review.proposal.reference_number }}{{ review.accountable_user.get_full_name }}{{ review.proposal.title }}{{ review.get_stage_display }}{{ review.date_start|date:"j M Y" }}{{ review.date_should_end|date:"j M Y" }}{{ decision.get_go_display|default:"" }} - {% if review.stage == review.CLOSED %} - {% if review.proposal.has_minor_revision %} - {{ review.get_continuation_display }}{% trans ', met revisie' %} - {% else %} - {{ review.get_continuation_display }} + {% for review in reviews %} +
    {{ review.proposal.reference_number }}{{ review.accountable_user.get_full_name }}{{ review.proposal.title }}{{ review.get_stage_display }}{{ review.date_start|date:"j M Y" }}{{ review.date_should_end|date:"j M Y" }}{{ decision.get_go_display|default:"" }} + {% if review.stage == review.Stages.CLOSED %} + {% if review.proposal.has_minor_revision %} + {{ review.get_continuation_display }}{% trans ', met revisie' %} + {% else %} + {{ review.get_continuation_display }} + {% endif %} {% endif %} - {% endif %} - - - - {% if user|is_secretary and review.stage == review.ASSIGNMENT %} - - {% elif user|is_secretary and review.stage == review.CLOSING %} - - {% elif user|is_secretary and review.stage == review.CLOSED %} - {% if review.continuation == review.GO or review.continuation == review.GO_POST_HOC %} - - + + + + + + + + {% if user|is_secretary and review.stage == review.Stages.ASSIGNMENT %} + + - - {% if not review.proposal.date_confirmed %} - - {% else %} - - {% endif %} + {% elif user|is_secretary and review.stage == review.Stages.CLOSING %} + + + {% elif user|is_secretary and review.stage == review.Stages.CLOSED %} + {% if review.continuation == review.Continuations.GO or review.continuation == review.Continuations.GO_POST_HOC %} + + + + + {% if not review.proposal.date_confirmed %} + + {% else %} + + {% endif %} + + {% endif %} {% endif %} - {% endif %} -
    diff --git a/main/templates/base/form_buttons.html b/main/templates/base/form_buttons.html index 52d989c66..e7cd1ed23 100644 --- a/main/templates/base/form_buttons.html +++ b/main/templates/base/form_buttons.html @@ -3,37 +3,42 @@
    {% if not no_back %} - + {% if proposal %} {% if proposal.is_pre_assessment %} - - {% trans "Terug naar begin aanvraag" %} - + {% trans "Terug naar begin aanvraag" %} + {% elif proposal.is_pre_approved %} + {% trans "Terug naar begin aanvraag" %} {% elif proposal.is_practice %} - + {% trans "Terug naar begin aanvraag" %} {% else %} - - {% trans "Terug naar begin aanvraag" %} - + {% trans "Terug naar begin aanvraag" %} {% endif %} {% endif %} {% if study %} - - {% trans "Terug naar begin traject" %} - + {% trans "Terug naar begin traject" %} {% endif %} {% if session %} - - {% trans "Terug naar begin sessie" %} - + {% trans "Terug naar begin sessie" %} {% endif %} {% endif %} {% if not no_forward %} - + {% trans 'Opslaan en volgende stap >>' as default_next_text %} + {% endif %}
    -
    diff --git a/main/templates/base/login_header.html b/main/templates/base/login_header.html index 49290366d..ed081a8b3 100644 --- a/main/templates/base/login_header.html +++ b/main/templates/base/login_header.html @@ -6,6 +6,6 @@ {% transformat "Welkom {}" user.get_full_name %} ({% trans 'Log uit' %}) {% endwith %} - {% else %} +{% else %}   {# UI requires a line here #} {% endif %} diff --git a/main/templates/base/menu.html b/main/templates/base/menu.html deleted file mode 100644 index 4e9dffd4b..000000000 --- a/main/templates/base/menu.html +++ /dev/null @@ -1,180 +0,0 @@ -{% load i18n %} -{% load fetc_filters %} - -
    - -
    - - diff --git a/main/templates/base/navigation.html b/main/templates/base/navigation.html index c89922521..caecae092 100644 --- a/main/templates/base/navigation.html +++ b/main/templates/base/navigation.html @@ -2,7 +2,6 @@ {% load uil_filters %} {% include 'base/sidebar.html' %} - \ No newline at end of file +
    diff --git a/main/templates/base/sidebar.html b/main/templates/base/sidebar.html index fe8ecde4d..f4c0bc086 100644 --- a/main/templates/base/sidebar.html +++ b/main/templates/base/sidebar.html @@ -1,9 +1,12 @@ {% load static %} {% load i18n %} - - - + + - -
    +

    {% trans "Voortgang" %}

      - {% for item in nav_items %} - {% if not item.is_title %} -
    • - {% if item.url %} - {{ item.title }} - {% else %} - {{ item.title }} - {% endif %} -
    • -
    • - {% for child in item.children %} -
    • - {% if child.url %} - {{ child.title }} - {% else %} - {{ child.title }} - {% endif %} -
    • -
    • - {% for subchild in child.children %} + {% for item in nav_items %} + {% if not item.is_title %}
    • - {% if subchild.url %} - {{ subchild.title }} + {% if item.url %} + {{ item.title }} {% else %} - {{ subchild.title }} + {{ item.title }} {% endif %}
    • -
    • - {% endfor %} +
    • +
      +
    • + {% for child in item.children %} +
    • + {% if child.url %} + {{ child.title }} + {% else %} + {{ child.title }} + {% endif %} +
    • +
    • +
      +
    • + {% for subchild in child.children %} +
    • + {% if subchild.url %} + {{ subchild.title }} + {% else %} + {{ subchild.title }} + {% endif %} +
    • +
    • +
      +
    • + {% endfor %} + {% endfor %} + {% else %} +
    + {{ item.title }} +
      + {% endif %} {% endfor %} - {% else %} -
    - {{ item.title }} -
      - {% endif %} - {% endfor %}
    diff --git a/main/templates/base/site_header.html b/main/templates/base/site_header.html index ece9f41a6..aac33d38d 100644 --- a/main/templates/base/site_header.html +++ b/main/templates/base/site_header.html @@ -1,2 +1,3 @@ {% load i18n %} + {% trans "Portal FETC - Geesteswetenschappen" %} diff --git a/main/templates/base/site_html_head.html b/main/templates/base/site_html_head.html index 3fe174739..60501b7c9 100644 --- a/main/templates/base/site_html_head.html +++ b/main/templates/base/site_html_head.html @@ -1,6 +1,10 @@ {% load static %} - - - -{% include "base/form_styling.html" %} \ No newline at end of file + + + +{% include "base/form_styling.html" %} diff --git a/main/templates/base/site_title.html b/main/templates/base/site_title.html index 1cabe3998..53157f48e 100644 --- a/main/templates/base/site_title.html +++ b/main/templates/base/site_title.html @@ -1,2 +1,3 @@ {% load i18n %} -{% trans "FETC-GW" %} \ No newline at end of file + +{% trans "FETC-GW" %} diff --git a/main/templates/error/400.html b/main/templates/error/400.html index 411a66c16..8c24478a5 100644 --- a/main/templates/error/400.html +++ b/main/templates/error/400.html @@ -10,9 +10,9 @@

    {% trans 'Server error' %}

    - {% blocktrans trimmed %} - Er is een fout opgetreden tijdens het opvragen van deze pagina. - {% endblocktrans %} + {% blocktrans trimmed %} + Er is een fout opgetreden tijdens het opvragen van deze pagina. + {% endblocktrans %}

    {% blocktrans trimmed %} diff --git a/main/templates/error/403.html b/main/templates/error/403.html index 98556bca1..e680da6c4 100644 --- a/main/templates/error/403.html +++ b/main/templates/error/403.html @@ -5,23 +5,13 @@ {% block content %}

    -

    - {% trans 'Geen toegang' %} -

    -

    - {% trans 'Je hebt geen toegang tot de opgevraagde pagina.' %} -

    +

    {% trans 'Geen toegang' %}

    +

    {% trans 'Je hebt geen toegang tot de opgevraagde pagina.' %}

    {% if request.user.is_authenticated %} -

    - {% trans 'Dit kan meerdere oorzaken hebben:' %} -

    +

    {% trans 'Dit kan meerdere oorzaken hebben:' %}

      -
    • - {% trans 'Je hebt niet de benodigde rechten om deze pagina te bekijken;' %} -
    • -
    • - {% trans 'Je bent niet als mede-onderzoeker opgegeven voor deze aanvraag;' %} -
    • +
    • {% trans 'Je hebt niet de benodigde rechten om deze pagina te bekijken;' %}
    • +
    • {% trans 'Je bent niet als mede-onderzoeker opgegeven voor deze aanvraag;' %}
    • {% trans 'Je probeert een door jou eerder genomen beslissing aan te passen, maar de beoordelingsperiode is verstreken.' %}
    • @@ -30,7 +20,7 @@

      {% url 'login' as login_url %} {% blocktrans trimmed %} - Je bent niet ingelogd, probeer in te loggen. + Je bent niet ingelogd, probeer in te loggen. {% endblocktrans %}

      {% endif %} diff --git a/main/templates/error/403_csrf.html b/main/templates/error/403_csrf.html index a4188bb55..0afd99004 100644 --- a/main/templates/error/403_csrf.html +++ b/main/templates/error/403_csrf.html @@ -9,28 +9,16 @@ {% block content %}
      -

      - {% trans 'Verzoek kon niet geverifieerd worden' %} -

      -

      - {% trans 'Er is iets fout gegaan met het verifiëren van je browser.' %} -

      +

      {% trans 'Verzoek kon niet geverifieerd worden' %}

      +

      {% trans 'Er is iets fout gegaan met het verifiëren van je browser.' %}

      {% trans 'Dit kan meerdere oorzaken hebben, zoals het gebruik van een script- of ad-blocker, of je cookie-instellingen. Probeer eerst een volledige verversing van de pagina:' %}

        -
      • - {% trans 'Voor Chrome: ctrl + F5 (Windows) of cmd + shift + R (Mac)' %} -
      • -
      • - {% trans 'Voor Firefox: ctrl + shift + R (Windows) of cmd + shift + R (Mac)' %} -
      • -
      • - {% trans 'Voor Edge: ctrl + F5' %} -
      • -
      • - {% trans 'Voor Safari: option + cmnd + E' %} -
      • +
      • {% trans 'Voor Chrome: ctrl + F5 (Windows) of cmd + shift + R (Mac)' %}
      • +
      • {% trans 'Voor Firefox: ctrl + shift + R (Windows) of cmd + shift + R (Mac)' %}
      • +
      • {% trans 'Voor Edge: ctrl + F5' %}
      • +
      • {% trans 'Voor Safari: option + cmnd + E' %}

      {% blocktrans trimmed %} diff --git a/main/templates/error/404.html b/main/templates/error/404.html index 907a31191..58af97167 100644 --- a/main/templates/error/404.html +++ b/main/templates/error/404.html @@ -5,12 +5,8 @@ {% block content %}

      -

      - {% trans 'Pagina niet gevonden' %} -

      -

      - {% trans 'Sorry, deze pagina is helaas niet (meer) beschikbaar.' %} -

      +

      {% trans 'Pagina niet gevonden' %}

      +

      {% trans 'Sorry, deze pagina is helaas niet (meer) beschikbaar.' %}

      {% blocktrans trimmed %} Mogelijk ben je hier terechtgekomen via een verouderde of foutieve link. Graag vernemen wij welke diff --git a/main/templates/error/500.html b/main/templates/error/500.html index da7446a24..c28084678 100644 --- a/main/templates/error/500.html +++ b/main/templates/error/500.html @@ -5,9 +5,7 @@ {% block content %}

      -

      - {% trans 'Server error' %} -

      +

      {% trans 'Server error' %}

      {% blocktrans trimmed %} Er is een fout opgetreden tijdens het opvragen van deze pagina. diff --git a/main/templates/main/index.html b/main/templates/main/index.html index 768af10c6..10f923f63 100644 --- a/main/templates/main/index.html +++ b/main/templates/main/index.html @@ -18,7 +18,6 @@ {% blocktrans trimmed %} Deze portal is bedoeld voor medewerkers (en studenten) van de Faculteit Geesteswetenschappen. {% endblocktrans %} - {% if user.faculties.all %} {# Filters do not like blocktrans, so that value is just outside... #} {% blocktrans trimmed %} @@ -30,7 +29,6 @@ Volgens onze gegevens werk/studeer je bij een andere faculteit of dienst. {% endblocktrans %} {% endif %} - {% blocktrans trimmed %} Controleer of je inderdaad een aanvraag wilt indienen bij de Facultaire Ethische Toetsingscommissie van Geesteswetenschappen. {% endblocktrans %} @@ -52,44 +50,34 @@ {% endautoescape %}

      {% endfor %} -

      - {% trans "Startpagina" %} - {{ user.get_full_name }} -

      +

      {% trans "Startpagina" %} - {{ user.get_full_name }}

      -

      {% blocktrans trimmed %} - - Formele goedkeuring door één van beide kamers van de FETC-GW (middels een formele goedkeuringsbrief) is vereist voor mensgebonden onderzoek binnen de Faculteit Geesteswetenschappen. Voorafgaand aan het onderzoek, maar ook voorafgaand aan het rekruteren van deelnemers, moet de aanvraag zijn goedgekeurd. Het is dus van belang om te wachten met de aanvang van het onderzoek tot deze brief ontvangen is. - {% endblocktrans %} -

      +

      +

      {% blocktrans trimmed %} - - - NB: Goedgekeurde aanvragen komen in het archief van deze portal te staan, zie het menu hierboven. Dit archief is toegankelijk voor iedereen met een Solis-ID die bij de Faculteit Geesteswetenschappen werkt of studeert. - {% endblocktrans %} -

      +

      +

      {% blocktrans trimmed %} - Heb je een vraag over de werking van de portal, ontdek je een foutje, missende functionaliteit, of verkeerde vertaling? Neem dan contact op met portalsupport.gw@uu.nl. {% endblocktrans %} -

      -

      {% blocktrans trimmed %} In deze portal kan je het volgende doen: {% endblocktrans %}

      -
      +
      -
      - {% trans "Dien een nieuwe aanvraag in" %} -
      +
      {% trans "Dien een nieuwe aanvraag in" %}
      {# {% trans '(check de meest recente voorbeelddocumenten op intranet)' %}#}
      • @@ -140,9 +135,7 @@
      -
      - {% trans "Een aanvraag reviseren" %} -
      +
      {% trans "Een aanvraag reviseren" %}
      {# {% trans '(check de meest recente voorbeelddocumenten op intranet)' %}#}
      • @@ -156,9 +149,7 @@
      -
      - {% trans "Bekijk" %} -
      +
      {% trans "Bekijk" %}
      -
      - {% trans 'FETC-GW archief' %} -
      +
      {% trans 'FETC-GW archief' %}
      - - -
      - - -

      {% trans "Bannerfoto door Kim O'leary" %}

      - +
      + +
      +

      {% trans "Bannerfoto door Kim O'leary" %}

      +
      {% endblock %} diff --git a/main/templates/main/landing.html b/main/templates/main/landing.html index 1a5420bf7..3a61585ee 100644 --- a/main/templates/main/landing.html +++ b/main/templates/main/landing.html @@ -30,9 +30,7 @@ {# Very ugly imitation of uu-hero #}
      -

      - {% trans "Startpagina" %} -

      +

      {% trans "Startpagina" %}

      @@ -61,13 +59,15 @@

      {% trans 'Contact' %}

      - {% trans 'Secretaris FETC-GW' %}
      + {% trans 'Secretaris FETC-GW' %} +

      - {% trans 'Technische ondersteuning' %}
      + {% trans 'Technische ondersteuning' %} +
      @@ -82,15 +82,19 @@

      {% trans "Inloggen" %}

      {% endblocktrans %}

      {% if show_saml %} - - {% trans 'Log in met je Solis-ID' %}{% if login_descriptors %} (SAML){% endif %} + + {% trans 'Log in met je Solis-ID' %} + {% if login_descriptors %}(SAML){% endif %} {% endif %} {# Unnecessary layout hack #} {% if show_saml and show_django %}
      {% endif %} {% if show_django %} - - {% trans 'Log in met je Solis-ID' %}{% if login_descriptors %} (Non-SAML){% endif %} + + {% trans 'Log in met je Solis-ID' %} + {% if login_descriptors %}(Non-SAML){% endif %} {% endif %}
      diff --git a/main/templates/main/setting_checks.html b/main/templates/main/setting_checks.html index 2527c0bfc..6035230a7 100644 --- a/main/templates/main/setting_checks.html +++ b/main/templates/main/setting_checks.html @@ -12,4 +12,4 @@ } }); }); - \ No newline at end of file + diff --git a/main/templates/registration/logged_out.html b/main/templates/registration/logged_out.html index 724347283..f67b94eca 100644 --- a/main/templates/registration/logged_out.html +++ b/main/templates/registration/logged_out.html @@ -5,22 +5,18 @@ {% block content %}
      -

      - {% trans "Uitloggen" %} -

      -

      - {% trans "Je bent succesvol uitgelogd." %} -

      +

      {% trans "Uitloggen" %}

      +

      {% trans "Je bent succesvol uitgelogd." %}

      • {% url 'main:landing' as landing_url %} {% blocktrans trimmed %} - Klik hier om naar de startpagina te gaan. + Klik hier om naar de startpagina te gaan. {% endblocktrans %}
      • {% blocktrans trimmed %} - Klik hier om terug te keren naar de FETC-GW-website. + Klik hier om terug te keren naar de FETC-GW-website. {% endblocktrans %}
      diff --git a/main/templates/registration/login.html b/main/templates/registration/login.html index 6fe005bcb..846aa2fb0 100644 --- a/main/templates/registration/login.html +++ b/main/templates/registration/login.html @@ -11,24 +11,29 @@ {# Very ugly imitation of uu-hero #}
      -

      - {% trans "Inloggen" %} -

      +

      {% trans "Inloggen" %}

      {% if form.errors %} -

      - {% trans "Gebruikersnaam of wachtwoord incorrect. Probeer het alstublieft opnieuw." %} -

      +

      {% trans "Gebruikersnaam of wachtwoord incorrect. Probeer het alstublieft opnieuw." %}

      {% endif %} -

      - {% trans "Je kan hier inloggen met je Solis-ID en wachtwoord." %} -

      -
      {% csrf_token %} -
      -
      +

      {% trans "Je kan hier inloggen met je Solis-ID en wachtwoord." %}

      + + {% csrf_token %} + +
      + +
      diff --git a/main/templatetags/compare_tags.py b/main/templatetags/compare_tags.py index 4dc9fadfa..2b8eef841 100644 --- a/main/templatetags/compare_tags.py +++ b/main/templatetags/compare_tags.py @@ -10,8 +10,7 @@ class CompareLinkNode(template.Node): - - def __init__(self, type, obj, attribute=''): + def __init__(self, type, obj, attribute=""): self.type = type self.obj = template.Variable(obj) self.attribute = attribute @@ -22,19 +21,11 @@ def _get_documents_url(self, obj, proposal: Proposal): order=obj.study.order, ) # type: Study - args = [ - parent_study.documents.pk, - obj.pk, - self.attribute - ] + args = [parent_study.documents.pk, obj.pk, self.attribute] else: - old_set = proposal.parent.documents_set.filter( - study=None - ) - new_set = proposal.documents_set.filter( - study=None - ) + old_set = proposal.parent.documents_set.filter(study=None) + new_set = proposal.documents_set.filter(study=None) new_index = -1 for i, el in enumerate(new_set): if el.pk == obj.pk: @@ -45,13 +36,9 @@ def _get_documents_url(self, obj, proposal: Proposal): except (IndexError, AttributeError): return None - args = [ - old_obj, - obj.pk, - self.attribute - ] + args = [old_obj, obj.pk, self.attribute] - return reverse('proposals:compare_documents', args=args) + return reverse("proposals:compare_documents", args=args) def _get_observation_url(self, obj, proposal): order = obj.study.order @@ -61,37 +48,33 @@ def _get_observation_url(self, obj, proposal): return None if old_study.has_observation: - if not obj.approval_document or not \ - old_study.observation.approval_document: + if not obj.approval_document or not old_study.observation.approval_document: return None - args = [ - old_study.observation.pk, - obj.pk - ] + args = [old_study.observation.pk, obj.pk] - return reverse('proposals:compare_observation_approval', args=args) + return reverse("proposals:compare_observation_approval", args=args) return None def render(self, context): - "This function gets called when the template gets rendered" - + "This function gets called when the template gets rendered" + title = _("Toon verschillen") - img = get_static_file('proposals/images/arrow_divide.png') + img = get_static_file("proposals/images/arrow_divide.png") obj = self.obj.resolve(context) # Documents associated with a study # or extra Documents objects - if self.type == 'documents': + if self.type == "documents": proposal = obj.proposal if not proposal.parent: return "" url = self._get_documents_url(obj, proposal) - + # Observations, possibly unused - elif self.type == 'observation': + elif self.type == "observation": proposal = obj.study.proposal if not proposal.parent: return "" @@ -99,7 +82,7 @@ def render(self, context): url = self._get_observation_url(obj, proposal) # General proposal docs - elif self.type == 'proposal': + elif self.type == "proposal": if not obj.parent: return "" @@ -109,10 +92,10 @@ def render(self, context): self.attribute, ] - url = reverse('proposals:compare_proposal_docs', args=args) - + url = reverse("proposals:compare_proposal_docs", args=args) + # METC Decision files - elif self.type == 'wmo': + elif self.type == "wmo": if not obj.proposal.parent or not obj.proposal.parent.wmo: return "" @@ -121,19 +104,21 @@ def render(self, context): obj.pk, ] - url = reverse('proposals:compare_wmo_decision', args=args) + url = reverse("proposals:compare_wmo_decision", args=args) else: return "" if url is None: return "" - return '' \ - '' \ - ''.format( - url=url, - img=img, - title=title, + return ( + '' + '' + "".format( + url=url, + img=img, + title=title, + ) ) @@ -141,7 +126,7 @@ def render(self, context): def get_compare_link(parser, token): """This function splits up the arguments given inside the tag and passes them on to the CompareLinkNode class""" - + parts = token.split_contents() if not (3 <= len(parts) < 5): @@ -151,11 +136,11 @@ def get_compare_link(parser, token): ) args = { - 'type': parts[1], - 'obj': parts[2], + "type": parts[1], + "obj": parts[2], } if len(parts) == 4: - args['attribute'] = parts[3] + args["attribute"] = parts[3] return CompareLinkNode(**args) diff --git a/main/templatetags/fetc_filters.py b/main/templatetags/fetc_filters.py index 340351339..99a4cd197 100644 --- a/main/templatetags/fetc_filters.py +++ b/main/templatetags/fetc_filters.py @@ -5,13 +5,27 @@ register = template.Library() +def is_in_groups(current_user, groups): + """ + Check whether the current user is in specific groups, specified in the + groups argument, like eg.: + + groups = [settings.GROUP_SECRETARY, settings.GROUP_CHAIR] + """ + user_groups = current_user.groups.all() + group_objects = [Group.objects.get(name=group) for group in groups] + + return any(group in user_groups for group in group_objects) + + @register.filter def in_linguistics_chamber(current_user): """ Check whether the current user is in the 'ETCL' or 'Secretaris' group """ - return Group.objects.get(name=settings.GROUP_LINGUISTICS_CHAMBER) in current_user.groups.all() or \ - Group.objects.get(name=settings.GROUP_SECRETARY) in current_user.groups.all() + return is_in_groups( + current_user, [settings.GROUP_LINGUISTICS_CHAMBER, settings.GROUP_SECRETARY] + ) @register.filter @@ -19,8 +33,9 @@ def in_general_chamber(current_user): """ Check whether the current user is in the 'FETC' or 'Secretaris' group """ - return Group.objects.get(name=settings.GROUP_GENERAL_CHAMBER) in current_user.groups.all() or \ - Group.objects.get(name=settings.GROUP_SECRETARY) in current_user.groups.all() + return is_in_groups( + current_user, [settings.GROUP_GENERAL_CHAMBER, settings.GROUP_SECRETARY] + ) @register.filter @@ -28,4 +43,24 @@ def is_secretary(current_user): """ Check whether the current user is in the 'Secretary' group """ - return Group.objects.get(name=settings.GROUP_SECRETARY) in current_user.groups.all() + return is_in_groups(current_user, [settings.GROUP_SECRETARY]) + + +@register.filter +def is_chair_or_secretary(current_user): + """ + Check whether the current user is in the 'Secretary' or 'Chair' group + """ + return is_in_groups(current_user, [settings.GROUP_SECRETARY, settings.GROUP_CHAIR]) + + +@register.filter +def is_po_chair_or_secretary(current_user): + """ + Check whether the current user is in the 'Secretary', 'Privacy officer' + or 'Chair' group + """ + return is_in_groups( + current_user, + [settings.GROUP_SECRETARY, settings.GROUP_CHAIR, settings.GROUP_PO], + ) diff --git a/main/tests.py b/main/tests.py index c9167491d..acca230a0 100644 --- a/main/tests.py +++ b/main/tests.py @@ -1,25 +1,88 @@ -from django.core.exceptions import ValidationError +from django.core.exceptions import ValidationError, PermissionDenied from django.db import models -from django.test import TestCase +from django.test import TestCase, RequestFactory, Client +from django.contrib.auth.models import AnonymousUser from .models import Setting from .utils import is_empty from .validators import MaxWordsValidator +class BaseViewTestCase: + """ + Inherit from this class to test the functioning of + class-based views. + """ + + # This testcase supports only class-based views + view_class = None + + # for example: + # "/proposals/update/1/" + # NOT a full URL including protocol and domain + view_path = None + + allowed_users = [] + disallowed_users = [AnonymousUser] + enforce_csrf = True + + def setUp(self): + self.client = Client() + self.view = self.view_class.as_view() + self.factory = RequestFactory() + super().setUp() + + def check_access(self, user): + request = self.factory.get( + self.get_view_path(), + ) + request.user = user + try: + response = self.view(request, **self.get_view_args()) + except PermissionDenied: + return False + return response.status_code == 200 + + def post(self, update_dict={}, user=AnonymousUser): + """Generic function to test form submission""" + post_data = {} + post_data.update(update_dict) + if self.enforce_csrf: + csrf_token = self.fetch_csrf_token( + user=user, + ) + post_data["csrfmiddlewaretoken"] = csrf_token + response = self.client.post( + self.get_view_path(), + data=post_data, + ) + return response + + def fetch_csrf_token(self, user=None): + if user: + self.client.force_login(user) + page = self.client.get( + self.get_view_path(), + ) + return page.context["csrf_token"] + + def get_view_path(self): + return self.view_path + + class ValidatorTest(TestCase): def test_max_words_validator(self): class Mock(models.Model): test = models.TextField(validators=[MaxWordsValidator(5)]) try: - m = Mock(test='Dit is een test') + m = Mock(test="Dit is een test") m.full_clean() except ValidationError: self.fail() with self.assertRaises(ValidationError): - m = Mock(test='Dit is een test die faalt') + m = Mock(test="Dit is een test die faalt") m.full_clean() @@ -31,8 +94,8 @@ def test_is_empty(self): self.assertTrue(is_empty([])) self.assertTrue(is_empty(Setting.objects.none())) - self.assertFalse(is_empty([''])) + self.assertFalse(is_empty([""])) - self.assertTrue(is_empty(u'')) - self.assertTrue(is_empty(u' ')) - self.assertFalse(is_empty(u' test ')) + self.assertTrue(is_empty("")) + self.assertTrue(is_empty(" ")) + self.assertFalse(is_empty(" test ")) diff --git a/main/translation.py b/main/translation.py index 12b368e84..ac55fa97f 100644 --- a/main/translation.py +++ b/main/translation.py @@ -5,14 +5,14 @@ @register(Setting) class SettingTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) @register(SystemMessage) class SystemMessageTranslationOptions(TranslationOptions): - fields = ('message',) + fields = ("message",) @register(Faculty) class FacultyTranslationOptions(TranslationOptions): - fields = ('name',) + fields = ("name",) diff --git a/main/urls.py b/main/urls.py index d6e50ca36..b6096086a 100644 --- a/main/urls.py +++ b/main/urls.py @@ -1,21 +1,17 @@ from django.urls import path -from .views import HomeView, LandingView, check_requires, UserSearchView, \ - UserDetailView +from .views import HomeView, LandingView, check_requires, UserSearchView, UserDetailView -app_name = 'main' +app_name = "main" urlpatterns = [ # Home - path('', HomeView.as_view(), name='home'), - path('landing/', LandingView.as_view(), name='landing'), - + path("", HomeView.as_view(), name="home"), + path("landing/", LandingView.as_view(), name="landing"), # User detail page - path('user//', UserDetailView.as_view(), name='user_detail'), - + path("user//", UserDetailView.as_view(), name="user_detail"), # User search - path('user_search/', UserSearchView.as_view(), name='user_search'), - + path("user_search/", UserSearchView.as_view(), name="user_search"), # Checks on conditional fields - path('check_requires/', check_requires, name='check_requires'), + path("check_requires/", check_requires, name="check_requires"), ] diff --git a/main/utils.py b/main/utils.py index e1d79de76..d03c1bda9 100644 --- a/main/utils.py +++ b/main/utils.py @@ -11,8 +11,9 @@ from docx2txt import docx2txt from main.models import Faculty +from fetc import constants -YES_NO = [(True, _('ja')), (False, _('nee'))] +YES_NO = [(True, _("ja")), (False, _("nee"))] class AvailableURL(object): @@ -31,52 +32,58 @@ def get_secretary(): """ Returns the Head secretary. We limit this to one user. """ - obj = get_user_model().objects.filter(groups__name=settings.GROUP_PRIMARY_SECRETARY).first() + obj = ( + get_user_model() + .objects.filter(groups__name=settings.GROUP_PRIMARY_SECRETARY) + .first() + ) obj.email = settings.EMAIL_FROM return obj + def get_all_secretaries(): """ Return all users in the 'Secretary' group. """ return get_user_model().objects.filter(groups__name=settings.GROUP_SECRETARY).all() + def is_secretary(user): """ Check whether the current user is in the 'Secretary' group. """ return Group.objects.get(name=settings.GROUP_SECRETARY) in user.groups.all() + def get_reviewers(): return get_user_model().objects.filter( - Q(groups__name=settings.GROUP_GENERAL_CHAMBER) | - Q(groups__name=settings.GROUP_LINGUISTICS_CHAMBER) + Q(groups__name=settings.GROUP_GENERAL_CHAMBER) + | Q(groups__name=settings.GROUP_LINGUISTICS_CHAMBER) ) def get_reviewers_from_group(group): - return get_user_model().objects.filter( - groups__name=group - ) + return get_user_model().objects.filter(groups__name=group) def get_reviewers_from_groups(groups): - return get_user_model().objects.filter( - groups__name__in=groups - ).distinct() + return get_user_model().objects.filter(groups__name__in=groups).distinct() def string_to_bool(s): - if s == 'None' or s is None: + if s == "None" or s is None: return False - return s not in ['False', 'false', '0', 0] + return s not in ["False", "false", "0", 0] def get_users_as_list(users): """ Retrieves all Users as a list. """ - return [(user.pk, u'{}: {}'.format(user.username, user.get_full_name())) for user in users] + return [ + (user.pk, "{}: {}".format(user.username, user.get_full_name())) + for user in users + ] def is_empty(value): @@ -87,7 +94,7 @@ def is_empty(value): result = False if value is None: result = True - if hasattr(value, '__len__') and len(value) == 0: + if hasattr(value, "__len__") and len(value) == 0: result = True if isinstance(value, str) and not value.strip(): result = True @@ -102,51 +109,23 @@ def get_document_contents(file: FieldFile) -> str: if file is None: return "" - mime = magic.from_buffer(file.open(mode='rb').read(2048), mime=True) + mime = magic.from_buffer(file.open(mode="rb").read(2048), mime=True) - if mime == 'application/pdf': + if mime == "application/pdf": with file.open(mode="rb") as f: pdf = pdftotext.PDF(f) return "\n\n".join(pdf) - if mime == 'application/octet-stream': + if mime == "application/octet-stream": # This _might_ not be a DocX, but as we only allow PDF and DocX we # know it should be fine with file.open(mode="rb") as f: return docx2txt.process(f) - if mime == 'application/vnd.openxmlformats-officedocument' \ - '.wordprocessingml.document': - with file.open(mode="rb") as f: - return docx2txt.process(f) - - return "No text found" - - -def get_static_file(file): - return staticfiles_storage.url(file) - - -def get_document_contents(file: FieldFile) -> str: - if file is None: - return "" - - mime = magic.from_buffer(file.open(mode='rb').read(2048), mime=True) - - if mime == 'application/pdf': - with file.open(mode="rb") as f: - pdf = pdftotext.PDF(f) - return "\n\n".join(pdf) - - if mime == 'application/octet-stream': - # This _might_ not be a DocX, but as we only allow PDF and DocX we - # know it should be fine - with file.open(mode="rb") as f: - return docx2txt.process(f) - - if mime == 'application/vnd.openxmlformats-officedocument' \ - '.wordprocessingml.document' or \ - mime == 'application/msword': + if ( + mime == "application/vnd.openxmlformats-officedocument" + ".wordprocessingml.document" + ): with file.open(mode="rb") as f: return docx2txt.process(f) @@ -159,3 +138,27 @@ def is_member_of_faculty(user, faculty): def is_member_of_humanities(user): return is_member_of_faculty(user, Faculty.InternalNames.HUMANITIES) + + +def can_view_archive(user): + if not user.is_authenticated: + return False + if user.is_superuser: + return True + privileged_groups = [ + constants.GROUP_CHAIR, + constants.GROUP_GENERAL_CHAMBER, + constants.GROUP_LINGUISTICS_CHAMBER, + constants.GROUP_SECRETARY, + constants.GROUP_PRIMARY_SECRETARY, + ] + user_groups = user.groups.values_list( + "name", + flat=True, + ) + for group in user_groups: + if group in privileged_groups: + return True + # If our tests are inconclusive, + # check for Humanities affiliation + return is_member_of_humanities(user) diff --git a/main/validators.py b/main/validators.py index c4caf2283..fbaf07f31 100644 --- a/main/validators.py +++ b/main/validators.py @@ -3,21 +3,27 @@ from django.core.validators import BaseValidator from django.utils.translation import ugettext_lazy, ungettext_lazy -ALLOWED_CONTENT_TYPES = ['application/pdf', 'application/msword', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'] +ALLOWED_CONTENT_TYPES = [ + "application/pdf", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", +] class MaxWordsValidator(BaseValidator): compare = lambda self, a, b: a > b clean = lambda self, x: len(x.split()) message = ungettext_lazy( - 'Dit veld mag maximaal %(limit_value)d woord bevatten.', - 'Dit veld mag maximaal %(limit_value)d woorden bevatten.', - 'limit_value') - code = 'max_words' + "Dit veld mag maximaal %(limit_value)d woord bevatten.", + "Dit veld mag maximaal %(limit_value)d woorden bevatten.", + "limit_value", + ) + code = "max_words" def validate_pdf_or_doc(value): f = value.file if isinstance(f, UploadedFile) and f.content_type not in ALLOWED_CONTENT_TYPES: - raise ValidationError(ugettext_lazy('Alleen .pdf- of .doc(x)-bestanden zijn toegestaan.')) + raise ValidationError( + ugettext_lazy("Alleen .pdf- of .doc(x)-bestanden zijn toegestaan.") + ) diff --git a/main/views.py b/main/views.py index 0a4a89c16..488060f9b 100644 --- a/main/views.py +++ b/main/views.py @@ -4,7 +4,7 @@ import ldap import os -from braces.views import LoginRequiredMixin, GroupRequiredMixin +from braces.views import LoginRequiredMixin, GroupRequiredMixin, UserPassesTestMixin from django.apps import apps from django.conf import settings from django.contrib import messages @@ -14,8 +14,13 @@ from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.db.models import Q from django.forms import modelformset_factory -from django.http import HttpResponseRedirect, JsonResponse, FileResponse, \ - Http404, QueryDict +from django.http import ( + HttpResponseRedirect, + JsonResponse, + FileResponse, + Http404, + QueryDict, +) from django.shortcuts import render from django.urls import reverse from django.utils import timezone @@ -26,7 +31,7 @@ from interventions.models import Intervention from main.models import Faculty, SystemMessage -from main.utils import is_member_of_humanities +from main.utils import is_member_of_humanities, can_view_archive from observations.models import Observation from proposals.models import Proposal from reviews.models import Review @@ -35,8 +40,9 @@ try: # This will trigger an exception if LDAP is not configured from fetc.ldap_settings import * + LDAP_CONFIGURED = True -except (ImportError): +except ImportError: LDAP_CONFIGURED = False @@ -48,46 +54,41 @@ class _SystemMessageView(generic.ListView): def get_queryset(self): now = timezone.now() - return self.model.objects.filter( - not_after__gt=now, - not_before__lt=now - ) + return self.model.objects.filter(not_after__gt=now, not_before__lt=now) class HomeView(LoginRequiredMixin, _SystemMessageView): - template_name = 'main/index.html' + template_name = "main/index.html" def no_permissions_fail(self, request=None): """ Overrides normal permission fail to redirect to landing instead of directly to login """ - resolved_url = reverse('main:landing') + resolved_url = reverse("main:landing") return HttpResponseRedirect(f"{resolved_url}?next=/") def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) - context['is_humanities'] = is_member_of_humanities(self.request.user) + context["is_humanities"] = is_member_of_humanities(self.request.user) return context + class LandingView(_SystemMessageView): - template_name = 'main/landing.html' + template_name = "main/landing.html" model = SystemMessage def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) - context['next'] = self.request.GET.get( - 'next', - settings.LOGIN_REDIRECT_URL - ) - context['saml'] = hasattr(settings, 'SAML_CONFIG') - context['show_saml'] = settings.SHOW_SAML_LOGIN - context['show_django'] = settings.SHOW_DJANGO_LOGIN - context['login_descriptors'] = settings.SHOW_LOGIN_DESCRIPTORS + context["next"] = self.request.GET.get("next", settings.LOGIN_REDIRECT_URL) + context["saml"] = hasattr(settings, "SAML_CONFIG") + context["show_saml"] = settings.SHOW_SAML_LOGIN + context["show_django"] = settings.SHOW_DJANGO_LOGIN + context["login_descriptors"] = settings.SHOW_LOGIN_DESCRIPTORS return context @@ -99,12 +100,12 @@ class UserDetailView(GroupRequiredMixin, generic.DetailView): settings.GROUP_GENERAL_CHAMBER, ] model = get_user_model() - context_object_name = 'user_object' + context_object_name = "user_object" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['reviews'] = self.get_user_reviews() + context["reviews"] = self.get_user_reviews() return context @@ -112,9 +113,9 @@ def get_user_reviews(self): """Returns all Committee Reviews of this user""" reviews = {} objects = Review.objects.filter( - stage__gte=Review.ASSIGNMENT, - proposal__status__gte=Proposal.SUBMITTED, - proposal__created_by=self.get_object() + stage__gte=Review.Stages.ASSIGNMENT, + proposal__status__gte=Proposal.Statuses.SUBMITTED, + proposal__created_by=self.get_object(), ) for obj in objects: @@ -136,15 +137,14 @@ def check_requires(request): """ This call checks whether a certain value requires another input to be filled. """ - values = map(int, request.POST.getlist('value[]')) - model = apps.get_model(request.POST.get('app'), request.POST.get('model')) - required_values = model.objects.filter(**{ - request.POST.get('field'): True - }).values_list('id', flat=True) + values = map(int, request.POST.getlist("value[]")) + model = apps.get_model(request.POST.get("app"), request.POST.get("model")) + required_values = model.objects.filter( + **{request.POST.get("field"): True} + ).values_list("id", flat=True) result = bool(set(required_values).intersection(values)) - return JsonResponse({ - 'result': result - }) + return JsonResponse({"result": result}) + def establish_ldap_connection(): # We set up a custom LDAP connection here, separate from the Django auth one @@ -159,6 +159,7 @@ def establish_ldap_connection(): # Raised if there was a problem connecting to LDAP return None + def user_search(query, page): """ This function searches through users for a given query. Page 1 will return registered users, or if there are none, @@ -172,18 +173,20 @@ def user_search(query, page): users = [] # If we have a wildcard or an empty query, we just show all users - if query == u'*' or query == u'': + if query == "*" or query == "": users = format_user_info(User.objects.all()) - elif page == u'1': + elif page == "1": # Otherwise we search through the users with a given query data = User.objects.filter( - Q(username__icontains=query) | Q(first_name__icontains=query) | Q( - last_name__icontains=query)) + Q(username__icontains=query) + | Q(first_name__icontains=query) + | Q(last_name__icontains=query) + ) users = format_user_info(data) # We need results from the LDAP if either, this is page 2, or page 1 has no results for now # We put this in a variable because we're going to reuse this later on - ldap_results_needed = (page == u'2' or len(users) == 0) + ldap_results_needed = page == "2" or len(users) == 0 # Attempt to establish LDAP connection ldap_connection = establish_ldap_connection() @@ -193,40 +196,35 @@ def user_search(query, page): # Start the LDAP search ldap_query = escape_ldap_input(query) msgid = ldap_connection.search( - 'ou=People,dc=uu,dc=nl', + "ou=People,dc=uu,dc=nl", ldap.SCOPE_SUBTREE, - filterstr='(|(humAchternaam=*{}*)(uid=*{}*)(givenName=*{}*)(displayName=*{}*))'.format( - ldap_query, - ldap_query, - ldap_query, - ldap_query - ) + filterstr="(|(humAchternaam=*{}*)(uid=*{}*)(givenName=*{}*)(displayName=*{}*))".format( + ldap_query, ldap_query, ldap_query, ldap_query + ), ) # Get results and loop over them for _, data in ldap_connection.result(msgid)[1]: # Add them to the users, with a ldap_ prefix in the ID so we can distinguish this when processing the form - users.append({ - 'id': 'ldap_' + data.get('uid')[0].decode("utf-8"), - 'text': '{}: {}'.format(data.get('uid')[0].decode("utf-8"), - data.get('displayName')[0].decode( - "utf-8")) - }) + users.append( + { + "id": "ldap_" + data.get("uid")[0].decode("utf-8"), + "text": "{}: {}".format( + data.get("uid")[0].decode("utf-8"), + data.get("displayName")[0].decode("utf-8"), + ), + } + ) # Paging-more should be true if there are no LDAP results included in this page, the LDAP is available and # the query is not a wildcard - paging_more = not ldap_results_needed and ldap_connection and query != '*' + paging_more = not ldap_results_needed and ldap_connection and query != "*" # Unbind the ldap connection after we are done with it if ldap_connection: ldap_connection.unbind() # Return a formatted dict with the results - return { - 'results': users, - 'pagination': { - 'more': paging_more - } - } + return {"results": users, "pagination": {"more": paging_more}} def escape_ldap_input(string): @@ -239,17 +237,17 @@ def escape_ldap_input(string): :return string: The escaped string """ escape_vals = { - '\\': r'\5c', - r'(': r'\28', - r'|': r'\7c', - r'<': r'\3c', - r'/': r'\2f', - r')': r'\29', - r'=': r'\3d', - r'~': r'\7e', - r'&': r'\26', - r'>': r'\3e', - r'*': r'\2a' + "\\": r"\5c", + r"(": r"\28", + r"|": r"\7c", + r"<": r"\3c", + r"/": r"\2f", + r")": r"\29", + r"=": r"\3d", + r"~": r"\7e", + r"&": r"\26", + r">": r"\3e", + r"*": r"\2a", } for x, y in escape_vals.items(): @@ -260,20 +258,19 @@ def escape_ldap_input(string): def format_user_info(lst): """This will format a user object into a displayable format""" - return [{ - 'id': x.pk, - 'text': u'{}: {}'.format(x.username, x.get_full_name()) - } for x in lst] + return [ + {"id": x.pk, "text": "{}: {}".format(x.username, x.get_full_name())} + for x in lst + ] class UserSearchView(LoginRequiredMixin, generic.View): - def render_to_response(self, context, *args, **kwargs): return JsonResponse(context, *args, **kwargs) def get(self, *args, **kwargs): - query = self.request.GET.get('q') - page = self.request.GET.get('page') + query = self.request.GET.get("q") + page = self.request.GET.get("page") context = user_search(query, page) return self.render_to_response(context) @@ -287,21 +284,21 @@ def form_invalid(self, form): """ On back button, allow form to have errors. """ - if 'save_back' in self.request.POST: + if "save_back" in self.request.POST: return HttpResponseRedirect(self.get_back_url()) else: return super(AllowErrorsOnBackbuttonMixin, self).form_invalid(form) -class FacultyRequiredMixin: +class FacultyRequiredMixin(UserPassesTestMixin): """A clone of GroupRequiredMixin, but checking faculties instead""" + faculty_required = None def get_faculty_required(self): if self.faculty_required is None or ( not isinstance(self.faculty_required, (list, tuple, str)) ): - raise ImproperlyConfigured( '{0} requires the "faculty_required" attribute to be set and be ' "one of the following types: string, unicode, list or " @@ -314,29 +311,31 @@ def get_faculty_required(self): def check_membership(self, faculty): """Check required faculty(ies)""" user_faculties = self.request.user.faculties.values_list( - "internal_name", - flat=True + "internal_name", flat=True ) return set(faculty).intersection(set(user_faculties)) - def dispatch(self, request, *args, **kwargs): - self.request = request + def test_func(self, user): in_faculty = False - if request.user.is_authenticated: + if user.is_authenticated: in_faculty = self.check_membership(self.get_faculty_required()) - - if not in_faculty: - return self.handle_no_permission(request) - - return super().dispatch( - request, *args, **kwargs - ) + return in_faculty class HumanitiesRequiredMixin(FacultyRequiredMixin): faculty_required = Faculty.InternalNames.HUMANITIES +class HumanitiesOrPrivilegeRequiredMixin(UserPassesTestMixin): + """ + Checks for Humanities faculty affiliation, but also lets in users belonging + to a privileged set of groups. + """ + + def test_func(self, user): + return can_view_archive(user) + + class UserAllowedMixin(SingleObjectMixin): def get_object(self, queryset=None): """ @@ -352,9 +351,11 @@ def get_object(self, queryset=None): if isinstance(obj, Proposal): proposal = obj - elif isinstance(obj, Observation) or isinstance(obj, - Intervention) or isinstance( - obj, Session): + elif ( + isinstance(obj, Observation) + or isinstance(obj, Intervention) + or isinstance(obj, Session) + ): proposal = obj.study.proposal elif isinstance(obj, Task): proposal = obj.session.study.proposal @@ -363,22 +364,25 @@ def get_object(self, queryset=None): applicants = proposal.applicants.all() if proposal.supervisor: - supervisor = get_user_model().objects.filter( - pk=proposal.supervisor.pk) + supervisor = get_user_model().objects.filter(pk=proposal.supervisor.pk) else: supervisor = get_user_model().objects.none() - commission = get_user_model().objects.filter(groups__name=settings.GROUP_SECRETARY) + commission = get_user_model().objects.filter( + groups__name=settings.GROUP_SECRETARY + ) if proposal.reviewing_committee.name == settings.GROUP_LINGUISTICS_CHAMBER: commission |= get_user_model().objects.filter( - groups__name=settings.GROUP_LINGUISTICS_CHAMBER) + groups__name=settings.GROUP_LINGUISTICS_CHAMBER + ) if proposal.reviewing_committee.name == settings.GROUP_GENERAL_CHAMBER: commission |= get_user_model().objects.filter( - groups__name=settings.GROUP_GENERAL_CHAMBER) + groups__name=settings.GROUP_GENERAL_CHAMBER + ) - if proposal.status >= Proposal.SUBMITTED: + if proposal.status >= Proposal.Statuses.SUBMITTED: if self.request.user not in commission: raise PermissionDenied - elif proposal.status >= Proposal.SUBMITTED_TO_SUPERVISOR: + elif proposal.status >= Proposal.Statuses.SUBMITTED_TO_SUPERVISOR: if self.request.user not in supervisor: raise PermissionDenied else: @@ -389,7 +393,6 @@ def get_object(self, queryset=None): class FormSetUserAllowedMixin(UserAllowedMixin): - def check_allowed(self): """ Allows access to a proposal based on the status of a Proposal @@ -402,12 +405,13 @@ def check_allowed(self): """ for obj in self.objects: - if isinstance(obj, Proposal): proposal = obj - elif isinstance(obj, Observation) or isinstance(obj, - Intervention) or isinstance( - obj, Session): + elif ( + isinstance(obj, Observation) + or isinstance(obj, Intervention) + or isinstance(obj, Session) + ): proposal = obj.study.proposal elif isinstance(obj, Task): proposal = obj.session.study.proposal @@ -416,11 +420,12 @@ def check_allowed(self): applicants = proposal.applicants.all() if proposal.supervisor: - supervisor = get_user_model().objects.filter( - pk=proposal.supervisor.pk) + supervisor = get_user_model().objects.filter(pk=proposal.supervisor.pk) else: supervisor = get_user_model().objects.none() - commission = get_user_model().objects.filter(groups__name=settings.GROUP_SECRETARY) + commission = get_user_model().objects.filter( + groups__name=settings.GROUP_SECRETARY + ) if proposal.reviewing_committee.name == settings.GROUP_LINGUISTICS_CHAMBER: commission |= get_user_model().objects.filter( @@ -432,10 +437,10 @@ def check_allowed(self): groups__name=settings.GROUP_GENERAL_CHAMBER ) - if proposal.status >= Proposal.SUBMITTED: + if proposal.status >= Proposal.Statuses.SUBMITTED: if self.request.user not in commission: raise PermissionDenied - elif proposal.status >= Proposal.SUBMITTED_TO_SUPERVISOR: + elif proposal.status >= Proposal.Statuses.SUBMITTED_TO_SUPERVISOR: if self.request.user not in supervisor: raise PermissionDenied else: @@ -452,8 +457,9 @@ def get_success_url(self): return success_url(self) -class UpdateView(LoginRequiredMixin, SuccessMessageMixin, UserAllowedMixin, - generic.UpdateView): +class UpdateView( + LoginRequiredMixin, SuccessMessageMixin, UserAllowedMixin, generic.UpdateView +): """Generic update view including success message, user allowed and login required mixins""" @@ -462,11 +468,13 @@ def get_success_url(self): return success_url(self) -class FormSetUpdateView(FormSetUserAllowedMixin, LoginRequiredMixin, - SuccessMessageMixin, generic.View): - """ Generic update view that uses a formset. This allows you to edit +class FormSetUpdateView( + FormSetUserAllowedMixin, LoginRequiredMixin, SuccessMessageMixin, generic.View +): + """Generic update view that uses a formset. This allows you to edit multiple forms of the same type on the same page. """ + form = None _formset = None queryset = None @@ -479,15 +487,15 @@ def get(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): self._on_request() - formset = self._formset(request.POST, request.FILES, - queryset=self.objects) + formset = self._formset(request.POST, request.FILES, queryset=self.objects) self.pre_validation(formset) if formset.is_valid(): self.save_form(formset) return HttpResponseRedirect(self.get_success_url()) else: - return render(request, self.template_name, - self.get_context_data(formset=formset)) + return render( + request, self.template_name, self.get_context_data(formset=formset) + ) def pre_validation(self, formset): """This method can be overridden to manipulate the formset before @@ -498,16 +506,17 @@ def save_form(self, formset): formset.save() def _on_request(self): - self._formset = modelformset_factory(self.form._meta.model, - form=self.form, extra=self.extra) + self._formset = modelformset_factory( + self.form._meta.model, form=self.form, extra=self.extra + ) self.objects = self.get_queryset() self.check_allowed() def get_queryset(self): if self.queryset is None: raise ImproperlyConfigured( - "Either override get_queryset, or provide a queryset class " - "variable") + "Either override get_queryset, or provide a queryset class " "variable" + ) return self.queryset @@ -516,13 +525,13 @@ def get_success_url(self): return success_url(self) def get_context_data(self, **kwargs): - if 'view' not in kwargs: - kwargs['view'] = self + if "view" not in kwargs: + kwargs["view"] = self - kwargs['objects'] = self.objects + kwargs["objects"] = self.objects - if 'formset' not in kwargs: - kwargs['formset'] = self._formset(queryset=self.objects) + if "formset" not in kwargs: + kwargs["formset"] = self._formset(queryset=self.objects) return kwargs @@ -544,9 +553,7 @@ class UserMediaView(LoginRequiredMixin, generic.View): def get_response_path(self, filename): """Make sure the requested filename exists within MEDIA_ROOT, to prevent upwards directory traversal.""" - media_root = os.path.realpath( - settings.MEDIA_ROOT - ) + media_root = os.path.realpath(settings.MEDIA_ROOT) filepath = os.path.realpath( os.path.join(media_root, filename), ) @@ -572,12 +579,11 @@ def get(self, request, filename): def success_url(self): - if 'next' in self.request.GET: - return self.request.GET['next'] - if 'save_continue' in self.request.POST: + if "next" in self.request.GET: + return self.request.GET["next"] + if "save_continue" in self.request.POST: return self.get_next_url() - if 'save_back' in self.request.POST: + if "save_back" in self.request.POST: return self.get_back_url() else: - return reverse('proposals:my_concepts') - + return reverse("proposals:my_concepts") diff --git a/observations/admin.py b/observations/admin.py index 9fedbde04..55a93297e 100644 --- a/observations/admin.py +++ b/observations/admin.py @@ -5,6 +5,6 @@ @admin.register(Registration) class RegistrationAdmin(admin.ModelAdmin): - list_display = ('order', 'description', 'needs_details', 'requires_review') - list_display_links = ('description', ) - ordering = ['order'] + list_display = ("order", "description", "needs_details", "requires_review") + list_display_links = ("description",) + ordering = ["order"] diff --git a/observations/forms.py b/observations/forms.py index dc4b0bf1b..ef33d5670 100644 --- a/observations/forms.py +++ b/observations/forms.py @@ -12,24 +12,36 @@ class ObservationForm(SoftValidationMixin, ConditionalModelForm): class Meta: model = Observation fields = [ - 'setting', 'setting_details', 'supervision', 'leader_has_coc', - 'details_who', 'details_why', 'details_frequency', - 'is_anonymous', 'is_anonymous_details', 'is_in_target_group', - 'is_in_target_group_details', 'is_nonpublic_space', 'is_nonpublic_space_details', - 'has_advanced_consent', 'has_advanced_consent_details', - 'needs_approval', 'approval_institution', - 'registrations', 'registrations_details', + "setting", + "setting_details", + "supervision", + "leader_has_coc", + "details_who", + "details_why", + "details_frequency", + "is_anonymous", + "is_anonymous_details", + "is_in_target_group", + "is_in_target_group_details", + "is_nonpublic_space", + "is_nonpublic_space_details", + "has_advanced_consent", + "has_advanced_consent_details", + "needs_approval", + "approval_institution", + "registrations", + "registrations_details", ] widgets = { - 'setting': forms.CheckboxSelectMultiple(), - 'supervision': forms.RadioSelect(choices=YES_NO), - 'leader_has_coc': forms.RadioSelect(choices=YES_NO), - 'is_anonymous': forms.RadioSelect(choices=YES_NO), - 'is_in_target_group': forms.RadioSelect(choices=YES_NO), - 'is_nonpublic_space': forms.RadioSelect(choices=YES_NO), - 'has_advanced_consent': forms.RadioSelect(choices=YES_NO), - 'needs_approval': forms.RadioSelect(choices=YES_NO), - 'registrations': forms.CheckboxSelectMultiple(), + "setting": forms.CheckboxSelectMultiple(), + "supervision": forms.RadioSelect(choices=YES_NO), + "leader_has_coc": forms.RadioSelect(choices=YES_NO), + "is_anonymous": forms.RadioSelect(choices=YES_NO), + "is_in_target_group": forms.RadioSelect(choices=YES_NO), + "is_nonpublic_space": forms.RadioSelect(choices=YES_NO), + "has_advanced_consent": forms.RadioSelect(choices=YES_NO), + "needs_approval": forms.RadioSelect(choices=YES_NO), + "registrations": forms.CheckboxSelectMultiple(), } def __init__(self, *args, **kwargs): @@ -37,18 +49,19 @@ def __init__(self, *args, **kwargs): - Set the Study for later reference - Don't ask the supervision question when there are only adult AgeGroups in this Study """ - self.study = kwargs.pop('study', None) + self.study = kwargs.pop("study", None) super(ObservationForm, self).__init__(*args, **kwargs) - self.fields['details_who'].label = mark_safe(self.fields['details_who'].label) - self.fields['details_why'].label = mark_safe(self.fields['details_why'].label) - self.fields['details_frequency'].label = mark_safe(self.fields['details_frequency'].label) - + self.fields["details_who"].label = mark_safe(self.fields["details_who"].label) + self.fields["details_why"].label = mark_safe(self.fields["details_why"].label) + self.fields["details_frequency"].label = mark_safe( + self.fields["details_frequency"].label + ) if not self.study.has_children(): - del self.fields['supervision'] - del self.fields['leader_has_coc'] + del self.fields["supervision"] + del self.fields["leader_has_coc"] def get_soft_validation_fields(self): # We want soft validation of all fields @@ -65,29 +78,39 @@ def clean(self): self.mark_soft_required( cleaned_data, - 'setting', - 'details_who', - 'details_why', - 'details_frequency', + "setting", + "details_who", + "details_why", + "details_frequency", ) - self.check_dependency_multiple(cleaned_data, 'setting', 'needs_details', 'setting_details') + self.check_dependency_multiple( + cleaned_data, "setting", "needs_details", "setting_details" + ) if self.study.has_children(): - self.check_dependency_multiple(cleaned_data, 'setting', 'needs_supervision', 'supervision') - self.check_dependency(cleaned_data, 'supervision', 'leader_has_coc', f1_value=False) - self.check_dependency(cleaned_data, 'needs_approval', 'approval_institution') - self.check_dependency_multiple(cleaned_data, 'registrations', 'needs_details', 'registrations_details') - - self.check_dependency(cleaned_data, 'is_anonymous', 'is_anonymous_details') - self.check_dependency(cleaned_data, 'is_in_target_group', 'is_in_target_group_details') - self.check_dependency(cleaned_data, 'is_nonpublic_space', 'is_nonpublic_space_details') - + self.check_dependency_multiple( + cleaned_data, "setting", "needs_supervision", "supervision" + ) + self.check_dependency( + cleaned_data, "supervision", "leader_has_coc", f1_value=False + ) + self.check_dependency(cleaned_data, "needs_approval", "approval_institution") + self.check_dependency_multiple( + cleaned_data, "registrations", "needs_details", "registrations_details" + ) + self.check_dependency(cleaned_data, "is_anonymous", "is_anonymous_details") + self.check_dependency( + cleaned_data, "is_in_target_group", "is_in_target_group_details" + ) + self.check_dependency( + cleaned_data, "is_nonpublic_space", "is_nonpublic_space_details" + ) class ObservationUpdateAttachmentsForm(forms.ModelForm): class Meta: model = Observation fields = [ - 'approval_document', + "approval_document", ] diff --git a/observations/migrations/0001_initial.py b/observations/migrations/0001_initial.py index 82af931c8..de69da1f6 100644 --- a/observations/migrations/0001_initial.py +++ b/observations/migrations/0001_initial.py @@ -7,59 +7,153 @@ class Migration(migrations.Migration): - dependencies = [ - ('studies', '0001_initial'), - ('main', '0001_initial'), + ("studies", "0001_initial"), + ("main", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Observation', + name="Observation", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('setting_details', models.CharField(max_length=200, verbose_name='Namelijk', blank=True)), - ('supervision', models.NullBooleanField(verbose_name='Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?')), - ('days', models.PositiveIntegerField(verbose_name='Op hoeveel dagen wordt er geobserveerd (per deelnemer)?')), - ('mean_hours', models.DecimalField(verbose_name='Hoeveel uur wordt er gemiddeld per dag geobserveerd?', max_digits=4, decimal_places=2, validators=[django.core.validators.MaxValueValidator(24)])), - ('is_anonymous', models.BooleanField(default=False, help_text='Zoals zou kunnen voorkomen op fora en de onderzoeker ook een account heeft.', verbose_name='Wordt er anoniem geobserveerd?')), - ('is_in_target_group', models.BooleanField(default=False, verbose_name='Doet de onderzoeker zich voor als behorende tot de doelgroep?')), - ('is_nonpublic_space', models.BooleanField(default=False, help_text='Bijvoorbeeld er wordt geobserveerd bij iemand thuis, tijdens een hypotheekgesprek, tijdens politieverhoren of een forum waar een account voor moet worden aangemaakt.', verbose_name='Wordt er geobserveerd in een niet-openbare ruimte?')), - ('has_advanced_consent', models.BooleanField(default=True, verbose_name='Vindt informed consent van tevoren plaats?')), - ('needs_approval', models.BooleanField(default=False, verbose_name='Heeft u toestemming nodig van een (samenwerkende) instantie om deze observatie te mogen uitvoeren?')), - ('approval_institution', models.CharField(max_length=200, verbose_name='Welke instantie?', blank=True)), - ('approval_document', models.FileField(blank=True, upload_to=b'', verbose_name='Upload hier het toestemmingsdocument (in .pdf of .doc(x)-formaat)', validators=[main.validators.validate_pdf_or_doc])), - ('registrations_details', models.CharField(max_length=200, verbose_name='Namelijk', blank=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "setting_details", + models.CharField( + max_length=200, verbose_name="Namelijk", blank=True + ), + ), + ( + "supervision", + models.NullBooleanField( + verbose_name="Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?" + ), + ), + ( + "days", + models.PositiveIntegerField( + verbose_name="Op hoeveel dagen wordt er geobserveerd (per deelnemer)?" + ), + ), + ( + "mean_hours", + models.DecimalField( + verbose_name="Hoeveel uur wordt er gemiddeld per dag geobserveerd?", + max_digits=4, + decimal_places=2, + validators=[django.core.validators.MaxValueValidator(24)], + ), + ), + ( + "is_anonymous", + models.BooleanField( + default=False, + help_text="Zoals zou kunnen voorkomen op fora en de onderzoeker ook een account heeft.", + verbose_name="Wordt er anoniem geobserveerd?", + ), + ), + ( + "is_in_target_group", + models.BooleanField( + default=False, + verbose_name="Doet de onderzoeker zich voor als behorende tot de doelgroep?", + ), + ), + ( + "is_nonpublic_space", + models.BooleanField( + default=False, + help_text="Bijvoorbeeld er wordt geobserveerd bij iemand thuis, tijdens een hypotheekgesprek, tijdens politieverhoren of een forum waar een account voor moet worden aangemaakt.", + verbose_name="Wordt er geobserveerd in een niet-openbare ruimte?", + ), + ), + ( + "has_advanced_consent", + models.BooleanField( + default=True, + verbose_name="Vindt informed consent van tevoren plaats?", + ), + ), + ( + "needs_approval", + models.BooleanField( + default=False, + verbose_name="Heeft u toestemming nodig van een (samenwerkende) instantie om deze observatie te mogen uitvoeren?", + ), + ), + ( + "approval_institution", + models.CharField( + max_length=200, verbose_name="Welke instantie?", blank=True + ), + ), + ( + "approval_document", + models.FileField( + blank=True, + upload_to=b"", + verbose_name="Upload hier het toestemmingsdocument (in .pdf of .doc(x)-formaat)", + validators=[main.validators.validate_pdf_or_doc], + ), + ), + ( + "registrations_details", + models.CharField( + max_length=200, verbose_name="Namelijk", blank=True + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), migrations.CreateModel( - name='Registration', + name="Registration", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('order', models.PositiveIntegerField(unique=True)), - ('description', models.CharField(max_length=200)), - ('needs_details', models.BooleanField(default=False)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("order", models.PositiveIntegerField(unique=True)), + ("description", models.CharField(max_length=200)), + ("needs_details", models.BooleanField(default=False)), ], options={ - 'ordering': ['order'], + "ordering": ["order"], }, ), migrations.AddField( - model_name='observation', - name='registrations', - field=models.ManyToManyField(to='observations.Registration', verbose_name='Hoe wordt het gedrag geregistreerd?'), + model_name="observation", + name="registrations", + field=models.ManyToManyField( + to="observations.Registration", + verbose_name="Hoe wordt het gedrag geregistreerd?", + ), ), migrations.AddField( - model_name='observation', - name='setting', - field=models.ManyToManyField(to='main.Setting', verbose_name='Geef aan waar de dataverzameling plaatsvindt'), + model_name="observation", + name="setting", + field=models.ManyToManyField( + to="main.Setting", + verbose_name="Geef aan waar de dataverzameling plaatsvindt", + ), ), migrations.AddField( - model_name='observation', - name='study', - field=models.OneToOneField(to='studies.Study', on_delete=models.CASCADE), + model_name="observation", + name="study", + field=models.OneToOneField(to="studies.Study", on_delete=models.CASCADE), ), ] diff --git a/observations/migrations/0002_auto_20161013_1959.py b/observations/migrations/0002_auto_20161013_1959.py index 82a3d78ff..7a13e2cd6 100644 --- a/observations/migrations/0002_auto_20161013_1959.py +++ b/observations/migrations/0002_auto_20161013_1959.py @@ -5,20 +5,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0001_initial'), + ("observations", "0001_initial"), ] operations = [ migrations.AddField( - model_name='registration', - name='description_en', + model_name="registration", + name="description_en", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='registration', - name='description_nl', + model_name="registration", + name="description_nl", field=models.CharField(max_length=200, null=True), ), ] diff --git a/observations/migrations/0003_observation_leader_has_coc.py b/observations/migrations/0003_observation_leader_has_coc.py index ce267b459..a092a15d8 100644 --- a/observations/migrations/0003_observation_leader_has_coc.py +++ b/observations/migrations/0003_observation_leader_has_coc.py @@ -5,15 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0002_auto_20161013_1959'), + ("observations", "0002_auto_20161013_1959"), ] operations = [ migrations.AddField( - model_name='observation', - name='leader_has_coc', - field=models.NullBooleanField(help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De ETCL neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', verbose_name='Is de testleider in het bezit van een VOG?'), + model_name="observation", + name="leader_has_coc", + field=models.NullBooleanField( + help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De ETCL neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', + verbose_name="Is de testleider in het bezit van een VOG?", + ), ), ] diff --git a/observations/migrations/0004_auto_20180808_1129.py b/observations/migrations/0004_auto_20180808_1129.py index d0966bfac..7c6851220 100644 --- a/observations/migrations/0004_auto_20180808_1129.py +++ b/observations/migrations/0004_auto_20180808_1129.py @@ -7,15 +7,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0003_observation_leader_has_coc'), + ("observations", "0003_observation_leader_has_coc"), ] operations = [ migrations.AlterField( - model_name='observation', - name='approval_document', - field=models.FileField(blank=True, upload_to='', validators=[main.validators.validate_pdf_or_doc], verbose_name='Upload hier het toestemmingsdocument (in .pdf of .doc(x)-formaat)'), + model_name="observation", + name="approval_document", + field=models.FileField( + blank=True, + upload_to="", + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Upload hier het toestemmingsdocument (in .pdf of .doc(x)-formaat)", + ), ), ] diff --git a/observations/migrations/0005_auto_20180822_1206.py b/observations/migrations/0005_auto_20180822_1206.py index 82c61ac03..9f9065fe2 100644 --- a/observations/migrations/0005_auto_20180822_1206.py +++ b/observations/migrations/0005_auto_20180822_1206.py @@ -7,25 +7,36 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0004_auto_20180808_1129'), + ("observations", "0004_auto_20180808_1129"), ] operations = [ migrations.AddField( - model_name='observation', - name='version', - field=models.PositiveIntegerField(default=1, verbose_name='INTERNAL - Describes which version of the intervention model is used'), + model_name="observation", + name="version", + field=models.PositiveIntegerField( + default=1, + verbose_name="INTERNAL - Describes which version of the intervention model is used", + ), ), migrations.AlterField( - model_name='observation', - name='days', - field=models.PositiveIntegerField(blank=True, verbose_name='Op hoeveel dagen wordt er geobserveerd (per deelnemer)?'), + model_name="observation", + name="days", + field=models.PositiveIntegerField( + blank=True, + verbose_name="Op hoeveel dagen wordt er geobserveerd (per deelnemer)?", + ), ), migrations.AlterField( - model_name='observation', - name='mean_hours', - field=models.DecimalField(blank=True, decimal_places=2, max_digits=4, validators=[django.core.validators.MaxValueValidator(24)], verbose_name='Hoeveel uur wordt er gemiddeld per dag geobserveerd?'), + model_name="observation", + name="mean_hours", + field=models.DecimalField( + blank=True, + decimal_places=2, + max_digits=4, + validators=[django.core.validators.MaxValueValidator(24)], + verbose_name="Hoeveel uur wordt er gemiddeld per dag geobserveerd?", + ), ), ] diff --git a/observations/migrations/0006_auto_20180822_1207.py b/observations/migrations/0006_auto_20180822_1207.py index 59edb5c9d..442c533b9 100644 --- a/observations/migrations/0006_auto_20180822_1207.py +++ b/observations/migrations/0006_auto_20180822_1207.py @@ -6,15 +6,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0005_auto_20180822_1206'), + ("observations", "0005_auto_20180822_1206"), ] operations = [ migrations.AlterField( - model_name='observation', - name='version', - field=models.PositiveIntegerField(default=2, verbose_name='INTERNAL - Describes which version of the intervention model is used'), + model_name="observation", + name="version", + field=models.PositiveIntegerField( + default=2, + verbose_name="INTERNAL - Describes which version of the intervention model is used", + ), ), ] diff --git a/observations/migrations/0007_auto_20180822_1214.py b/observations/migrations/0007_auto_20180822_1214.py index 5f38db81b..3dbe1185c 100644 --- a/observations/migrations/0007_auto_20180822_1214.py +++ b/observations/migrations/0007_auto_20180822_1214.py @@ -6,33 +6,42 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0006_auto_20180822_1207'), + ("observations", "0006_auto_20180822_1207"), ] operations = [ migrations.AddField( - model_name='observation', - name='details_frequency', - field=models.TextField(default='', verbose_name='Beschrijf hoe vaak en hoe lang de observant wordt geobserveerd.'), + model_name="observation", + name="details_frequency", + field=models.TextField( + default="", + verbose_name="Beschrijf hoe vaak en hoe lang de observant wordt geobserveerd.", + ), preserve_default=False, ), migrations.AddField( - model_name='observation', - name='details_who', - field=models.TextField(default=' ', verbose_name='Beschrijf wie er wordt geobserveerd.'), + model_name="observation", + name="details_who", + field=models.TextField( + default=" ", verbose_name="Beschrijf wie er wordt geobserveerd." + ), preserve_default=False, ), migrations.AddField( - model_name='observation', - name='details_why', - field=models.TextField(default=' ', verbose_name='Beschrijf waarom er wordt geobserveerd.'), + model_name="observation", + name="details_why", + field=models.TextField( + default=" ", verbose_name="Beschrijf waarom er wordt geobserveerd." + ), preserve_default=False, ), migrations.AlterField( - model_name='observation', - name='version', - field=models.PositiveIntegerField(default=2, verbose_name='INTERNAL - Describes which version of the observation model is used'), + model_name="observation", + name="version", + field=models.PositiveIntegerField( + default=2, + verbose_name="INTERNAL - Describes which version of the observation model is used", + ), ), ] diff --git a/observations/migrations/0008_auto_20180822_1307.py b/observations/migrations/0008_auto_20180822_1307.py index 23d222ca8..3d8756379 100644 --- a/observations/migrations/0008_auto_20180822_1307.py +++ b/observations/migrations/0008_auto_20180822_1307.py @@ -6,25 +6,33 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0007_auto_20180822_1214'), + ("observations", "0007_auto_20180822_1214"), ] operations = [ migrations.AlterField( - model_name='observation', - name='details_frequency', - field=models.TextField(help_text='Bijvoorbeeld: De leraar zal 5 lessen van 45 minuten worden geobserveerd.', verbose_name='Beschrijf hoe vaak en hoe lang de observant wordt geobserveerd.'), + model_name="observation", + name="details_frequency", + field=models.TextField( + help_text="Bijvoorbeeld: De leraar zal 5 lessen van 45 minuten worden geobserveerd.", + verbose_name="Beschrijf hoe vaak en hoe lang de observant wordt geobserveerd.", + ), ), migrations.AlterField( - model_name='observation', - name='details_who', - field=models.TextField(help_text='Maak duidelijk voor de commissie wie er wordt geobserveerd en wat er precies van de deelnemer wordt geobserveerd. Bijvoorbeeld: De leraar zal geobserveerd worden. De observatie moet de interactie tussen leraar en leerling in kaart brengen.', verbose_name='Beschrijf wie er wordt geobserveerd.'), + model_name="observation", + name="details_who", + field=models.TextField( + help_text="Maak duidelijk voor de commissie wie er wordt geobserveerd en wat er precies van de deelnemer wordt geobserveerd. Bijvoorbeeld: De leraar zal geobserveerd worden. De observatie moet de interactie tussen leraar en leerling in kaart brengen.", + verbose_name="Beschrijf wie er wordt geobserveerd.", + ), ), migrations.AlterField( - model_name='observation', - name='details_why', - field=models.TextField(help_text='Wat is het doel van de observatie? Bijvoorbeeld: Het doel van de observatie is inzicht te krijgen in hoe de leerkracht omgaat met de uitleg van de nieuwe lesmethode. Doet h/zij dat op de gewenste manier en in begrijpelijke taal?', verbose_name='Beschrijf waarom er wordt geobserveerd.'), + model_name="observation", + name="details_why", + field=models.TextField( + help_text="Wat is het doel van de observatie? Bijvoorbeeld: Het doel van de observatie is inzicht te krijgen in hoe de leerkracht omgaat met de uitleg van de nieuwe lesmethode. Doet h/zij dat op de gewenste manier en in begrijpelijke taal?", + verbose_name="Beschrijf waarom er wordt geobserveerd.", + ), ), ] diff --git a/observations/migrations/0009_auto_20180822_1328.py b/observations/migrations/0009_auto_20180822_1328.py index 5d98101e0..e9c4855b1 100644 --- a/observations/migrations/0009_auto_20180822_1328.py +++ b/observations/migrations/0009_auto_20180822_1328.py @@ -6,25 +6,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0008_auto_20180822_1307'), + ("observations", "0008_auto_20180822_1307"), ] operations = [ migrations.AddField( - model_name='observation', - name='is_anonymous_details', - field=models.TextField(blank=True, verbose_name='Licht toe'), + model_name="observation", + name="is_anonymous_details", + field=models.TextField(blank=True, verbose_name="Licht toe"), ), migrations.AddField( - model_name='observation', - name='is_in_target_group_details', - field=models.TextField(blank=True, verbose_name='Licht toe'), + model_name="observation", + name="is_in_target_group_details", + field=models.TextField(blank=True, verbose_name="Licht toe"), ), migrations.AddField( - model_name='observation', - name='is_nonpublic_space_details', - field=models.TextField(blank=True, verbose_name='Licht toe'), + model_name="observation", + name="is_nonpublic_space_details", + field=models.TextField(blank=True, verbose_name="Licht toe"), ), ] diff --git a/observations/migrations/0010_auto_20180822_1332.py b/observations/migrations/0010_auto_20180822_1332.py index b6a1668e5..779ce640e 100644 --- a/observations/migrations/0010_auto_20180822_1332.py +++ b/observations/migrations/0010_auto_20180822_1332.py @@ -7,20 +7,30 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0009_auto_20180822_1328'), + ("observations", "0009_auto_20180822_1328"), ] operations = [ migrations.AlterField( - model_name='observation', - name='days', - field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Op hoeveel dagen wordt er geobserveerd (per deelnemer)?'), + model_name="observation", + name="days", + field=models.PositiveIntegerField( + blank=True, + null=True, + verbose_name="Op hoeveel dagen wordt er geobserveerd (per deelnemer)?", + ), ), migrations.AlterField( - model_name='observation', - name='mean_hours', - field=models.DecimalField(blank=True, decimal_places=2, max_digits=4, null=True, validators=[django.core.validators.MaxValueValidator(24)], verbose_name='Hoeveel uur wordt er gemiddeld per dag geobserveerd?'), + model_name="observation", + name="mean_hours", + field=models.DecimalField( + blank=True, + decimal_places=2, + max_digits=4, + null=True, + validators=[django.core.validators.MaxValueValidator(24)], + verbose_name="Hoeveel uur wordt er gemiddeld per dag geobserveerd?", + ), ), ] diff --git a/observations/migrations/0011_auto_20190401_1343.py b/observations/migrations/0011_auto_20190401_1343.py index 6cf1424a2..39ba2cbe3 100644 --- a/observations/migrations/0011_auto_20190401_1343.py +++ b/observations/migrations/0011_auto_20190401_1343.py @@ -6,35 +6,53 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0010_auto_20180822_1332'), + ("observations", "0010_auto_20180822_1332"), ] operations = [ migrations.AlterField( - model_name='observation', - name='details_frequency', - field=models.TextField(blank=True, help_text='Bijvoorbeeld: De leraar zal 5 lessen van 45 minuten worden geobserveerd.', verbose_name='Beschrijf hoe vaak en hoe lang de observant wordt geobserveerd.'), + model_name="observation", + name="details_frequency", + field=models.TextField( + blank=True, + help_text="Bijvoorbeeld: De leraar zal 5 lessen van 45 minuten worden geobserveerd.", + verbose_name="Beschrijf hoe vaak en hoe lang de observant wordt geobserveerd.", + ), ), migrations.AlterField( - model_name='observation', - name='details_who', - field=models.TextField(blank=True, help_text='Maak duidelijk voor de commissie wie er wordt geobserveerd en wat er precies van de deelnemer wordt geobserveerd. Bijvoorbeeld: De leraar zal geobserveerd worden. De observatie moet de interactie tussen leraar en leerling in kaart brengen.', verbose_name='Beschrijf wie er wordt geobserveerd.'), + model_name="observation", + name="details_who", + field=models.TextField( + blank=True, + help_text="Maak duidelijk voor de commissie wie er wordt geobserveerd en wat er precies van de deelnemer wordt geobserveerd. Bijvoorbeeld: De leraar zal geobserveerd worden. De observatie moet de interactie tussen leraar en leerling in kaart brengen.", + verbose_name="Beschrijf wie er wordt geobserveerd.", + ), ), migrations.AlterField( - model_name='observation', - name='details_why', - field=models.TextField(blank=True, help_text='Wat is het doel van de observatie? Bijvoorbeeld: Het doel van de observatie is inzicht te krijgen in hoe de leerkracht omgaat met de uitleg van de nieuwe lesmethode. Doet h/zij dat op de gewenste manier en in begrijpelijke taal?', verbose_name='Beschrijf waarom er wordt geobserveerd.'), + model_name="observation", + name="details_why", + field=models.TextField( + blank=True, + help_text="Wat is het doel van de observatie? Bijvoorbeeld: Het doel van de observatie is inzicht te krijgen in hoe de leerkracht omgaat met de uitleg van de nieuwe lesmethode. Doet h/zij dat op de gewenste manier en in begrijpelijke taal?", + verbose_name="Beschrijf waarom er wordt geobserveerd.", + ), ), migrations.AlterField( - model_name='observation', - name='leader_has_coc', - field=models.NullBooleanField(help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', verbose_name='Is de testleider in het bezit van een VOG?'), + model_name="observation", + name="leader_has_coc", + field=models.NullBooleanField( + help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', + verbose_name="Is de testleider in het bezit van een VOG?", + ), ), migrations.AlterField( - model_name='observation', - name='setting', - field=models.ManyToManyField(blank=True, to='main.Setting', verbose_name='Geef aan waar de dataverzameling plaatsvindt'), + model_name="observation", + name="setting", + field=models.ManyToManyField( + blank=True, + to="main.Setting", + verbose_name="Geef aan waar de dataverzameling plaatsvindt", + ), ), ] diff --git a/observations/migrations/0012_observation_has_advanced_consent_details.py b/observations/migrations/0012_observation_has_advanced_consent_details.py index 4b4e93554..d8764f1e1 100644 --- a/observations/migrations/0012_observation_has_advanced_consent_details.py +++ b/observations/migrations/0012_observation_has_advanced_consent_details.py @@ -6,15 +6,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0011_auto_20190401_1343'), + ("observations", "0011_auto_20190401_1343"), ] operations = [ migrations.AddField( - model_name='observation', - name='has_advanced_consent_details', - field=models.TextField(blank=True, verbose_name='Leg uit waarom informed consent niet van te voren plaatsvindt en geef ook op welke wijze dit achteraf verzorgd wordt.'), + model_name="observation", + name="has_advanced_consent_details", + field=models.TextField( + blank=True, + verbose_name="Leg uit waarom informed consent niet van te voren plaatsvindt en geef ook op welke wijze dit achteraf verzorgd wordt.", + ), ), ] diff --git a/observations/migrations/0013_registration_requires_review.py b/observations/migrations/0013_registration_requires_review.py index bfa6e708b..976f0b763 100644 --- a/observations/migrations/0013_registration_requires_review.py +++ b/observations/migrations/0013_registration_requires_review.py @@ -6,15 +6,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0012_observation_has_advanced_consent_details'), + ("observations", "0012_observation_has_advanced_consent_details"), ] operations = [ migrations.AddField( - model_name='registration', - name='requires_review', + model_name="registration", + name="requires_review", field=models.BooleanField(default=False), ), ] diff --git a/observations/migrations/0014_auto_20200428_1337.py b/observations/migrations/0014_auto_20200428_1337.py index 799785787..64bd354f7 100644 --- a/observations/migrations/0014_auto_20200428_1337.py +++ b/observations/migrations/0014_auto_20200428_1337.py @@ -4,20 +4,28 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0013_registration_requires_review'), + ("observations", "0013_registration_requires_review"), ] operations = [ migrations.AlterField( - model_name='observation', - name='leader_has_coc', - field=models.BooleanField(blank=True, help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', null=True, verbose_name='Is de testleider in het bezit van een VOG?'), + model_name="observation", + name="leader_has_coc", + field=models.BooleanField( + blank=True, + help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', + null=True, + verbose_name="Is de testleider in het bezit van een VOG?", + ), ), migrations.AlterField( - model_name='observation', - name='supervision', - field=models.BooleanField(blank=True, null=True, verbose_name='Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?'), + model_name="observation", + name="supervision", + field=models.BooleanField( + blank=True, + null=True, + verbose_name="Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?", + ), ), ] diff --git a/observations/migrations/0015_auto_20211213_1503.py b/observations/migrations/0015_auto_20211213_1503.py index 0deee9cee..fc0d119a4 100644 --- a/observations/migrations/0015_auto_20211213_1503.py +++ b/observations/migrations/0015_auto_20211213_1503.py @@ -4,20 +4,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0014_auto_20200428_1337'), + ("observations", "0014_auto_20200428_1337"), ] operations = [ migrations.AlterField( - model_name='observation', - name='details_why', - field=models.TextField(blank=True, help_text='Wat is het doel van de observatie? Bijvoorbeeld: Het doel van de observatie is inzicht te krijgen in hoe de leerkracht omgaat met de uitleg van de nieuwe lesmethode. Doet die dat op de gewenste manier en in begrijpelijke taal?', verbose_name='Beschrijf waarom er wordt geobserveerd.'), + model_name="observation", + name="details_why", + field=models.TextField( + blank=True, + help_text="Wat is het doel van de observatie? Bijvoorbeeld: Het doel van de observatie is inzicht te krijgen in hoe de leerkracht omgaat met de uitleg van de nieuwe lesmethode. Doet die dat op de gewenste manier en in begrijpelijke taal?", + verbose_name="Beschrijf waarom er wordt geobserveerd.", + ), ), migrations.AlterField( - model_name='observation', - name='needs_approval', - field=models.BooleanField(default=False, verbose_name='Heb je toestemming nodig van een (samenwerkende) instantie om deze observatie te mogen uitvoeren?'), + model_name="observation", + name="needs_approval", + field=models.BooleanField( + default=False, + verbose_name="Heb je toestemming nodig van een (samenwerkende) instantie om deze observatie te mogen uitvoeren?", + ), ), ] diff --git a/observations/migrations/0016_alter_observation_registrations.py b/observations/migrations/0016_alter_observation_registrations.py index c95f0fe0d..9811e144b 100644 --- a/observations/migrations/0016_alter_observation_registrations.py +++ b/observations/migrations/0016_alter_observation_registrations.py @@ -4,15 +4,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('observations', '0015_auto_20211213_1503'), + ("observations", "0015_auto_20211213_1503"), ] operations = [ migrations.AlterField( - model_name='observation', - name='registrations', - field=models.ManyToManyField(help_text="Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het gebruik van de term ‘anoniem’ of ‘geanonimiseerd’ in je documenten voor deelnemers. Voor meer informatie, zie de Richtlijnen voor geïnformeerde toestemming, ‘Beeld en geluid’.", to='observations.Registration', verbose_name='Hoe wordt het gedrag geregistreerd?'), + model_name="observation", + name="registrations", + field=models.ManyToManyField( + help_text="Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het gebruik van de term ‘anoniem’ of ‘geanonimiseerd’ in je documenten voor deelnemers. Voor meer informatie, zie de Richtlijnen voor geïnformeerde toestemming, ‘Beeld en geluid’.", + to="observations.Registration", + verbose_name="Hoe wordt het gedrag geregistreerd?", + ), ), ] diff --git a/observations/models.py b/observations/models.py index 7acb2cc7b..25403c7ed 100644 --- a/observations/models.py +++ b/observations/models.py @@ -14,7 +14,7 @@ class Registration(models.Model): requires_review = models.BooleanField(default=False) class Meta: - ordering = ['order'] + ordering = ["order"] def __str__(self): return self.description @@ -24,126 +24,134 @@ class Observation(SettingModel): # This is used internally to provide backwards compatibility with the old # version of this model. All old fields are still used if this is 1. version = models.PositiveIntegerField( - 'INTERNAL - Describes which version of the observation model is used', - default=2) + "INTERNAL - Describes which version of the observation model is used", default=2 + ) details_who = models.TextField( - _('Beschrijf wie er wordt geobserveerd.'), + _("Beschrijf wie er wordt geobserveerd."), help_text=_( - 'Maak duidelijk voor de commissie wie er wordt geobserveerd en wat er precies van de deelnemer wordt' - ' geobserveerd. Bijvoorbeeld: De leraar zal geobserveerd worden. De observatie moet de interactie ' - 'tussen leraar en leerling in kaart brengen.'), + "Maak duidelijk voor de commissie wie er wordt geobserveerd en wat er precies van de deelnemer wordt" + " geobserveerd. Bijvoorbeeld: De leraar zal geobserveerd worden. De observatie moet de interactie " + "tussen leraar en leerling in kaart brengen." + ), blank=True, ) details_why = models.TextField( - _('Beschrijf waarom er wordt geobserveerd.'), + _("Beschrijf waarom er wordt geobserveerd."), help_text=_( - 'Wat is het doel van de observatie? Bijvoorbeeld: Het doel van de ' - 'observatie is inzicht te krijgen in hoe de leerkracht omgaat met ' - 'de uitleg van de nieuwe lesmethode. Doet die dat op de gewenste ' - 'manier en in begrijpelijke taal?'), + "Wat is het doel van de observatie? Bijvoorbeeld: Het doel van de " + "observatie is inzicht te krijgen in hoe de leerkracht omgaat met " + "de uitleg van de nieuwe lesmethode. Doet die dat op de gewenste " + "manier en in begrijpelijke taal?" + ), blank=True, ) details_frequency = models.TextField( - _( - 'Beschrijf hoe vaak en hoe lang de observant wordt geobserveerd.'), - help_text=_('Bijvoorbeeld: De leraar zal 5 lessen van 45 minuten ' - 'worden geobserveerd.'), + _("Beschrijf hoe vaak en hoe lang de observant wordt geobserveerd."), + help_text=_( + "Bijvoorbeeld: De leraar zal 5 lessen van 45 minuten " + "worden geobserveerd." + ), blank=True, ) is_anonymous = models.BooleanField( - _('Wordt er anoniem geobserveerd?'), + _("Wordt er anoniem geobserveerd?"), help_text=_( - 'Zoals zou kunnen voorkomen op fora en de onderzoeker ook een account heeft.'), + "Zoals zou kunnen voorkomen op fora en de onderzoeker ook een account heeft." + ), default=False, ) is_anonymous_details = models.TextField( - _('Licht toe'), + _("Licht toe"), blank=True, ) is_in_target_group = models.BooleanField( - _('Doet de onderzoeker zich voor als behorende tot de doelgroep?'), + _("Doet de onderzoeker zich voor als behorende tot de doelgroep?"), default=False, ) is_in_target_group_details = models.TextField( - _('Licht toe'), + _("Licht toe"), blank=True, ) is_nonpublic_space = models.BooleanField( - _('Wordt er geobserveerd in een niet-openbare ruimte?'), - help_text=_('Bijvoorbeeld er wordt geobserveerd bij iemand thuis, \ + _("Wordt er geobserveerd in een niet-openbare ruimte?"), + help_text=_( + "Bijvoorbeeld er wordt geobserveerd bij iemand thuis, \ tijdens een hypotheekgesprek, tijdens politieverhoren of een forum waar \ -een account voor moet worden aangemaakt.'), +een account voor moet worden aangemaakt." + ), default=False, ) is_nonpublic_space_details = models.TextField( - _('Licht toe'), + _("Licht toe"), blank=True, ) has_advanced_consent = models.BooleanField( - _('Vindt informed consent van tevoren plaats?'), + _("Vindt informed consent van tevoren plaats?"), default=True, ) has_advanced_consent_details = models.TextField( _( - 'Leg uit waarom informed consent niet van te voren plaatsvindt en ' - 'geef ook op welke wijze dit achteraf verzorgd wordt.' + "Leg uit waarom informed consent niet van te voren plaatsvindt en " + "geef ook op welke wijze dit achteraf verzorgd wordt." ), blank=True, ) needs_approval = models.BooleanField( - _('Heb je toestemming nodig van een (samenwerkende) instantie \ -om deze observatie te mogen uitvoeren?'), + _( + "Heb je toestemming nodig van een (samenwerkende) instantie \ +om deze observatie te mogen uitvoeren?" + ), default=False, ) approval_institution = models.CharField( - _('Welke instantie?'), + _("Welke instantie?"), max_length=200, blank=True, ) approval_document = models.FileField( - _('Upload hier het toestemmingsdocument (in .pdf of .doc(x)-formaat)'), + _("Upload hier het toestemmingsdocument (in .pdf of .doc(x)-formaat)"), blank=True, validators=[validate_pdf_or_doc], ) registrations = models.ManyToManyField( Registration, - help_text=_("Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het gebruik van de term ‘anoniem’ of ‘geanonimiseerd’ in je documenten voor deelnemers. Voor meer informatie, zie de Richtlijnen voor geïnformeerde toestemming, ‘Beeld en geluid’."), - verbose_name=_('Hoe wordt het gedrag geregistreerd?')) + help_text=_( + "Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het gebruik van de term ‘anoniem’ of ‘geanonimiseerd’ in je documenten voor deelnemers. Voor meer informatie, zie de Richtlijnen voor geïnformeerde toestemming, ‘Beeld en geluid’." + ), + verbose_name=_("Hoe wordt het gedrag geregistreerd?"), + ) - registrations_details = models.CharField( - _('Namelijk'), - max_length=200, - blank=True) + registrations_details = models.CharField(_("Namelijk"), max_length=200, blank=True) # Legacy, only used in v1 days = models.PositiveIntegerField( - _('Op hoeveel dagen wordt er geobserveerd (per deelnemer)?'), + _("Op hoeveel dagen wordt er geobserveerd (per deelnemer)?"), blank=True, - null=True) + null=True, + ) mean_hours = models.DecimalField( - _('Hoeveel uur wordt er gemiddeld per dag geobserveerd?'), + _("Hoeveel uur wordt er gemiddeld per dag geobserveerd?"), max_digits=4, decimal_places=2, validators=[MaxValueValidator(24)], blank=True, - null=True) + null=True, + ) # References - study = models.OneToOneField( - Study, - on_delete=models.CASCADE) + study = models.OneToOneField(Study, on_delete=models.CASCADE) diff --git a/observations/templates/observations/observation_form.html b/observations/templates/observations/observation_form.html index fc5738207..61eb3fa57 100644 --- a/observations/templates/observations/observation_form.html +++ b/observations/templates/observations/observation_form.html @@ -7,7 +7,6 @@ {% trans "Het observatieonderzoek" %} - {{ block.super }} {% endblock %} - {% block html_head %} -{% include "main/setting_checks.html" %} + + {% include "main/setting_checks.html" %} {% endblock %} {% block content %} @@ -40,14 +39,15 @@ {% with nav_items=study.proposal.available_urls active=3 %} {% include 'base/navigation.html' %} {% endwith %} -

      - {% trans "Het observatieonderzoek" %} -

      +

      {% trans "Het observatieonderzoek" %}

      {% include "studies/study_title.html" %} -
      {% csrf_token %} - {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      {% with proposal=observation.study.proposal %} - {% include "base/form_buttons.html" %} + {% include "base/form_buttons.html" %} {% endwith %}
      diff --git a/observations/templates/observations/observation_update_attachments.html b/observations/templates/observations/observation_update_attachments.html index 543375f44..d01e80e15 100644 --- a/observations/templates/observations/observation_update_attachments.html +++ b/observations/templates/observations/observation_update_attachments.html @@ -8,7 +8,7 @@ {% endblock %} {% block html_head %} - + {% endblock %} {% block content %}
      -

      - {% trans "Formulieren aanpassen" %} -

      +

      {% trans "Formulieren aanpassen" %}

      {% blocktrans trimmed with title=study.proposal.title ref_number=study.proposal.reference_number order=study.order %} - Op deze pagina kan je de formulieren aanpassen behorende bij de aanvraag {{ title }} - (referentienummer {{ ref_number }}), traject {{ order }}. + Op deze pagina kan je de formulieren aanpassen behorende bij de aanvraag {{ title }} + (referentienummer {{ ref_number }}), traject {{ order }}. {% endblocktrans %}

      -
      {% csrf_token %} - {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      - - {% trans "Terug naar de vorige pagina" %} + + {% trans "Terug naar de vorige pagina" %}
      diff --git a/observations/tests.py b/observations/tests.py index 2701b0627..b7dbda4a6 100644 --- a/observations/tests.py +++ b/observations/tests.py @@ -5,10 +5,10 @@ class ObservationTestCase(TestCase): def test_create(self): pk = 1 - response = self.client.get(reverse('observations:create', args=(pk,))) + response = self.client.get(reverse("observations:create", args=(pk,))) self.assertEqual(response.status_code, 302) def test_update(self): pk = 1 - response = self.client.get(reverse('observations:update', args=(pk,))) + response = self.client.get(reverse("observations:update", args=(pk,))) self.assertEqual(response.status_code, 302) diff --git a/observations/translation.py b/observations/translation.py index a71d34b5c..c97e9aac6 100644 --- a/observations/translation.py +++ b/observations/translation.py @@ -5,4 +5,4 @@ @register(Registration) class RegistrationTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) diff --git a/observations/urls.py b/observations/urls.py index fb52506c7..05c991352 100644 --- a/observations/urls.py +++ b/observations/urls.py @@ -2,11 +2,10 @@ from .views import ObservationCreate, ObservationUpdate, AttachmentsUpdate -app_name = 'observations' +app_name = "observations" urlpatterns = [ - path('create//', ObservationCreate.as_view(), name='create'), - path('update//', ObservationUpdate.as_view(), name='update'), - path('attachments//', AttachmentsUpdate.as_view(), - name='attachments') + path("create//", ObservationCreate.as_view(), name="create"), + path("update//", ObservationUpdate.as_view(), name="update"), + path("attachments//", AttachmentsUpdate.as_view(), name="attachments"), ] diff --git a/observations/utils.py b/observations/utils.py index 6bfe00f29..509c8f95e 100644 --- a/observations/utils.py +++ b/observations/utils.py @@ -5,12 +5,12 @@ def observation_url(study): - result = AvailableURL(title=_('Observatieonderzoek'), margin=2) + result = AvailableURL(title=_("Observatieonderzoek"), margin=2) if study.has_observation: - if hasattr(study, 'observation'): - result.url = reverse('observations:update', args=(study.observation.pk,)) + if hasattr(study, "observation"): + result.url = reverse("observations:update", args=(study.observation.pk,)) else: - result.url = reverse('observations:create', args=(study.pk,)) + result.url = reverse("observations:create", args=(study.pk,)) return result diff --git a/observations/views.py b/observations/views.py index 7cf9269d7..0121ff727 100644 --- a/observations/views.py +++ b/observations/views.py @@ -15,38 +15,39 @@ ############################# class ObservationMixin(object): """Mixin for a Observation, to use in both ObservationCreate and ObservationUpdate below""" + model = Observation form_class = ObservationForm - success_message = _('Observatie opgeslagen') + success_message = _("Observatie opgeslagen") def get_context_data(self, **kwargs): """Setting the Study and progress on the context""" context = super(ObservationMixin, self).get_context_data(**kwargs) study = self.get_study() - context['study'] = study - context['progress'] = get_study_progress(study) + 5 + context["study"] = study + context["progress"] = get_study_progress(study) + 5 return context def get_form_kwargs(self): """Sets the Study as a form kwarg""" kwargs = super(ObservationMixin, self).get_form_kwargs() - kwargs['study'] = self.get_study() + kwargs["study"] = self.get_study() return kwargs def get_next_url(self): study = self.get_study() - next_url = 'studies:design_end' + next_url = "studies:design_end" pk = study.pk if study.has_sessions: - next_url = 'studies:session_start' + next_url = "studies:session_start" return reverse(next_url, args=(pk,)) def get_back_url(self): study = self.get_study() pk = study.pk - next_url = 'studies:design' + next_url = "studies:design" if study.has_intervention: - next_url = 'interventions:update' + next_url = "interventions:update" pk = study.intervention.pk return reverse(next_url, args=(pk,)) @@ -56,7 +57,7 @@ def get_study(self): class AttachmentsUpdate(UpdateView): model = Observation - template_name = 'observations/observation_update_attachments.html' + template_name = "observations/observation_update_attachments.html" form_class = ObservationUpdateAttachmentsForm group_required = settings.GROUP_SECRETARY @@ -71,7 +72,7 @@ def form_valid(self, form): def get_study(self): """Retrieves the Study from the pk kwarg""" - return Study.objects.get(pk=self.kwargs['pk']) + return Study.objects.get(pk=self.kwargs["pk"]) class ObservationUpdate(ObservationMixin, AllowErrorsOnBackbuttonMixin, UpdateView): diff --git a/proposals/admin.py b/proposals/admin.py index 08e525038..c801ed8d1 100644 --- a/proposals/admin.py +++ b/proposals/admin.py @@ -5,33 +5,54 @@ @admin.register(Relation) class RelationAdmin(admin.ModelAdmin): - list_display = ('order', 'description', 'needs_supervisor', 'check_in_course', 'check_pre_assessment', ) - list_display_links = ('description', ) - ordering = ['order'] + list_display = ( + "order", + "description", + "needs_supervisor", + "check_in_course", + "check_pre_assessment", + ) + list_display_links = ("description",) + ordering = ["order"] + @admin.register(StudentContext) class StudentContextAdmin(admin.ModelAdmin): - list_display = ('order', 'description', 'needs_details', ) - list_display_links = ('description', ) - ordering = ['order'] + list_display = ( + "order", + "description", + "needs_details", + ) + list_display_links = ("description",) + ordering = ["order"] @admin.register(Funding) class FundingAdmin(admin.ModelAdmin): - list_display = ('order', 'description', 'needs_details', 'needs_name', 'requires_review', ) - list_display_links = ('description', ) - ordering = ['order'] + list_display = ( + "order", + "description", + "needs_details", + "needs_name", + "requires_review", + ) + list_display_links = ("description",) + ordering = ["order"] @admin.register(Proposal) class ProposalAdmin(admin.ModelAdmin): - list_display = ('reference_number', 'title', 'created_by', 'supervisor') - list_display_links = ('reference_number', ) - ordering = ['reference_number'] + list_display = ("reference_number", "title", "created_by", "supervisor") + list_display_links = ("reference_number",) + ordering = ["reference_number"] @admin.register(Institution) class ProposalAdmin(admin.ModelAdmin): - list_display = ('order', 'description', 'reviewing_chamber', ) - list_display_links = ('description', ) - ordering = ['order'] + list_display = ( + "order", + "description", + "reviewing_chamber", + ) + list_display_links = ("description",) + ordering = ["order"] diff --git a/proposals/api/serializers.py b/proposals/api/serializers.py index 2ddb94171..6be309a3a 100644 --- a/proposals/api/serializers.py +++ b/proposals/api/serializers.py @@ -2,19 +2,31 @@ from main.serializers import UserSerializer from proposals.models import Proposal -from reviews.api.serializers import InlineReviewSerializer, \ - InlineDecisionSerializer +from reviews.api.serializers import InlineReviewSerializer, InlineDecisionSerializer from uil.core.rest.serializers import ModelDisplaySerializer class ProposalInlineSerializer(ModelDisplaySerializer): class Meta: model = Proposal - fields = ['pk', 'reference_number', 'title', 'is_revision', - 'type', 'date_confirmed', 'date_submitted', - 'date_reviewed', 'date_modified', 'latest_review', - 'supervisor_decision', 'applicants', 'status', 'supervisor', - 'pdf', 'in_archive'] + fields = [ + "pk", + "reference_number", + "title", + "is_revision", + "type", + "date_confirmed", + "date_submitted", + "date_reviewed", + "date_modified", + "latest_review", + "supervisor_decision", + "applicants", + "status", + "supervisor", + "pdf", + "in_archive", + ] latest_review = serializers.SerializerMethodField() supervisor = serializers.SerializerMethodField() @@ -22,7 +34,6 @@ class Meta: applicants = serializers.SerializerMethodField() pdf = serializers.SerializerMethodField() - def get_latest_review(self, proposal): review = proposal.latest_review() @@ -63,12 +74,28 @@ def get_pdf(self, proposal): class ProposalSerializer(ProposalInlineSerializer): class Meta: model = Proposal - fields = ['pk', 'reference_number', 'title', 'is_revision', 'type', - 'date_confirmed', 'date_submitted', - 'date_submitted_supervisor', 'date_reviewed', 'date_modified', - 'parent', 'latest_review', 'supervisor_decision', - 'applicants', 'status', 'supervisor', 'continue_url', - 'pdf', 'in_archive'] + fields = [ + "pk", + "reference_number", + "title", + "is_revision", + "type", + "date_confirmed", + "date_submitted", + "date_submitted_supervisor", + "date_reviewed", + "date_modified", + "parent", + "latest_review", + "supervisor_decision", + "applicants", + "status", + "supervisor", + "continue_url", + "pdf", + "in_archive", + "is_revisable", + ] parent = serializers.SerializerMethodField() diff --git a/proposals/api/urls.py b/proposals/api/urls.py index 2415170aa..ddcad55c4 100644 --- a/proposals/api/urls.py +++ b/proposals/api/urls.py @@ -1,33 +1,23 @@ from django.urls import path -from .views import ProposalArchiveApiView, MyConceptsApiView, \ - MySubmittedApiView, MyCompletedApiView, MySupervisedApiView, \ - MyPracticeApiView, MyProposalsApiView +from .views import ( + ProposalArchiveApiView, + MyConceptsApiView, + MySubmittedApiView, + MyCompletedApiView, + MySupervisedApiView, + MyPracticeApiView, + MyProposalsApiView, +) -app_name = 'api' +app_name = "api" urlpatterns = [ - path('archive//', - ProposalArchiveApiView.as_view(), - name='archive'), - - path('my_archive/', - MyProposalsApiView.as_view(), - name='my_archive'), - path('my_concepts/', - MyConceptsApiView.as_view(), - name='my_concepts'), - path('my_submitted/', - MySubmittedApiView.as_view(), - name='my_submitted'), - path('my_completed/', - MyCompletedApiView.as_view(), - name='my_completed'), - path('my_supervised/', - MySupervisedApiView.as_view(), - name='my_supervised'), - path('my_practice/', - MyPracticeApiView.as_view(), - name='my_practice'), - + path("archive//", ProposalArchiveApiView.as_view(), name="archive"), + path("my_archive/", MyProposalsApiView.as_view(), name="my_archive"), + path("my_concepts/", MyConceptsApiView.as_view(), name="my_concepts"), + path("my_submitted/", MySubmittedApiView.as_view(), name="my_submitted"), + path("my_completed/", MyCompletedApiView.as_view(), name="my_completed"), + path("my_supervised/", MySupervisedApiView.as_view(), name="my_supervised"), + path("my_practice/", MyPracticeApiView.as_view(), name="my_practice"), ] diff --git a/proposals/api/views.py b/proposals/api/views.py index af99992d9..47693495e 100644 --- a/proposals/api/views.py +++ b/proposals/api/views.py @@ -15,168 +15,138 @@ class BaseProposalsApiView(LoginRequiredMixin, FancyListApiView): - authentication_classes = (SessionAuthentication, ) + authentication_classes = (SessionAuthentication,) serializer_class = ProposalSerializer sort_definitions = [ - FancyListApiView.SortDefinition( - 'date_submitted', - _('Datum ingediend') - ), - FancyListApiView.SortDefinition( - 'date_reviewed', - _('Datum afgerond') - ), - FancyListApiView.SortDefinition( - 'date_modified', - _('Laatst bijgewerkt') - ), + FancyListApiView.SortDefinition("date_submitted", _("Datum ingediend")), + FancyListApiView.SortDefinition("date_reviewed", _("Datum afgerond")), + FancyListApiView.SortDefinition("date_modified", _("Laatst bijgewerkt")), ] - default_sort = ('date_modified', 'desc') + default_sort = ("date_modified", "desc") def get_my_proposals(self): - return Proposal.objects.filter( - Q(applicants=self.request.user) | Q(supervisor=self.request.user) - ).distinct().select_related( # this optimizes the loading a bit - 'supervisor', 'parent', 'relation', - 'parent__supervisor', 'parent__relation', - ).prefetch_related( - 'applicants', 'review_set', 'parent__review_set', 'study_set', - 'study_set__observation', 'study_set__session_set', - 'study_set__intervention', 'study_set__session_set__task_set' + return ( + Proposal.objects.filter( + Q(applicants=self.request.user) | Q(supervisor=self.request.user) + ) + .distinct() + .select_related( # this optimizes the loading a bit + "supervisor", + "parent", + "relation", + "parent__supervisor", + "parent__relation", + ) + .prefetch_related( + "applicants", + "review_set", + "parent__review_set", + "study_set", + "study_set__observation", + "study_set__session_set", + "study_set__intervention", + "study_set__session_set__task_set", + ) ) def get_context(self): context = super().get_context() - context['is_secretary'] = is_secretary(self.request.user) - context['proposal'] = { - 'SUBMITTED_TO_SUPERVISOR': Proposal.SUBMITTED_TO_SUPERVISOR, - 'DECISION_MADE': Proposal.DECISION_MADE, + context["is_secretary"] = is_secretary(self.request.user) + context["proposal"] = { + "SUBMITTED_TO_SUPERVISOR": Proposal.Statuses.SUBMITTED_TO_SUPERVISOR, + "DECISION_MADE": Proposal.Statuses.DECISION_MADE, } - context['review'] = { - 'REVISION': Review.REVISION, + context["review"] = { + "REVISION": Review.Continuations.REVISION, } - context['user_pk'] = self.request.user.pk + context["user_pk"] = self.request.user.pk return context class MyProposalsApiView(BaseProposalsApiView): - def get_queryset(self): """Returns all Proposals for the current User""" return self.get_my_proposals() class MyConceptsApiView(BaseProposalsApiView): - sort_definitions = [ - FancyListApiView.SortDefinition( - 'date_modified', - _('Laatst bijgewerkt') - ), + FancyListApiView.SortDefinition("date_modified", _("Laatst bijgewerkt")), ] def get_queryset(self): """Returns all non-submitted Proposals for the current User""" return self.get_my_proposals().filter( - status__lt=Proposal.SUBMITTED_TO_SUPERVISOR + status__lt=Proposal.Statuses.SUBMITTED_TO_SUPERVISOR ) class MySubmittedApiView(BaseProposalsApiView): sort_definitions = [ - FancyListApiView.SortDefinition( - 'date_submitted', - _('Datum ingediend') - ), - FancyListApiView.SortDefinition( - 'date_modified', - _('Laatst bijgewerkt') - ), + FancyListApiView.SortDefinition("date_submitted", _("Datum ingediend")), + FancyListApiView.SortDefinition("date_modified", _("Laatst bijgewerkt")), ] - default_sort = ('date_submitted', 'desc') + default_sort = ("date_submitted", "desc") def get_queryset(self): """Returns all submitted Proposals for the current User""" return self.get_my_proposals().filter( - status__gte=Proposal.SUBMITTED_TO_SUPERVISOR, - status__lt=Proposal.DECISION_MADE + status__gte=Proposal.Statuses.SUBMITTED_TO_SUPERVISOR, + status__lt=Proposal.Statuses.DECISION_MADE, ) class MyCompletedApiView(BaseProposalsApiView): - def get_queryset(self): """Returns all completed Proposals for the current User""" return self.get_my_proposals().filter( - status__gte=Proposal.DECISION_MADE + status__gte=Proposal.Statuses.DECISION_MADE ) class MySupervisedApiView(BaseProposalsApiView): sort_definitions = [ + FancyListApiView.SortDefinition("date_submitted", _("Datum ingediend")), FancyListApiView.SortDefinition( - 'date_submitted', - _('Datum ingediend') - ), - FancyListApiView.SortDefinition( - 'date_submitted_supervisor', - _('Datum ingediend bij eindverantwoordelijke') - ), - FancyListApiView.SortDefinition( - 'date_reviewed', - _('Datum afgerond') - ), - FancyListApiView.SortDefinition( - 'date_modified', - _('Laatst bijgewerkt') + "date_submitted_supervisor", _("Datum ingediend bij eindverantwoordelijke") ), + FancyListApiView.SortDefinition("date_reviewed", _("Datum afgerond")), + FancyListApiView.SortDefinition("date_modified", _("Laatst bijgewerkt")), ] - default_sort = ('date_submitted_supervisor', 'desc') + default_sort = ("date_submitted_supervisor", "desc") def get_context(self): context = super().get_context() - context['wants_route_info'] = True + context["wants_route_info"] = True return context def get_queryset(self): """Returns all Proposals supervised by the current User""" - return Proposal.objects.filter( - supervisor=self.request.user - ) + return Proposal.objects.filter(supervisor=self.request.user) class MyPracticeApiView(BaseProposalsApiView): sort_definitions = [ - FancyListApiView.SortDefinition( - 'date_modified', - _('Laatst bijgewerkt') - ), + FancyListApiView.SortDefinition("date_modified", _("Laatst bijgewerkt")), ] def get_queryset(self): """Returns all practice Proposals for the current User""" return Proposal.objects.filter( Q(in_course=True) | Q(is_exploration=True), - Q(applicants=self.request.user) | - Q(supervisor=self.request.user) + Q(applicants=self.request.user) | Q(supervisor=self.request.user), ) class ProposalArchiveApiView(CommitteeMixin, BaseProposalsApiView): sort_definitions = [ - FancyListApiView.SortDefinition( - 'date_submitted', - _('Datum ingediend') - ), - FancyListApiView.SortDefinition( - 'date_reviewed', - _('Datum afgerond') - ), + FancyListApiView.SortDefinition("date_submitted", _("Datum ingediend")), + FancyListApiView.SortDefinition("date_reviewed", _("Datum afgerond")), ] - default_sort = ('date_reviewed', 'desc') + default_sort = ("date_reviewed", "desc") def get(self, *args, **kwargs): return super().get(*args, **kwargs) diff --git a/proposals/copy.py b/proposals/copy.py index 461164d81..612a1dd28 100644 --- a/proposals/copy.py +++ b/proposals/copy.py @@ -18,18 +18,16 @@ def copy_proposal(original_proposal, is_revision, created_by_user): copy_proposal.pk = None copy_wmo = None - if hasattr(original_proposal, 'wmo'): + if hasattr(original_proposal, "wmo"): copy_wmo = original_proposal.wmo if is_revision: - copy_proposal.reference_number = generate_revision_ref_number( - original_proposal - ) + copy_proposal.reference_number = generate_revision_ref_number(original_proposal) else: copy_proposal.reference_number = generate_ref_number() copy_proposal.created_by = created_by_user - copy_proposal.status = Proposal.DRAFT + copy_proposal.status = Proposal.Statuses.DRAFT copy_proposal.status_review = None copy_proposal.pdf = None copy_proposal.date_created = timezone.now() diff --git a/proposals/field.py b/proposals/field.py index 1c7d6a245..89b097cad 100644 --- a/proposals/field.py +++ b/proposals/field.py @@ -11,16 +11,11 @@ class ParentChoiceModelField(ModelChoiceField): This is done so we don't have to change the default __str__, just to make this form different. """ + def label_from_instance(self, obj: Proposal): last_modified = obj.date_modified.strftime("%b %d %Y %H:%M") if obj.is_practice(): - return '{} - {} ({}) (Practice)'.format( - obj.reference_number, - obj.title, - last_modified + return "{} - {} ({}) (Practice)".format( + obj.reference_number, obj.title, last_modified ) - return '{} - {} ({})'.format( - obj.reference_number, - obj.title, - last_modified - ) + return "{} - {} ({})".format(obj.reference_number, obj.title, last_modified) diff --git a/proposals/fixtures/testing/test_proposals.json b/proposals/fixtures/testing/test_proposals.json new file mode 100644 index 000000000..874f6c230 --- /dev/null +++ b/proposals/fixtures/testing/test_proposals.json @@ -0,0 +1,189 @@ +[ +{ + "model": "proposals.proposal", + "pk": 1, + "fields": { + "reference_number": "23-003-01", + "reviewing_committee": 3, + "institution": 2, + "date_start": "2025-01-01", + "title": "Fixture proposal", + "summary": "asdf", + "other_applicants": false, + "other_stakeholders": false, + "stakeholders": "", + "translated_forms": true, + "translated_forms_languages": "asdf", + "funding_details": "", + "funding_name": "", + "comments": "asdf", + "inform_local_staff": true, + "embargo": true, + "embargo_end_date": "2024-09-01", + "in_archive": false, + "is_pre_assessment": false, + "pre_assessment_pdf": "", + "is_pre_approved": null, + "pre_approval_institute": null, + "pre_approval_pdf": "", + "in_course": false, + "is_exploration": false, + "pdf": "FETC-AK-23-003-01-Proposal.pdf", + "studies_similar": false, + "studies_number": 3, + "status": 1, + "status_review": null, + "dmp_file": "FETC-AK-23-003-01-DMP.pdf", + "confirmation_comments": "", + "date_created": "2023-11-28T12:59:17.670Z", + "date_modified": "2023-11-28T13:36:55.297Z", + "date_submitted_supervisor": null, + "date_reviewed_supervisor": null, + "date_submitted": "2023-11-28T13:36:55.296Z", + "date_reviewed": null, + "date_confirmed": null, + "has_minor_revision": false, + "minor_revision_description": null, + "self_assessment": "asdf", + "relation": 5, + "student_program": "", + "student_context": null, + "student_context_details": null, + "student_justification": "", + "created_by": 5, + "supervisor": null, + "parent": null, + "is_revision": false, + "funding": [ + 1 + ], + "applicants": [ + 5 + ] + } +}, +{ + "model": "proposals.proposal", + "pk": 2, + "fields": { + "reference_number": "23-004-01", + "reviewing_committee": 3, + "institution": 2, + "date_start": "2024-08-01", + "title": "Fixture Preassessment", + "summary": "", + "other_applicants": false, + "other_stakeholders": true, + "stakeholders": "asdf", + "translated_forms": null, + "translated_forms_languages": null, + "funding_details": "", + "funding_name": "", + "comments": "asdf", + "inform_local_staff": null, + "embargo": true, + "embargo_end_date": "2024-11-01", + "in_archive": false, + "is_pre_assessment": true, + "pre_assessment_pdf": "FETC-AK-23-004-01-Preassessment.pdf", + "is_pre_approved": null, + "pre_approval_institute": null, + "pre_approval_pdf": "", + "in_course": false, + "is_exploration": false, + "pdf": "FETC-AK-23-004-01-Proposal.pdf", + "studies_similar": null, + "studies_number": 1, + "status": 1, + "status_review": null, + "dmp_file": "", + "confirmation_comments": "", + "date_created": "2023-11-28T14:10:12.708Z", + "date_modified": "2023-11-28T14:10:40.554Z", + "date_submitted_supervisor": null, + "date_reviewed_supervisor": null, + "date_submitted": "2023-11-28T14:10:40.554Z", + "date_reviewed": null, + "date_confirmed": null, + "has_minor_revision": false, + "minor_revision_description": null, + "self_assessment": "asdf", + "relation": 5, + "student_program": "", + "student_context": null, + "student_context_details": null, + "student_justification": "", + "created_by": 5, + "supervisor": null, + "parent": null, + "is_revision": false, + "funding": [], + "applicants": [ + 5 + ] + } +}, +{ + "model": "proposals.proposal", + "pk": 3, + "fields": { + "reference_number": "23-005-01", + "reviewing_committee": 3, + "institution": 2, + "date_start": "2024-08-01", + "title": "Fixture Preapproval", + "summary": "asdf", + "other_applicants": false, + "other_stakeholders": false, + "stakeholders": "", + "translated_forms": null, + "translated_forms_languages": null, + "funding_details": "", + "funding_name": "", + "comments": "asdf", + "inform_local_staff": null, + "embargo": true, + "embargo_end_date": "2025-01-10", + "in_archive": false, + "is_pre_assessment": false, + "pre_assessment_pdf": "", + "is_pre_approved": true, + "pre_approval_institute": "asdf", + "pre_approval_pdf": "FETC-AK-23-005-01-Pre_Approval.pdf", + "in_course": false, + "is_exploration": false, + "pdf": "FETC-AK-23-005-01-Proposal.pdf", + "studies_similar": null, + "studies_number": 1, + "status": 1, + "status_review": null, + "dmp_file": "", + "confirmation_comments": "", + "date_created": "2023-11-28T14:28:19.045Z", + "date_modified": "2023-11-28T14:28:31.971Z", + "date_submitted_supervisor": null, + "date_reviewed_supervisor": null, + "date_submitted": "2023-11-28T14:28:31.971Z", + "date_reviewed": null, + "date_confirmed": null, + "has_minor_revision": false, + "minor_revision_description": null, + "self_assessment": "asdf", + "relation": 5, + "student_program": "", + "student_context": null, + "student_context_details": null, + "student_justification": "", + "created_by": 5, + "supervisor": null, + "parent": null, + "is_revision": false, + "funding": [ + 1 + ], + "applicants": [ + 5 + ] + } +} +] diff --git a/proposals/fixtures/testing/test_users.json b/proposals/fixtures/testing/test_users.json new file mode 100644 index 000000000..11188c79c --- /dev/null +++ b/proposals/fixtures/testing/test_users.json @@ -0,0 +1,20 @@ +[ +{ + "model": "auth.user", + "pk": 5, + "fields": { + "password": "pbkdf2_sha256$260000$So7oUMXGw1byCufugyqL0M$mE0guFb1Y34YeurnLiVJcbJrliV1FB33OnuJYlFnhf0=", + "last_login": "2023-11-28T12:55:06.786Z", + "is_superuser": false, + "username": "proposal_user", + "first_name": "Testing", + "last_name": "User", + "email": "testing@user.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-05-19T11:24:30.512Z", + "groups": [], + "user_permissions": [] + } +} +] diff --git a/proposals/forms.py b/proposals/forms.py index fee52a503..9adf50bbb 100644 --- a/proposals/forms.py +++ b/proposals/forms.py @@ -10,10 +10,11 @@ from django.utils.safestring import mark_safe from django.utils import timezone from datetime import timedelta + mark_safe_lazy = lazy(mark_safe, str) from main.forms import ConditionalModelForm, SoftValidationMixin -from main.models import DOUBT, NO, YES, YES_NO_DOUBT +from main.models import YesNoDoubt from main.utils import YES_NO, get_users_as_list from .field import ParentChoiceModelField from .models import Proposal, Relation, Wmo @@ -21,63 +22,78 @@ from .validators import UniqueTitleValidator from .widgets import SelectMultipleUser, SelectUser +from cdh.core.forms import DateField + -class ProposalForm(UserKwargModelFormMixin, SoftValidationMixin, - ConditionalModelForm): +class ProposalForm(UserKwargModelFormMixin, SoftValidationMixin, ConditionalModelForm): class Meta: model = Proposal fields = [ - 'is_pre_approved', - 'institution', - 'relation', 'student_program', 'student_context', - 'student_context_details', 'student_justification', - 'supervisor', 'other_applicants', 'applicants', - 'other_stakeholders', 'stakeholders', - 'date_start', 'title', - 'summary', 'pre_assessment_pdf', - 'funding', 'funding_details', 'funding_name', - 'pre_approval_institute', 'pre_approval_pdf', 'self_assessment', + "is_pre_approved", + "institution", + "relation", + "student_program", + "student_context", + "student_context_details", + "student_justification", + "supervisor", + "other_applicants", + "applicants", + "other_stakeholders", + "stakeholders", + "date_start", + "title", + "summary", + "pre_assessment_pdf", + "funding", + "funding_details", + "funding_name", + "pre_approval_institute", + "pre_approval_pdf", + "self_assessment", ] labels = { - 'other_stakeholders': mark_safe_lazy(_('Zijn er nog andere onderzoekers bij deze aanvraag betrokken ' \ - 'die niet geaffilieerd zijn aan een van de ' \ - 'onderzoeksinstituten van de Faculteit Geestwetenschappen van de ' \ - 'UU? ')), - } + "other_stakeholders": mark_safe_lazy( + _( + "Zijn er nog andere onderzoekers bij deze aanvraag betrokken " + "die niet geaffilieerd zijn aan een van de " + "onderzoeksinstituten van de Faculteit Geestwetenschappen van de " + "UU? " + ) + ), + } widgets = { - 'is_pre_approved': forms.RadioSelect(choices=YES_NO), - 'institution': forms.RadioSelect(), - 'relation': forms.RadioSelect(), - 'student_context': forms.RadioSelect(), - 'other_applicants': forms.RadioSelect(choices=YES_NO), - 'other_stakeholders': forms.RadioSelect(choices=YES_NO), - 'summary': forms.Textarea(attrs={ - 'cols': 50 - }), - 'funding': forms.CheckboxSelectMultiple(), - 'applicants': SelectMultipleUser(), - 'supervisor': SelectUser(), + "is_pre_approved": forms.RadioSelect(choices=YES_NO), + "institution": forms.RadioSelect(), + "relation": forms.RadioSelect(), + "student_context": forms.RadioSelect(), + "other_applicants": forms.RadioSelect(choices=YES_NO), + "other_stakeholders": forms.RadioSelect(choices=YES_NO), + "summary": forms.Textarea(attrs={"cols": 50}), + "funding": forms.CheckboxSelectMultiple(), + "applicants": SelectMultipleUser(), + "supervisor": forms.Select(), } error_messages = { - 'title': { - 'unique': _('Er bestaat al een aanvraag met deze titel.'), + "title": { + "unique": _("Er bestaat al een aanvraag met deze titel."), }, } - _soft_validation_fields = ['relation', - 'supervisor', - 'other_applicants', - 'other_stakeholders', - 'stakeholders', - 'summary', - 'pre_assessment_pdf', - 'funding', - 'funding_details', - 'funding_name', - 'pre_approval_institute', - 'pre_approval_pdf', - 'self_assessment', - ] + _soft_validation_fields = [ + "relation", + "other_applicants", + "other_stakeholders", + "stakeholders", + "summary", + "pre_assessment_pdf", + "funding", + "funding_details", + "funding_name", + "pre_approval_institute", + "pre_approval_pdf", + "self_assessment", + ] def __init__(self, *args, **kwargs): """ @@ -90,82 +106,83 @@ def __init__(self, *args, **kwargs): - Remove summary for preliminary assessment Proposals - Set pre_assessment_pdf required for preliminary assessment Proposals, otherwise remove """ - in_course = kwargs.pop('in_course', False) - is_pre_approved = kwargs.pop('is_pre_approved', False) + in_course = kwargs.pop("in_course", False) + is_pre_approved = kwargs.pop("is_pre_approved", False) # First, try to determine this value from the kwargs. Otherwise, try # to get it from the instance. If that fails, assume False self.is_pre_assessment = kwargs.pop( - 'is_pre_assessment', - getattr( - kwargs.get('instance'), - 'is_pre_assessment', - False - ) + "is_pre_assessment", + getattr(kwargs.get("instance"), "is_pre_assessment", False), ) - super(ProposalForm, self).__init__(*args, **kwargs) - self.fields['relation'].empty_label = None - self.fields['institution'].empty_label = None - self.fields['student_context'].empty_label = None + self.fields["relation"].empty_label = None + self.fields["institution"].empty_label = None + self.fields["student_context"].empty_label = None # Only revisions or amendments are allowed to have a title that's not # unique. if not self.instance or not self.instance.is_revision: - self.fields['title'].validators.append( - UniqueTitleValidator(self.instance) - ) + self.fields["title"].validators.append(UniqueTitleValidator(self.instance)) applicants = get_user_model().objects.all() supervisors = applicants.exclude(pk=self.user.pk) - instance = kwargs.get('instance') + instance = kwargs.get("instance") - self.fields['other_stakeholders'].label = mark_safe( - self.fields['other_stakeholders'].label) + self.fields["other_stakeholders"].label = mark_safe( + self.fields["other_stakeholders"].label + ) # If you are already defined as a supervisor, we have to set it to you if instance is not None and instance.supervisor == self.user: supervisors = [self.user] - self.fields['supervisor'].choices = [(None, _( - 'Selecteer...'))] + get_users_as_list(supervisors) - self.fields['applicants'].choices = get_users_as_list(applicants) + self.fields["supervisor"].choices = [ + (None, _("Selecteer...")) + ] + get_users_as_list(supervisors) + + self.fields["applicants"].choices = get_users_as_list(applicants) if in_course: - self.fields['relation'].queryset = Relation.objects.filter( - check_in_course=True) - self.fields['supervisor'].label = _('Docent') - self.fields['supervisor'].help_text = _('Vul hier de docent van \ + self.fields["relation"].queryset = Relation.objects.filter( + check_in_course=True + ) + self.fields["supervisor"].label = _("Docent") + self.fields["supervisor"].help_text = _( + "Vul hier de docent van \ de cursus in waarbinnen je deze portal moet doorlopen. De docent kan na afloop \ de aanvraag inkijken in de portal. De studie zal niet in het semipublieke archief \ -van het FETC-GW worden opgenomen.') +van het FETC-GW worden opgenomen." + ) if self.is_pre_assessment: - self.fields['relation'].queryset = Relation.objects.filter( - check_pre_assessment=True) - self.fields['pre_assessment_pdf'].required = True - del self.fields['summary'] - del self.fields['funding'] - del self.fields['funding_details'] - del self.fields['funding_name'] + self.fields["relation"].queryset = Relation.objects.filter( + check_pre_assessment=True + ) + self.fields["pre_assessment_pdf"].required = True + del self.fields["summary"] + del self.fields["funding"] + del self.fields["funding_details"] + del self.fields["funding_name"] else: - del self.fields['pre_assessment_pdf'] + del self.fields["pre_assessment_pdf"] if is_pre_approved: - self.fields['pre_approval_institute'].required = True - self.fields['pre_approval_pdf'].required = True + self.fields["pre_approval_institute"].required = True + self.fields["pre_approval_pdf"].required = True else: - del self.fields['is_pre_approved'] - del self.fields['pre_approval_institute'] - del self.fields['pre_approval_pdf'] + del self.fields["is_pre_approved"] + del self.fields["pre_approval_institute"] + del self.fields["pre_approval_pdf"] def clean(self): """ Check for conditional requirements: - If relation needs supervisor, make sure supervisor is set + - If relation needs supervisor, make sure supervisor is a different person - If other_applicants is checked, make sure applicants are set - If other_stakeholders is checked, make sure stakeholders is not empty - Maximum number of words for summary @@ -176,128 +193,142 @@ def clean(self): cleaned_data = super(ProposalForm, self).clean() if not self.is_pre_assessment: - self.mark_soft_required(cleaned_data, 'funding') - self.mark_soft_required(cleaned_data, 'summary') + self.mark_soft_required(cleaned_data, "funding") + self.mark_soft_required(cleaned_data, "summary") - self.mark_soft_required(cleaned_data, 'relation') - self.mark_soft_required(cleaned_data, 'date_start') + self.mark_soft_required(cleaned_data, "relation") + self.mark_soft_required(cleaned_data, "date_start") - relation = cleaned_data.get('relation') - if relation and relation.needs_supervisor and \ - not cleaned_data.get('supervisor'): + relation = cleaned_data.get("relation") + supervisor = cleaned_data.get("supervisor") + + if relation and relation.needs_supervisor and not supervisor: error = forms.ValidationError( - _('Je dient een eindverantwoordelijke op te geven.'), - code='required') - self.add_error('supervisor', error) + _("Je dient een promotor/begeleider op te geven."), code="required" + ) + self.add_error("supervisor", error) + + if relation and relation.needs_supervisor and supervisor == self.user: + error = forms.ValidationError( + _("Je kunt niet jezelf als promotor/begeleider opgeven.") + ) + self.add_error("supervisor", error) if relation.check_in_course: - self.mark_soft_required(cleaned_data, 'student_context') - self.mark_soft_required(cleaned_data, 'student_justification') + self.mark_soft_required(cleaned_data, "student_context") + self.mark_soft_required(cleaned_data, "student_justification") - other_applicants = cleaned_data.get('other_applicants') - applicants = cleaned_data.get('applicants') - supervisor = cleaned_data.get('supervisor') + other_applicants = cleaned_data.get("other_applicants") + applicants = cleaned_data.get("applicants") # Always make sure the applicant is actually in the applicants list if self.user not in applicants and self.user != supervisor: error = forms.ValidationError( - _('Je hebt jezelf niet als onderzoekers geselecteerd.'), - code='required') - self.add_error('applicants', error) + _("Je hebt jezelf niet als onderzoekers geselecteerd."), code="required" + ) + self.add_error("applicants", error) elif other_applicants and len(applicants) == 1: error = forms.ValidationError( - _('Je hebt geen andere onderzoekers geselecteerd.'), - code='required') - self.add_error('applicants', error) + _("Je hebt geen andere onderzoekers geselecteerd."), code="required" + ) + self.add_error("applicants", error) # Add an error if self_assessment is missing - self_assessment = cleaned_data.get('self_assessment') - if self_assessment == '': + self_assessment = cleaned_data.get("self_assessment") + if self_assessment == "": self.add_error( - 'self_assessment', + "self_assessment", forms.ValidationError( - _('Dit veld is verplicht, maar je kunt later terugkomen om hem \ - verder in te vullen.'), - code='required', - ) + _( + "Dit veld is verplicht, maar je kunt later terugkomen om hem \ + verder in te vullen." + ), + code="required", + ), ) - if 'is_pre_approved' in cleaned_data: - if not cleaned_data['is_pre_approved']: + if "is_pre_approved" in cleaned_data: + if not cleaned_data["is_pre_approved"]: error = forms.ValidationError( _( - 'Indien je geen toestemming hebt van een andere ethische commissie, dien je het normale formulier in ' + "Indien je geen toestemming hebt van een andere ethische commissie, dien je het normale formulier in " 'te vullen. Ga terug naar de startpagina, en selecteer "Een nieuwe aanvraag aanmelden (from scratch in ' - 'een leeg formulier)" of "Een nieuwe aanvraag aanmelden (vanuit een kopie van een oude aanvraag)".') + 'een leeg formulier)" of "Een nieuwe aanvraag aanmelden (vanuit een kopie van een oude aanvraag)".' + ) ) - self.add_error('is_pre_approved', error) - - self.check_dependency(cleaned_data, 'is_pre_approved', - 'pre_approval_pdf') - self.check_dependency(cleaned_data, 'is_pre_approved', - 'pre_approval_institute') - - self.check_dependency(cleaned_data, 'other_stakeholders', - 'stakeholders') - self.check_dependency_multiple(cleaned_data, 'funding', 'needs_details', - 'funding_details') - self.check_dependency_multiple(cleaned_data, 'funding', 'needs_name', - 'funding_name') - self.check_dependency_singular(cleaned_data, 'relation', 'check_in_course', - 'student_program') - self.check_dependency_singular(cleaned_data, 'student_context', 'needs_details', - 'student_context_details') - self.check_dependency_singular(cleaned_data, 'relation', 'check_in_course', - 'student_justification') + self.add_error("is_pre_approved", error) + + self.check_dependency(cleaned_data, "is_pre_approved", "pre_approval_pdf") + self.check_dependency( + cleaned_data, "is_pre_approved", "pre_approval_institute" + ) + + self.check_dependency(cleaned_data, "other_stakeholders", "stakeholders") + self.check_dependency_multiple( + cleaned_data, "funding", "needs_details", "funding_details" + ) + self.check_dependency_multiple( + cleaned_data, "funding", "needs_name", "funding_name" + ) + self.check_dependency_singular( + cleaned_data, "relation", "check_in_course", "student_program" + ) + self.check_dependency_singular( + cleaned_data, "student_context", "needs_details", "student_context_details" + ) + self.check_dependency_singular( + cleaned_data, "relation", "check_in_course", "student_justification" + ) class ProposalStartPracticeForm(forms.Form): practice_reason = forms.ChoiceField( - label=_('Ik maak een oefenaanvraag aan'), - choices=Proposal.PRACTICE_REASONS, - widget=forms.RadioSelect()) + label=_("Ik maak een oefenaanvraag aan"), + choices=Proposal.PracticeReasons.choices, + widget=forms.RadioSelect(), + ) class BaseProposalCopyForm(UserKwargModelFormMixin, forms.ModelForm): class Meta: model = Proposal - fields = ['parent', 'is_revision'] + fields = ["parent", "is_revision"] widgets = { - 'is_revision': forms.HiddenInput(), - } - error_messages = { - 'title': { - 'unique': _('Er bestaat al een aanvraag met deze titel.'), - }, + "is_revision": forms.HiddenInput(), } parent = ParentChoiceModelField( queryset=Proposal.objects.all(), - label=_('Te kopiëren aanvraag'), + label=_("Te kopiëren aanvraag"), help_text=_( - 'Dit veld toont enkel aanvragen waar je zelf een medeuitvoerende ' - 'bent.' + "Dit veld toont enkel aanvragen waar je zelf een medeuitvoerende " "bent." ), ) def __init__(self, *args, **kwargs): super(BaseProposalCopyForm, self).__init__(*args, **kwargs) - self.fields['parent'].queryset = self._get_parent_queryset() + self.fields["parent"].queryset = self._get_parent_queryset() def _get_parent_queryset(self): # Return all non-pre-assessments, that are not currently in review - return Proposal.objects.filter( - is_pre_assessment=False - ).filter( - Q(applicants=self.user, ) | Q(supervisor=self.user) - ).filter( - Q(status=Proposal.DRAFT) | Q(status__gte=Proposal.DECISION_MADE) - ).distinct() + return ( + Proposal.objects.filter(is_pre_assessment=False) + .filter( + Q( + applicants=self.user, + ) + | Q(supervisor=self.user) + ) + .filter( + Q(status=Proposal.Statuses.DRAFT) + | Q(status__gte=Proposal.Statuses.DECISION_MADE) + ) + .distinct() + ) class ProposalCopyForm(BaseProposalCopyForm): - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Only revisions or amendments are allowed to have a title that's not @@ -309,102 +340,92 @@ def __init__(self, *args, **kwargs): class RevisionProposalCopyForm(BaseProposalCopyForm): - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - - if 'title' in self.fields: - self.fields['title'].label = _('Je kan de titel van je aanvraag nu, ' - 'indien nodig, wijzigen.') - self.fields['title'].help_text = _('De titel die je hier opgeeft is ' - 'zichtbaar voor de FETC-GW-leden en,' - ' wanneer de aanvraag is goedgekeurd,' - ' ook voor alle medewerkers die in' - ' het archief van deze portal ' - 'kijken.') - - self.fields['parent'].label = _('Te reviseren aanvraag') - self.fields['parent'].help_text = _('Dit veld toont enkel ingediende,' - ' (nog) niet goedgekeurde aanvragen ' - 'waar jij een ' - 'medeuitvoerende bent.') + self.fields["parent"].label = _("Te reviseren aanvraag") + self.fields["parent"].help_text = _( + "Dit veld toont enkel ingediende," + " (nog) niet goedgekeurde aanvragen " + "waar jij een " + "medeuitvoerende bent." + ) def _get_parent_queryset(self): # Select non-pre-assessments that have been reviewed and rejected and # haven't been parented yet. # Those are eligible for revisions - return Proposal.objects.filter( - is_pre_assessment=False, - status=Proposal.DECISION_MADE, - status_review=False, - children__isnull=True, - ).filter( - Q(applicants=self.user, ) | Q(supervisor=self.user) - ).distinct() + return ( + Proposal.objects.filter( + is_pre_assessment=False, + status=Proposal.Statuses.DECISION_MADE, + status_review=False, + children__isnull=True, + ) + .filter( + Q( + applicants=self.user, + ) + | Q(supervisor=self.user) + ) + .distinct() + ) class AmendmentProposalCopyForm(BaseProposalCopyForm): - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if 'title' in self.fields: - self.fields['title'].label = _('Je kan de titel van je aanvraag nu, ' - 'indien nodig, wijzigen.') - self.fields['title'].help_text = _('De titel die je hier opgeeft is ' - 'zichtbaar voor de FETC-GW-leden en,' - ' wanneer de aanvraag is goedgekeurd,' - ' ook voor alle medewerkers die in' - ' het archief van deze portal ' - 'kijken.') - - self.fields['parent'].label = _('Te amenderen aanvraag') - self.fields['parent'].help_text = _('Dit veld toont enkel goedgekeurde' - ' aanvragen waar je zelf een ' - 'medeuitvoerende bent.') + self.fields["parent"].label = _("Te amenderen aanvraag") + self.fields["parent"].help_text = _( + "Dit veld toont enkel goedgekeurde" + " aanvragen waar je zelf een " + "medeuitvoerende bent." + ) def _get_parent_queryset(self): # Select non-pre-assessments that have been reviewed and approved and # haven't been parented yet. # Those are eligible for amendments - return Proposal.objects.filter( - is_pre_assessment=False, - status_review=True, - children__isnull=True, - ).filter( - Q(applicants=self.user, ) | Q(supervisor=self.user) - ).distinct() + return ( + Proposal.objects.filter( + is_pre_assessment=False, + status_review=True, + children__isnull=True, + ) + .filter( + Q( + applicants=self.user, + ) + | Q(supervisor=self.user) + ) + .distinct() + ) class ProposalConfirmationForm(forms.ModelForm): class Meta: model = Proposal - fields = ['date_confirmed', 'confirmation_comments'] + fields = ["date_confirmed", "confirmation_comments"] class WmoForm(SoftValidationMixin, ConditionalModelForm): class Meta: model = Wmo - fields = [ - 'metc', 'metc_details', 'metc_institution', - 'is_medical'] - widgets = { - 'metc': forms.RadioSelect(), - 'is_medical': forms.RadioSelect()} + fields = ["metc", "metc_details", "metc_institution", "is_medical"] + widgets = {"metc": forms.RadioSelect(), "is_medical": forms.RadioSelect()} - _soft_validation_fields = ['metc_details', 'metc_institution', - 'is_medical'] + _soft_validation_fields = ["metc_details", "metc_institution", "is_medical"] def __init__(self, *args, **kwargs): """ - Remove empty label from is_medical/is_behavioristic field and reset the choices """ super(WmoForm, self).__init__(*args, **kwargs) - self.fields['metc'].empty_label = None - self.fields['metc'].choices = YES_NO_DOUBT - self.fields['is_medical'].empty_label = None - self.fields['is_medical'].choices = YES_NO_DOUBT + self.fields["metc"].empty_label = None + self.fields["metc"].choices = YesNoDoubt.choices + self.fields["is_medical"].empty_label = None + self.fields["is_medical"].choices = YesNoDoubt.choices def clean(self): """ @@ -414,29 +435,37 @@ def clean(self): """ cleaned_data = super(WmoForm, self).clean() - if 'metc' not in cleaned_data or not cleaned_data['metc']: - self.add_error('metc', _('Dit veld is verplicht om verder te ' - 'gaan.')) + if "metc" not in cleaned_data or not cleaned_data["metc"]: + self.add_error("metc", _("Dit veld is verplicht om verder te " "gaan.")) - self.check_dependency(cleaned_data, 'metc', 'metc_details', - f1_value=YES) - self.check_dependency(cleaned_data, 'metc', 'metc_institution', - f1_value=YES, - error_message=_( - 'Je dient een instelling op te geven.')) - self.check_dependency_list(cleaned_data, 'metc', 'is_medical', - f1_value_list=[NO, DOUBT]) + self.check_dependency( + cleaned_data, "metc", "metc_details", f1_value=YesNoDoubt.YES + ) + self.check_dependency( + cleaned_data, + "metc", + "metc_institution", + f1_value=YesNoDoubt.YES, + error_message=_("Je dient een instelling op te geven."), + ) + self.check_dependency_list( + cleaned_data, + "metc", + "is_medical", + f1_value_list=[YesNoDoubt.NO, YesNoDoubt.DOUBT], + ) class WmoCheckForm(forms.ModelForm): class Meta: model = Wmo fields = [ - 'metc', 'is_medical', + "metc", + "is_medical", ] widgets = { - 'metc': forms.RadioSelect(), - 'is_medical': forms.RadioSelect(), + "metc": forms.RadioSelect(), + "is_medical": forms.RadioSelect(), } def __init__(self, *args, **kwargs): @@ -444,28 +473,28 @@ def __init__(self, *args, **kwargs): - Remove empty label from is_medical/is_behavioristic field and reset the choices """ super(WmoCheckForm, self).__init__(*args, **kwargs) - self.fields['is_medical'].empty_label = None - self.fields['is_medical'].choices = YES_NO_DOUBT + self.fields["is_medical"].empty_label = None + self.fields["is_medical"].choices = YesNoDoubt.choices class WmoApplicationForm(SoftValidationMixin, ConditionalModelForm): class Meta: model = Wmo fields = [ - 'metc_application', - 'metc_decision', - 'metc_decision_pdf', + "metc_application", + "metc_decision", + "metc_decision_pdf", ] widgets = { - 'metc_application': forms.RadioSelect(choices=YES_NO), - 'metc_decision': forms.RadioSelect(choices=YES_NO), + "metc_application": forms.RadioSelect(choices=YES_NO), + "metc_decision": forms.RadioSelect(choices=YES_NO), } _soft_validation_fields = [ - 'metc_application', - 'metc_decision', - 'metc_decision_pdf', - ] + "metc_application", + "metc_decision", + "metc_decision_pdf", + ] def clean(self): """ @@ -477,49 +506,69 @@ def clean(self): # A PDF is always required for this form, but it's in ProposalSubmit # validation that this is actually rejected. Otherwise this is soft # validation - if cleaned_data['metc_decision_pdf'] == None: + if cleaned_data["metc_decision_pdf"] == None: from django.forms import ValidationError - self.add_error('metc_decision_pdf', - ValidationError( - _('In dit geval is een beslissing van een METC vereist'), - ) - ) - return cleaned_data # Sticking to Django conventions + self.add_error( + "metc_decision_pdf", + ValidationError( + _("In dit geval is een beslissing van een METC vereist"), + ), + ) + + return cleaned_data # Sticking to Django conventions class StudyStartForm(forms.ModelForm): - study_name_1 = forms.CharField(label=_('Naam traject 1'), max_length=15, - required=False) - study_name_2 = forms.CharField(label=_('Naam traject 2'), max_length=15, - required=False) - study_name_3 = forms.CharField(label=_('Naam traject 3'), max_length=15, - required=False) - study_name_4 = forms.CharField(label=_('Naam traject 4'), max_length=15, - required=False) - study_name_5 = forms.CharField(label=_('Naam traject 5'), max_length=15, - required=False) - study_name_6 = forms.CharField(label=_('Naam traject 6'), max_length=15, - required=False) - study_name_7 = forms.CharField(label=_('Naam traject 7'), max_length=15, - required=False) - study_name_8 = forms.CharField(label=_('Naam traject 8'), max_length=15, - required=False) - study_name_9 = forms.CharField(label=_('Naam traject 9'), max_length=15, - required=False) - study_name_10 = forms.CharField(label=_('Naam traject 10'), max_length=15, - required=False) + study_name_1 = forms.CharField( + label=_("Naam traject 1"), max_length=15, required=False + ) + study_name_2 = forms.CharField( + label=_("Naam traject 2"), max_length=15, required=False + ) + study_name_3 = forms.CharField( + label=_("Naam traject 3"), max_length=15, required=False + ) + study_name_4 = forms.CharField( + label=_("Naam traject 4"), max_length=15, required=False + ) + study_name_5 = forms.CharField( + label=_("Naam traject 5"), max_length=15, required=False + ) + study_name_6 = forms.CharField( + label=_("Naam traject 6"), max_length=15, required=False + ) + study_name_7 = forms.CharField( + label=_("Naam traject 7"), max_length=15, required=False + ) + study_name_8 = forms.CharField( + label=_("Naam traject 8"), max_length=15, required=False + ) + study_name_9 = forms.CharField( + label=_("Naam traject 9"), max_length=15, required=False + ) + study_name_10 = forms.CharField( + label=_("Naam traject 10"), max_length=15, required=False + ) class Meta: model = Proposal fields = [ - 'studies_similar', 'studies_number', - 'study_name_1', 'study_name_2', 'study_name_3', 'study_name_4', - 'study_name_5', 'study_name_6', 'study_name_7', 'study_name_8', - 'study_name_9', 'study_name_10', + "studies_similar", + "studies_number", + "study_name_1", + "study_name_2", + "study_name_3", + "study_name_4", + "study_name_5", + "study_name_6", + "study_name_7", + "study_name_8", + "study_name_9", + "study_name_10", ] widgets = { - 'studies_similar': forms.RadioSelect(choices=YES_NO), + "studies_similar": forms.RadioSelect(choices=YES_NO), } def __init__(self, *args, **kwargs): @@ -527,12 +576,12 @@ def __init__(self, *args, **kwargs): - Set the Proposal for later reference - Set initial data for the study_name fields """ - self.proposal = kwargs.pop('proposal', None) + self.proposal = kwargs.pop("proposal", None) super(StudyStartForm, self).__init__(*args, **kwargs) for n, study in enumerate(self.proposal.study_set.all()): - study_name = 'study_name_' + str(n + 1) + study_name = "study_name_" + str(n + 1) self.fields[study_name].initial = study.name def clean(self): @@ -544,43 +593,65 @@ def clean(self): """ cleaned_data = super(StudyStartForm, self).clean() - if cleaned_data['studies_similar'] is None: - self.add_error('studies_similar', _('Dit veld is verplicht om ' - 'verder te gaan.')) - elif not cleaned_data['studies_similar']: - nr_studies = cleaned_data['studies_number'] - if cleaned_data['studies_number'] < 2: - self.add_error('studies_number', _( - 'Als niet dezelfde trajecten worden doorlopen, moeten er minstens twee verschillende trajecten zijn.')) + if cleaned_data["studies_similar"] is None: + self.add_error( + "studies_similar", _("Dit veld is verplicht om " "verder te gaan.") + ) + elif not cleaned_data["studies_similar"]: + nr_studies = cleaned_data["studies_number"] + if cleaned_data["studies_number"] < 2: + self.add_error( + "studies_number", + _( + "Als niet dezelfde trajecten worden doorlopen, moeten er minstens twee verschillende trajecten zijn." + ), + ) for n in range(nr_studies): if n >= 10: break - study_name = 'study_name_' + str(n + 1) + study_name = "study_name_" + str(n + 1) if not cleaned_data[study_name]: - self.add_error(study_name, _('Dit veld is verplicht.')) + self.add_error(study_name, _("Dit veld is verplicht.")) class ProposalDataManagementForm(SoftValidationMixin, forms.ModelForm): class Meta: model = Proposal - fields = ['avg_understood', 'dmp_file'] + fields = ["privacy_officer", "dmp_file"] + widgets = { + "privacy_officer": forms.RadioSelect(choices=YES_NO), + } + + def clean(self): + cleaned_data = super(ProposalDataManagementForm, self).clean() + + if cleaned_data["privacy_officer"] is None: + self.add_error( + "privacy_officer", _("Dit veld is verplicht om verder te gaan.") + ) - _soft_validation_fields = ['avg_understood'] class ProposalUpdateDataManagementForm(forms.ModelForm): class Meta: model = Proposal - fields = [ - 'dmp_file' - ] + fields = ["dmp_file"] + + +class ProposalUpdateDateStartForm(forms.ModelForm): + date_start = DateField(label=_("Nieuwe beoogde startdatum")) + + class Meta: + model = Proposal + fields = ["date_start"] + class ProposalSubmitForm(forms.ModelForm): class Meta: model = Proposal - fields = ['comments', 'inform_local_staff', 'embargo', 'embargo_end_date'] + fields = ["comments", "inform_local_staff", "embargo", "embargo_end_date"] widgets = { - 'inform_local_staff': forms.RadioSelect(choices=YES_NO), - 'embargo': forms.RadioSelect(choices=YES_NO), + "inform_local_staff": forms.RadioSelect(choices=YES_NO), + "embargo": forms.RadioSelect(choices=YES_NO), } def __init__(self, *args, **kwargs): @@ -588,20 +659,21 @@ def __init__(self, *args, **kwargs): - Mark the label of inform_local_staff as safe - Check if the inform_local_staff question should be asked """ - self.proposal = kwargs.pop('proposal', None) + self.proposal = kwargs.pop("proposal", None) # Needed for POST data - self.request = kwargs.pop('request', None) + self.request = kwargs.pop("request", None) super(ProposalSubmitForm, self).__init__(*args, **kwargs) - self.fields['inform_local_staff'].label_suffix = '' + self.fields["inform_local_staff"].label_suffix = "" - self.fields['inform_local_staff'].label = mark_safe( - self.fields['inform_local_staff'].label) + self.fields["inform_local_staff"].label = mark_safe( + self.fields["inform_local_staff"].label + ) if not check_local_facilities(self.proposal): - del self.fields['inform_local_staff'] + del self.fields["inform_local_staff"] def clean(self): """ @@ -614,66 +686,77 @@ def clean(self): cleaned_data = super(ProposalSubmitForm, self).clean() - if not self.instance.is_pre_assessment and \ - not self.instance.is_practice() and \ - not 'js-redirect-submit' in self.request.POST and \ - not 'save_back' in self.request.POST: - - if check_local_facilities(self.proposal) and cleaned_data[ - 'inform_local_staff'] is None: - self.add_error('inform_local_staff', _('Dit veld is verplicht.')) + if ( + not self.instance.is_pre_assessment + and not self.instance.is_practice() + and not "js-redirect-submit" in self.request.POST + and not "save_back" in self.request.POST + ): + if ( + check_local_facilities(self.proposal) + and cleaned_data["inform_local_staff"] is None + ): + self.add_error("inform_local_staff", _("Dit veld is verplicht.")) for study in self.instance.study_set.all(): documents = Documents.objects.get(study=study) if not documents.informed_consent: - self.add_error('comments', _( - 'Toestemmingsverklaring voor traject {} nog niet toegevoegd.').format( - study.order)) + self.add_error( + "comments", + _( + "Toestemmingsverklaring voor traject {} nog niet toegevoegd." + ).format(study.order), + ) if not documents.briefing: - self.add_error('comments', _( - 'Informatiebrief voor traject {} nog niet toegevoegd.').format( - study.order)) + self.add_error( + "comments", + _( + "Informatiebrief voor traject {} nog niet toegevoegd." + ).format(study.order), + ) - if cleaned_data['embargo'] is None: - self.add_error('embargo', _('Dit veld is verplicht.')) + if cleaned_data["embargo"] is None: + self.add_error("embargo", _("Dit veld is verplicht.")) - embargo_end_date = cleaned_data['embargo_end_date'] + embargo_end_date = cleaned_data["embargo_end_date"] two_years_from_now = timezone.now().date() + timezone.timedelta(days=730) - if embargo_end_date is not None and \ - embargo_end_date > two_years_from_now: - self.add_error('embargo_end_date', _( - 'De embargo-periode kan maximaal 2 jaar zijn. Kies een datum binnen 2 jaar van vandaag.')) - - + if embargo_end_date is not None and embargo_end_date > two_years_from_now: + self.add_error( + "embargo_end_date", + _( + "De embargo-periode kan maximaal 2 jaar zijn. Kies een datum binnen 2 jaar van vandaag." + ), + ) class TranslatedConsentForms(SoftValidationMixin, forms.ModelForm): - class Meta: model = Proposal - fields = ['translated_forms', 'translated_forms_languages'] + fields = ["translated_forms", "translated_forms_languages"] widgets = { - 'translated_forms': forms.RadioSelect(choices=YES_NO), + "translated_forms": forms.RadioSelect(choices=YES_NO), } - _soft_validation_fields = ['translated_forms', 'translated_forms_languages'] - + _soft_validation_fields = ["translated_forms", "translated_forms_languages"] + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - + def clean(self): cleaned_data = super(TranslatedConsentForms, self).clean() - if cleaned_data['translated_forms'] is None: + if cleaned_data["translated_forms"] is None: self.add_error( - 'translated_forms', - _('Dit veld is verplicht om verder te gaan.') + "translated_forms", _("Dit veld is verplicht om verder te gaan.") ) - - elif cleaned_data['translated_forms'] == True and not cleaned_data['translated_forms_languages']: + + elif ( + cleaned_data["translated_forms"] == True + and not cleaned_data["translated_forms_languages"] + ): self.add_error( - 'translated_forms_languages', - _('Vul in in welke talen de formulieren worden vertaald.') - ) \ No newline at end of file + "translated_forms_languages", + _("Vul in in welke talen de formulieren worden vertaald."), + ) diff --git a/proposals/management/commands/export_csv.py b/proposals/management/commands/export_csv.py index 815d22bf5..4f25722be 100644 --- a/proposals/management/commands/export_csv.py +++ b/proposals/management/commands/export_csv.py @@ -2,44 +2,43 @@ from django.core.management.base import BaseCommand -from proposals.utils.statistics_utils import get_qs_for_year, \ - get_registrations_for_proposal, get_studytypes_for_proposal +from proposals.utils.statistics_utils import ( + get_qs_for_year, + get_registrations_for_proposal, + get_studytypes_for_proposal, +) class Command(BaseCommand): - help = 'Exports reviewed Proposals' + help = "Exports reviewed Proposals" def add_arguments(self, parser): - parser.add_argument('year', type=int) + parser.add_argument("year", type=int) def handle(self, *args, **options): - - with open('output.csv', 'w') as csvfile: + with open("output.csv", "w") as csvfile: csv_writer = csv.writer( - csvfile, - delimiter=',', - quotechar='"', - quoting=csv.QUOTE_MINIMAL + csvfile, delimiter=",", quotechar='"', quoting=csv.QUOTE_MINIMAL ) header = [ - 'title', - 'reference_number', - 'reviewing committee', - 'type(s) of research', - 'registration type(s)', - 'applicant', - 'applicant type', - 'supervisor', - 'submitted on', - 'route', - 'conclusion', - 'concluded on' + "title", + "reference_number", + "reviewing committee", + "type(s) of research", + "registration type(s)", + "applicant", + "applicant type", + "supervisor", + "submitted on", + "route", + "conclusion", + "concluded on", ] csv_writer.writerow(header) rows = [] - for proposal in get_qs_for_year(options['year']): + for proposal in get_qs_for_year(options["year"]): study_types = get_studytypes_for_proposal(proposal) registrations = get_registrations_for_proposal(proposal) @@ -58,9 +57,9 @@ def handle(self, *args, **options): review = proposal.latest_review() row.extend( [ - 'short' if review.short_route else 'long', + "short" if review.short_route else "long", review.get_continuation_display(), - review.date_end.date().isoformat() + review.date_end.date().isoformat(), ] ) @@ -72,5 +71,5 @@ def handle(self, *args, **options): def dict_to_string(dict_): result = [] for k, v in dict_.items(): - result.append(str(k) + ' - ' + ', '.join(v)) - return result[0].split(' - ')[1] if len(result) == 1 else '; '.join(result) + result.append(str(k) + " - " + ", ".join(v)) + return result[0].split(" - ")[1] if len(result) == 1 else "; ".join(result) diff --git a/proposals/management/commands/get_statistics.py b/proposals/management/commands/get_statistics.py index eb51d6d53..112d42826 100644 --- a/proposals/management/commands/get_statistics.py +++ b/proposals/management/commands/get_statistics.py @@ -3,46 +3,45 @@ from django.conf import settings from django.views.i18n import set_language -from proposals.utils.statistics_utils import get_average_turnaround_time, \ - get_qs_for_long_route_reviews, get_qs_for_short_route_reviews, \ - get_qs_for_year, \ - get_qs_for_year_and_committee, get_review_qs_for_proposals, \ - get_total_long_route_proposals, \ - get_total_short_route_proposals, \ - get_total_students, get_total_submitted_proposals +from proposals.utils.statistics_utils import ( + get_average_turnaround_time, + get_qs_for_long_route_reviews, + get_qs_for_short_route_reviews, + get_qs_for_year, + get_qs_for_year_and_committee, + get_review_qs_for_proposals, + get_total_long_route_proposals, + get_total_short_route_proposals, + get_total_students, + get_total_submitted_proposals, +) class Command(BaseCommand): - help = 'Calculate statistics for a given year' + help = "Calculate statistics for a given year" def add_arguments(self, parser): - parser.add_argument('year', type=int) + parser.add_argument("year", type=int) def handle(self, *args, **options): AK = Group.objects.get(name=settings.GROUP_GENERAL_CHAMBER) LK = Group.objects.get(name=settings.GROUP_LINGUISTICS_CHAMBER) datasets = { - 'Total': get_qs_for_year(options['year']), - 'AK': get_qs_for_year_and_committee(options['year'], AK), - 'LK': get_qs_for_year_and_committee(options['year'], LK) + "Total": get_qs_for_year(options["year"]), + "AK": get_qs_for_year_and_committee(options["year"], AK), + "LK": get_qs_for_year_and_committee(options["year"], LK), } for name, dataset in datasets.items(): print(name) - print('Total submitted:', get_total_submitted_proposals(dataset)) - print( - 'Total short route:', - get_total_short_route_proposals(dataset) - ) - print( - 'Total long route:', - get_total_long_route_proposals(dataset) - ) + print("Total submitted:", get_total_submitted_proposals(dataset)) + print("Total short route:", get_total_short_route_proposals(dataset)) + print("Total long route:", get_total_long_route_proposals(dataset)) print() - print('Total per relation:') + print("Total per relation:") for relation, count in get_total_students(dataset).items(): print(count, relation) @@ -50,17 +49,13 @@ def handle(self, *args, **options): print("Turnaround times:") print( "Short route", - get_average_turnaround_time( - get_qs_for_short_route_reviews(dataset) - ), - 'days' + get_average_turnaround_time(get_qs_for_short_route_reviews(dataset)), + "days", ) print( "Long route", - get_average_turnaround_time( - get_qs_for_long_route_reviews(dataset) - ), - 'days' + get_average_turnaround_time(get_qs_for_long_route_reviews(dataset)), + "days", ) - print() \ No newline at end of file + print() diff --git a/proposals/management/commands/regenerate_pdf.py b/proposals/management/commands/regenerate_pdf.py index a0a4b3781..c66bf1a0c 100644 --- a/proposals/management/commands/regenerate_pdf.py +++ b/proposals/management/commands/regenerate_pdf.py @@ -1,13 +1,14 @@ from django.core.management.base import BaseCommand, CommandError from proposals.models import Proposal + class Command(BaseCommand): - help = 'Regenerates the PDF for a Proposal' + help = "Regenerates the PDF for a Proposal" def add_arguments(self, parser): parser.add_argument( - 'reference_numbers', - nargs='+', + "reference_numbers", + nargs="+", type=str, help="Space separated list of reference number for which PDFs \ should be regenerated", @@ -19,17 +20,21 @@ def add_arguments(self, parser): proposal's state. This applies to ALL reference numbers provided.", ) - def get_proposals(self, ): + def get_proposals( + self, + ): refnums = self.options["reference_numbers"] proposals = [] for num in refnums: try: proposal = Proposal.objects.get(reference_number=num) except Proposal.DoesNotExist: - raise CommandError(f""" + raise CommandError( + f""" Proposal with reference number {num} could not be found. Aborting generation of all PDFs. - """) + """ + ) proposals.append(proposal) return proposals diff --git a/proposals/menus.py b/proposals/menus.py index 020f14f31..537923484 100644 --- a/proposals/menus.py +++ b/proposals/menus.py @@ -2,7 +2,7 @@ from django.utils.translation import gettext_lazy as _ from menu import Menu, MenuItem -from main.utils import is_member_of_humanities, is_secretary +from main.utils import is_secretary, can_view_archive new_proposal_menu = ( MenuItem( @@ -18,8 +18,10 @@ reverse("proposals:start_pre"), ), MenuItem( - _("Nieuwe aanvraag starten (die al goedgekeurd is door een andere " - "ethische toetsingscomissie)"), + _( + "Nieuwe aanvraag starten (die al goedgekeurd is door een andere " + "ethische toetsingscomissie)" + ), reverse("proposals:start_pre_approved"), ), MenuItem( @@ -41,10 +43,10 @@ MenuItem( _("Nieuwe aanvraag"), "#", - slug='new-studies', # needed for sub-menu! + slug="new-studies", # needed for sub-menu! children=new_proposal_menu, check=lambda x: x.user.is_authenticated, - ) + ), ) my_proposals_menu = ( @@ -79,22 +81,22 @@ MenuItem( _("Mijn aanvragen"), reverse("proposals:my_archive"), - slug='my-studies', # needed for sub-menu! + slug="my-studies", # needed for sub-menu! children=my_proposals_menu, check=lambda x: x.user.is_authenticated, - ) + ), ) archive_menu = ( MenuItem( _("Bekijk alle goedgekeurde aanvragen van de Algemene Kamer"), - reverse("proposals:archive", args=['AK']), - check=lambda x: is_member_of_humanities(x.user), + reverse("proposals:archive", args=["AK"]), + check=lambda x: can_view_archive(x.user), ), MenuItem( _("Bekijk alle goedgekeurde aanvragen van de Linguïstiek Kamer"), - reverse("proposals:archive", args=['LK']), - check=lambda x: is_member_of_humanities(x.user), + reverse("proposals:archive", args=["LK"]), + check=lambda x: can_view_archive(x.user), ), MenuItem( _("Site-export"), @@ -109,8 +111,8 @@ MenuItem( _("Archief"), "#", - slug='archive', # needed for sub-menu! + slug="archive", # needed for sub-menu! children=archive_menu, - check=lambda x: x.user.is_authenticated and is_member_of_humanities(x.user), - ) + check=lambda x: can_view_archive(x.user), + ), ) diff --git a/proposals/migrations/0001_initial.py b/proposals/migrations/0001_initial.py index e9bf451f1..0933fa4d5 100644 --- a/proposals/migrations/0001_initial.py +++ b/proposals/migrations/0001_initial.py @@ -8,107 +8,308 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='Funding', + name="Funding", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('order', models.PositiveIntegerField(unique=True)), - ('description', models.CharField(max_length=200)), - ('needs_details', models.BooleanField(default=False)), - ('requires_review', models.BooleanField(default=False)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("order", models.PositiveIntegerField(unique=True)), + ("description", models.CharField(max_length=200)), + ("needs_details", models.BooleanField(default=False)), + ("requires_review", models.BooleanField(default=False)), ], options={ - 'ordering': ['order'], + "ordering": ["order"], }, ), migrations.CreateModel( - name='Proposal', + name="Proposal", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('reference_number', models.CharField(unique=True, max_length=16)), - ('date_start', models.DateField(null=True, verbose_name='Wat is, indien bekend, de beoogde startdatum van uw studie?', blank=True)), - ('title', models.CharField(help_text='De titel die u hier opgeeft is zichtbaar voor de ETCL-leden en, wanneer de studie is goedgekeurd, ook voor alle UiL-OTS medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een studie die u heeft ingediend.', unique=True, max_length=200, verbose_name='Wat is de titel van uw studie?')), - ('summary', models.TextField(verbose_name='Geef een duidelijke, bondige beschrijving van de onderzoeksvraag of -vragen. Gebruik maximaal 200 woorden.', validators=[main.validators.MaxWordsValidator(200)])), - ('other_applicants', models.BooleanField(default=False, verbose_name='Zijn er nog andere UiL OTS-onderzoekers of -studenten bij deze studie betrokken?')), - ('other_stakeholders', models.BooleanField(default=False, verbose_name='Zijn er onderzoekers van buiten UiL OTS bij deze studie betrokken?')), - ('stakeholders', models.TextField(verbose_name='Andere betrokkenen', blank=True)), - ('funding_details', models.CharField(max_length=200, verbose_name='Namelijk', blank=True)), - ('comments', models.TextField(verbose_name='Ruimte voor eventuele opmerkingen', blank=True)), - ('pdf', models.FileField(upload_to=b'', blank=True)), - ('studies_similar', models.NullBooleanField(help_text='Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is sprake van in essentie hetzelfde traject. Denk hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van een set verhaaltjes te lezen krijgt, en de andere groep in taak X de andere helft. Of aan interventieonderzoek waarin drie vergelijkbare groepen op hetzelfde moment een verschillende interventie-variant krijgen (specificeer dan wel bij de beschrijving van de interventie welke varianten precies gebruikt worden).', verbose_name='Doorlopen alle deelnemersgroepen in essentie hetzelfde traject?')), - ('studies_number', models.PositiveIntegerField(default=1, verbose_name='Hoeveel verschillende trajecten zijn er?', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)])), - ('status', models.PositiveIntegerField(default=1, choices=[(1, 'Concept'), (40, 'Opgestuurd ter beoordeling door eindverantwoordelijke'), (50, 'Opgestuurd ter beoordeling door ETCL'), (55, 'Studie is beoordeeld door ETCL'), (60, 'Studie is beoordeeld door METC')])), - ('status_review', models.NullBooleanField(default=None)), - ('date_created', models.DateTimeField(auto_now_add=True)), - ('date_modified', models.DateTimeField(auto_now=True)), - ('date_submitted_supervisor', models.DateTimeField(null=True)), - ('date_reviewed_supervisor', models.DateTimeField(null=True)), - ('date_submitted', models.DateTimeField(null=True)), - ('date_reviewed', models.DateTimeField(null=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("reference_number", models.CharField(unique=True, max_length=16)), + ( + "date_start", + models.DateField( + null=True, + verbose_name="Wat is, indien bekend, de beoogde startdatum van uw studie?", + blank=True, + ), + ), + ( + "title", + models.CharField( + help_text="De titel die u hier opgeeft is zichtbaar voor de ETCL-leden en, wanneer de studie is goedgekeurd, ook voor alle UiL-OTS medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een studie die u heeft ingediend.", + unique=True, + max_length=200, + verbose_name="Wat is de titel van uw studie?", + ), + ), + ( + "summary", + models.TextField( + verbose_name="Geef een duidelijke, bondige beschrijving van de onderzoeksvraag of -vragen. Gebruik maximaal 200 woorden.", + validators=[main.validators.MaxWordsValidator(200)], + ), + ), + ( + "other_applicants", + models.BooleanField( + default=False, + verbose_name="Zijn er nog andere UiL OTS-onderzoekers of -studenten bij deze studie betrokken?", + ), + ), + ( + "other_stakeholders", + models.BooleanField( + default=False, + verbose_name="Zijn er onderzoekers van buiten UiL OTS bij deze studie betrokken?", + ), + ), + ( + "stakeholders", + models.TextField(verbose_name="Andere betrokkenen", blank=True), + ), + ( + "funding_details", + models.CharField( + max_length=200, verbose_name="Namelijk", blank=True + ), + ), + ( + "comments", + models.TextField( + verbose_name="Ruimte voor eventuele opmerkingen", blank=True + ), + ), + ("pdf", models.FileField(upload_to=b"", blank=True)), + ( + "studies_similar", + models.NullBooleanField( + help_text="Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is sprake van in essentie hetzelfde traject. Denk hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van een set verhaaltjes te lezen krijgt, en de andere groep in taak X de andere helft. Of aan interventieonderzoek waarin drie vergelijkbare groepen op hetzelfde moment een verschillende interventie-variant krijgen (specificeer dan wel bij de beschrijving van de interventie welke varianten precies gebruikt worden).", + verbose_name="Doorlopen alle deelnemersgroepen in essentie hetzelfde traject?", + ), + ), + ( + "studies_number", + models.PositiveIntegerField( + default=1, + verbose_name="Hoeveel verschillende trajecten zijn er?", + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(5), + ], + ), + ), + ( + "status", + models.PositiveIntegerField( + default=1, + choices=[ + (1, "Concept"), + ( + 40, + "Opgestuurd ter beoordeling door eindverantwoordelijke", + ), + (50, "Opgestuurd ter beoordeling door ETCL"), + (55, "Studie is beoordeeld door ETCL"), + (60, "Studie is beoordeeld door METC"), + ], + ), + ), + ("status_review", models.NullBooleanField(default=None)), + ("date_created", models.DateTimeField(auto_now_add=True)), + ("date_modified", models.DateTimeField(auto_now=True)), + ("date_submitted_supervisor", models.DateTimeField(null=True)), + ("date_reviewed_supervisor", models.DateTimeField(null=True)), + ("date_submitted", models.DateTimeField(null=True)), + ("date_reviewed", models.DateTimeField(null=True)), ], ), migrations.CreateModel( - name='Relation', + name="Relation", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('order', models.PositiveIntegerField(unique=True)), - ('description', models.CharField(max_length=200)), - ('needs_supervisor', models.BooleanField(default=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("order", models.PositiveIntegerField(unique=True)), + ("description", models.CharField(max_length=200)), + ("needs_supervisor", models.BooleanField(default=True)), ], options={ - 'ordering': ['order'], + "ordering": ["order"], }, ), migrations.CreateModel( - name='Wmo', + name="Wmo", fields=[ - ('metc', models.CharField(default=None, max_length=1, verbose_name='Vindt de dataverzameling plaats binnen het UMC Utrecht of andere instelling waar toetsing door een METC verplicht is gesteld?', choices=[(b'Y', 'ja'), (b'N', 'nee'), (b'?', 'twijfel')])), - ('metc_details', models.TextField(verbose_name='Licht toe', blank=True)), - ('metc_institution', models.CharField(max_length=200, verbose_name='Welke instelling?', blank=True)), - ('is_medical', models.CharField(blank=True, help_text='De definitie van medisch-wetenschappelijk onderzoek is: Medisch-wetenschappelijk onderzoek is onderzoek dat als doel heeft het beantwoorden van een vraag op het gebied van ziekte en gezondheid (etiologie, pathogenese, verschijnselen/symptomen, diagnose, preventie, uitkomst of behandeling van ziekte), door het op systematische wijze vergaren en bestuderen van gegevens. Het onderzoek beoogt bij te dragen aan medische kennis die ook geldend is voor populaties buiten de directe onderzoekspopulatie. (CCMO-notitie, Definitie medisch-wetenschappelijk onderzoek, 2005, ccmo.nl)', max_length=1, verbose_name='Is de onderzoeksvraag medisch-wetenschappelijk van aard (zoals gedefinieerd door de WMO)?', choices=[(b'Y', 'ja'), (b'N', 'nee'), (b'?', 'twijfel')])), - ('is_behavioristic', models.CharField(blank=True, help_text='Een handeling of opgelegde gedragsregel varieert tussen het afnemen van weefsel bij een deelnemer tot de deelnemer een knop/toets in laten drukken. Bij observatieonderzoek waarbij er niets van de deelnemers gevraagd wordt, deze dus uitsluitend geobserveerd worden in hun leven zoals het ook had plaatsgevonden zonder de observatie, slechts dan kan "nee" ingevuld worden.', max_length=1, verbose_name='Worden de deelnemers aan een handeling onderworpen of worden hen gedragsregels opgelegd (zoals gedefinieerd door de WMO)?', choices=[(b'Y', 'ja'), (b'N', 'nee'), (b'?', 'twijfel')])), - ('metc_application', models.BooleanField(default=False, verbose_name='Uw studie moet beoordeeld worden door de METC, maar dient nog wel bij de ETCL te worden geregistreerd. Is deze studie al aangemeld bij een METC?')), - ('metc_decision', models.BooleanField(default=False, verbose_name='Is de METC al tot een beslissing gekomen?')), - ('metc_decision_pdf', models.FileField(blank=True, upload_to=b'', verbose_name='Upload hier de beslissing van het METC (in .pdf of .doc(x)-formaat)', validators=[main.validators.validate_pdf_or_doc])), - ('status', models.PositiveIntegerField(default=0, choices=[(0, 'Geen beoordeling door METC noodzakelijk'), (1, 'In afwachting beslissing METC'), (2, 'Beslissing METC ge\xfcpload')])), - ('enforced_by_commission', models.BooleanField(default=False)), - ('proposal', models.OneToOneField(primary_key=True, serialize=False, to='proposals.Proposal', on_delete=models.CASCADE)), + ( + "metc", + models.CharField( + default=None, + max_length=1, + verbose_name="Vindt de dataverzameling plaats binnen het UMC Utrecht of andere instelling waar toetsing door een METC verplicht is gesteld?", + choices=[(b"Y", "ja"), (b"N", "nee"), (b"?", "twijfel")], + ), + ), + ( + "metc_details", + models.TextField(verbose_name="Licht toe", blank=True), + ), + ( + "metc_institution", + models.CharField( + max_length=200, verbose_name="Welke instelling?", blank=True + ), + ), + ( + "is_medical", + models.CharField( + blank=True, + help_text="De definitie van medisch-wetenschappelijk onderzoek is: Medisch-wetenschappelijk onderzoek is onderzoek dat als doel heeft het beantwoorden van een vraag op het gebied van ziekte en gezondheid (etiologie, pathogenese, verschijnselen/symptomen, diagnose, preventie, uitkomst of behandeling van ziekte), door het op systematische wijze vergaren en bestuderen van gegevens. Het onderzoek beoogt bij te dragen aan medische kennis die ook geldend is voor populaties buiten de directe onderzoekspopulatie. (CCMO-notitie, Definitie medisch-wetenschappelijk onderzoek, 2005, ccmo.nl)", + max_length=1, + verbose_name="Is de onderzoeksvraag medisch-wetenschappelijk van aard (zoals gedefinieerd door de WMO)?", + choices=[(b"Y", "ja"), (b"N", "nee"), (b"?", "twijfel")], + ), + ), + ( + "is_behavioristic", + models.CharField( + blank=True, + help_text='Een handeling of opgelegde gedragsregel varieert tussen het afnemen van weefsel bij een deelnemer tot de deelnemer een knop/toets in laten drukken. Bij observatieonderzoek waarbij er niets van de deelnemers gevraagd wordt, deze dus uitsluitend geobserveerd worden in hun leven zoals het ook had plaatsgevonden zonder de observatie, slechts dan kan "nee" ingevuld worden.', + max_length=1, + verbose_name="Worden de deelnemers aan een handeling onderworpen of worden hen gedragsregels opgelegd (zoals gedefinieerd door de WMO)?", + choices=[(b"Y", "ja"), (b"N", "nee"), (b"?", "twijfel")], + ), + ), + ( + "metc_application", + models.BooleanField( + default=False, + verbose_name="Uw studie moet beoordeeld worden door de METC, maar dient nog wel bij de ETCL te worden geregistreerd. Is deze studie al aangemeld bij een METC?", + ), + ), + ( + "metc_decision", + models.BooleanField( + default=False, + verbose_name="Is de METC al tot een beslissing gekomen?", + ), + ), + ( + "metc_decision_pdf", + models.FileField( + blank=True, + upload_to=b"", + verbose_name="Upload hier de beslissing van het METC (in .pdf of .doc(x)-formaat)", + validators=[main.validators.validate_pdf_or_doc], + ), + ), + ( + "status", + models.PositiveIntegerField( + default=0, + choices=[ + (0, "Geen beoordeling door METC noodzakelijk"), + (1, "In afwachting beslissing METC"), + (2, "Beslissing METC ge\xfcpload"), + ], + ), + ), + ("enforced_by_commission", models.BooleanField(default=False)), + ( + "proposal", + models.OneToOneField( + primary_key=True, + serialize=False, + to="proposals.Proposal", + on_delete=models.CASCADE, + ), + ), ], ), migrations.AddField( - model_name='proposal', - name='applicants', - field=models.ManyToManyField(help_text='Als uw medeonderzoeker niet in de lijst voorkomt, vraag hem dan een keer in te loggen in het webportaal.', related_name='applicants', verbose_name='Uitvoerende(n) (inclusief uzelf)', to=settings.AUTH_USER_MODEL), + model_name="proposal", + name="applicants", + field=models.ManyToManyField( + help_text="Als uw medeonderzoeker niet in de lijst voorkomt, vraag hem dan een keer in te loggen in het webportaal.", + related_name="applicants", + verbose_name="Uitvoerende(n) (inclusief uzelf)", + to=settings.AUTH_USER_MODEL, + ), ), migrations.AddField( - model_name='proposal', - name='created_by', - field=models.ForeignKey(related_name='created_by', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE), + model_name="proposal", + name="created_by", + field=models.ForeignKey( + related_name="created_by", + to=settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ), ), migrations.AddField( - model_name='proposal', - name='funding', - field=models.ManyToManyField(to='proposals.Funding', verbose_name='Hoe wordt dit onderzoek gefinancierd?'), + model_name="proposal", + name="funding", + field=models.ManyToManyField( + to="proposals.Funding", + verbose_name="Hoe wordt dit onderzoek gefinancierd?", + ), ), migrations.AddField( - model_name='proposal', - name='parent', - field=models.ForeignKey(verbose_name='Te kopi\xebren studie', on_delete=models.CASCADE, to='proposals.Proposal', help_text='Dit veld toont enkel studies waar u zelf een medeuitvoerende bent.', null=True), + model_name="proposal", + name="parent", + field=models.ForeignKey( + verbose_name="Te kopi\xebren studie", + on_delete=models.CASCADE, + to="proposals.Proposal", + help_text="Dit veld toont enkel studies waar u zelf een medeuitvoerende bent.", + null=True, + ), ), migrations.AddField( - model_name='proposal', - name='relation', - field=models.ForeignKey(verbose_name='In welke hoedanigheid bent u betrokken bij deze UiL OTS studie?', to='proposals.Relation', on_delete=models.CASCADE), + model_name="proposal", + name="relation", + field=models.ForeignKey( + verbose_name="In welke hoedanigheid bent u betrokken bij deze UiL OTS studie?", + to="proposals.Relation", + on_delete=models.CASCADE, + ), ), migrations.AddField( - model_name='proposal', - name='supervisor', - field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, help_text='Aan het einde van de procedure kunt u deze studie ter verificatie naar uw eindverantwoordelijke sturen. De eindverantwoordelijke zal de studie vervolgens kunnen aanpassen en indienen bij de ETCL.', null=True, verbose_name='Eindverantwoordelijke onderzoeker', on_delete=models.CASCADE), + model_name="proposal", + name="supervisor", + field=models.ForeignKey( + blank=True, + to=settings.AUTH_USER_MODEL, + help_text="Aan het einde van de procedure kunt u deze studie ter verificatie naar uw eindverantwoordelijke sturen. De eindverantwoordelijke zal de studie vervolgens kunnen aanpassen en indienen bij de ETCL.", + null=True, + verbose_name="Eindverantwoordelijke onderzoeker", + on_delete=models.CASCADE, + ), ), ] diff --git a/proposals/migrations/0002_proposal_is_revision.py b/proposals/migrations/0002_proposal_is_revision.py index bc76f6851..6a8d79280 100644 --- a/proposals/migrations/0002_proposal_is_revision.py +++ b/proposals/migrations/0002_proposal_is_revision.py @@ -5,15 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0001_initial'), + ("proposals", "0001_initial"), ] operations = [ migrations.AddField( - model_name='proposal', - name='is_revision', - field=models.BooleanField(default=False, verbose_name='Is deze studie een revisie van of amendement op een ingediende studie?'), + model_name="proposal", + name="is_revision", + field=models.BooleanField( + default=False, + verbose_name="Is deze studie een revisie van of amendement op een ingediende studie?", + ), ), ] diff --git a/proposals/migrations/0003_auto_20161008_2238.py b/proposals/migrations/0003_auto_20161008_2238.py index ab09ed246..cfe97162c 100644 --- a/proposals/migrations/0003_auto_20161008_2238.py +++ b/proposals/migrations/0003_auto_20161008_2238.py @@ -5,20 +5,22 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0002_proposal_is_revision'), + ("proposals", "0002_proposal_is_revision"), ] operations = [ migrations.AddField( - model_name='proposal', - name='in_course', - field=models.BooleanField(default=False, verbose_name='Ik vul deze portal in in de context van een cursus'), + model_name="proposal", + name="in_course", + field=models.BooleanField( + default=False, + verbose_name="Ik vul deze portal in in de context van een cursus", + ), ), migrations.AddField( - model_name='relation', - name='check_in_course', + model_name="relation", + name="check_in_course", field=models.BooleanField(default=True), ), ] diff --git a/proposals/migrations/0004_auto_20161013_1508.py b/proposals/migrations/0004_auto_20161013_1508.py index a2c471920..1e4cc6c4e 100644 --- a/proposals/migrations/0004_auto_20161013_1508.py +++ b/proposals/migrations/0004_auto_20161013_1508.py @@ -5,30 +5,29 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0003_auto_20161008_2238'), + ("proposals", "0003_auto_20161008_2238"), ] operations = [ migrations.AddField( - model_name='funding', - name='description_en', + model_name="funding", + name="description_en", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='funding', - name='description_nl', + model_name="funding", + name="description_nl", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='relation', - name='description_en', + model_name="relation", + name="description_en", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='relation', - name='description_nl', + model_name="relation", + name="description_nl", field=models.CharField(max_length=200, null=True), ), ] diff --git a/proposals/migrations/0005_proposal_in_archive.py b/proposals/migrations/0005_proposal_in_archive.py index 47806fd2c..d3d7cebf0 100644 --- a/proposals/migrations/0005_proposal_in_archive.py +++ b/proposals/migrations/0005_proposal_in_archive.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0004_auto_20161013_1508'), + ("proposals", "0004_auto_20161013_1508"), ] operations = [ migrations.AddField( - model_name='proposal', - name='in_archive', + model_name="proposal", + name="in_archive", field=models.BooleanField(default=False), ), ] diff --git a/proposals/migrations/0006_proposal_is_pre_assessment.py b/proposals/migrations/0006_proposal_is_pre_assessment.py index 8f8677cbb..50deac2c1 100644 --- a/proposals/migrations/0006_proposal_is_pre_assessment.py +++ b/proposals/migrations/0006_proposal_is_pre_assessment.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0005_proposal_in_archive'), + ("proposals", "0005_proposal_in_archive"), ] operations = [ migrations.AddField( - model_name='proposal', - name='is_pre_assessment', + model_name="proposal", + name="is_pre_assessment", field=models.BooleanField(default=False), ), ] diff --git a/proposals/migrations/0007_auto_20161219_1141.py b/proposals/migrations/0007_auto_20161219_1141.py index 533581ea4..1d045b243 100644 --- a/proposals/migrations/0007_auto_20161219_1141.py +++ b/proposals/migrations/0007_auto_20161219_1141.py @@ -5,20 +5,25 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0006_proposal_is_pre_assessment'), + ("proposals", "0006_proposal_is_pre_assessment"), ] operations = [ migrations.AddField( - model_name='proposal', - name='is_exploration', - field=models.BooleanField(default=False, verbose_name='Ik vul de portal in om de portal te exploreren'), + model_name="proposal", + name="is_exploration", + field=models.BooleanField( + default=False, + verbose_name="Ik vul de portal in om de portal te exploreren", + ), ), migrations.AlterField( - model_name='proposal', - name='in_course', - field=models.BooleanField(default=False, verbose_name='Ik vul de portal in in het kader van een cursus'), + model_name="proposal", + name="in_course", + field=models.BooleanField( + default=False, + verbose_name="Ik vul de portal in in het kader van een cursus", + ), ), ] diff --git a/proposals/migrations/0008_relation_check_pre_assessment.py b/proposals/migrations/0008_relation_check_pre_assessment.py index f5b002ef6..0f69d595f 100644 --- a/proposals/migrations/0008_relation_check_pre_assessment.py +++ b/proposals/migrations/0008_relation_check_pre_assessment.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0007_auto_20161219_1141'), + ("proposals", "0007_auto_20161219_1141"), ] operations = [ migrations.AddField( - model_name='relation', - name='check_pre_assessment', + model_name="relation", + name="check_pre_assessment", field=models.BooleanField(default=True), ), ] diff --git a/proposals/migrations/0009_proposal_pre_assessment_pdf.py b/proposals/migrations/0009_proposal_pre_assessment_pdf.py index a0b8e8d33..f37d48ce9 100644 --- a/proposals/migrations/0009_proposal_pre_assessment_pdf.py +++ b/proposals/migrations/0009_proposal_pre_assessment_pdf.py @@ -6,15 +6,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0008_relation_check_pre_assessment'), + ("proposals", "0008_relation_check_pre_assessment"), ] operations = [ migrations.AddField( - model_name='proposal', - name='pre_assessment_pdf', - field=models.FileField(blank=True, upload_to=b'', verbose_name='Upload hier uw aanvraag (in .pdf of .doc(x)-formaat)', validators=[main.validators.validate_pdf_or_doc]), + model_name="proposal", + name="pre_assessment_pdf", + field=models.FileField( + blank=True, + upload_to=b"", + verbose_name="Upload hier uw aanvraag (in .pdf of .doc(x)-formaat)", + validators=[main.validators.validate_pdf_or_doc], + ), ), ] diff --git a/proposals/migrations/0010_auto_20170328_1238.py b/proposals/migrations/0010_auto_20170328_1238.py index 045bacad4..e1fc4b9f1 100644 --- a/proposals/migrations/0010_auto_20170328_1238.py +++ b/proposals/migrations/0010_auto_20170328_1238.py @@ -6,30 +6,44 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0009_proposal_pre_assessment_pdf'), + ("proposals", "0009_proposal_pre_assessment_pdf"), ] operations = [ migrations.AddField( - model_name='funding', - name='needs_name', + model_name="funding", + name="needs_name", field=models.BooleanField(default=True), ), migrations.AddField( - model_name='proposal', - name='funding_name', - field=models.CharField(help_text='De titel die u hier opgeeft zal in de formele toestemmingsbrief gebruikt worden.', max_length=200, verbose_name='Wat is de naam van het gefinancierde project?', blank=True), + model_name="proposal", + name="funding_name", + field=models.CharField( + help_text="De titel die u hier opgeeft zal in de formele toestemmingsbrief gebruikt worden.", + max_length=200, + verbose_name="Wat is de naam van het gefinancierde project?", + blank=True, + ), ), migrations.AlterField( - model_name='proposal', - name='applicants', - field=models.ManyToManyField(help_text='Als uw medeonderzoeker niet in de lijst voorkomt, vraag hem dan een keer in te loggen in het webportaal.', related_name='applicants', verbose_name='Uitvoerende(n) (inclusief uzelf). Uitvoerende(n) kunnen pas worden toegevoegd als ze eerst een keer zelf zijn ingelogd.', to=settings.AUTH_USER_MODEL), + model_name="proposal", + name="applicants", + field=models.ManyToManyField( + help_text="Als uw medeonderzoeker niet in de lijst voorkomt, vraag hem dan een keer in te loggen in het webportaal.", + related_name="applicants", + verbose_name="Uitvoerende(n) (inclusief uzelf). Uitvoerende(n) kunnen pas worden toegevoegd als ze eerst een keer zelf zijn ingelogd.", + to=settings.AUTH_USER_MODEL, + ), ), migrations.AlterField( - model_name='proposal', - name='title', - field=models.CharField(help_text='De titel die u hier opgeeft is zichtbaar voor de ETCL-leden en, wanneer de studie is goedgekeurd, ook voor alle UiL-OTS medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een studie die u heeft ingediend.', unique=True, max_length=200, verbose_name='Wat is de titel van uw studie? Deze titel zal worden gebruikt in alle formele correspondentie.'), + model_name="proposal", + name="title", + field=models.CharField( + help_text="De titel die u hier opgeeft is zichtbaar voor de ETCL-leden en, wanneer de studie is goedgekeurd, ook voor alle UiL-OTS medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een studie die u heeft ingediend.", + unique=True, + max_length=200, + verbose_name="Wat is de titel van uw studie? Deze titel zal worden gebruikt in alle formele correspondentie.", + ), ), ] diff --git a/proposals/migrations/0011_auto_20170525_0005.py b/proposals/migrations/0011_auto_20170525_0005.py index bd0c4ba92..4a5d6eded 100644 --- a/proposals/migrations/0011_auto_20170525_0005.py +++ b/proposals/migrations/0011_auto_20170525_0005.py @@ -5,20 +5,23 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0010_auto_20170328_1238'), + ("proposals", "0010_auto_20170328_1238"), ] operations = [ migrations.AddField( - model_name='proposal', - name='confirmation_comments', - field=models.TextField(verbose_name='Ruimte voor eventuele opmerkingen', blank=True), + model_name="proposal", + name="confirmation_comments", + field=models.TextField( + verbose_name="Ruimte voor eventuele opmerkingen", blank=True + ), ), migrations.AddField( - model_name='proposal', - name='date_confirmed', - field=models.DateField(null=True, verbose_name='Datum bevestigingsbrief verstuurd'), + model_name="proposal", + name="date_confirmed", + field=models.DateField( + null=True, verbose_name="Datum bevestigingsbrief verstuurd" + ), ), ] diff --git a/proposals/migrations/0012_proposal_inform_local_staff.py b/proposals/migrations/0012_proposal_inform_local_staff.py index 3d9431842..a93ccc5c1 100644 --- a/proposals/migrations/0012_proposal_inform_local_staff.py +++ b/proposals/migrations/0012_proposal_inform_local_staff.py @@ -5,15 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0011_auto_20170525_0005'), + ("proposals", "0011_auto_20170525_0005"), ] operations = [ migrations.AddField( - model_name='proposal', - name='inform_local_staff', - field=models.NullBooleanField(default=None, verbose_name='

      U hebt aangegeven dat u gebruik wilt gaan maken van \xe9\xe9n van de faciliteiten van het UiL OTS, namelijk de database, Zep software en/of het UiL OTS lab. Het lab supportteam van het UiL OTS zou graag op de hoogte willen worden gesteld van aankomende studies. Daarom vragen wij hier u toestemming om delen van deze aanvraag door te sturen naar het lab supportteam.

      Vindt u het goed dat de volgende delen uit de aanvraag worden doorgestuurd:

      - Uw naam en de namen van de andere betrokkenen
      - De eindverantwoordelijke van de studie
      - De titel van de studie
      - De beoogde startdatum
      - Van welke faciliteiten u gebruik wilt maken (database, lab, Zep software)'), + model_name="proposal", + name="inform_local_staff", + field=models.NullBooleanField( + default=None, + verbose_name="

      U hebt aangegeven dat u gebruik wilt gaan maken van \xe9\xe9n van de faciliteiten van het UiL OTS, namelijk de database, Zep software en/of het UiL OTS lab. Het lab supportteam van het UiL OTS zou graag op de hoogte willen worden gesteld van aankomende studies. Daarom vragen wij hier u toestemming om delen van deze aanvraag door te sturen naar het lab supportteam.

      Vindt u het goed dat de volgende delen uit de aanvraag worden doorgestuurd:

      - Uw naam en de namen van de andere betrokkenen
      - De eindverantwoordelijke van de studie
      - De titel van de studie
      - De beoogde startdatum
      - Van welke faciliteiten u gebruik wilt maken (database, lab, Zep software)", + ), ), ] diff --git a/proposals/migrations/0013_proposal_public.py b/proposals/migrations/0013_proposal_public.py index 30a02880a..b76949d2e 100644 --- a/proposals/migrations/0013_proposal_public.py +++ b/proposals/migrations/0013_proposal_public.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0012_proposal_inform_local_staff'), + ("proposals", "0012_proposal_inform_local_staff"), ] operations = [ migrations.AddField( - model_name='proposal', - name='public', + model_name="proposal", + name="public", field=models.BooleanField(default=True), ), ] diff --git a/proposals/migrations/0014_auto_20180808_1129.py b/proposals/migrations/0014_auto_20180808_1129.py index 45f1f5c6e..2f08c0d6f 100644 --- a/proposals/migrations/0014_auto_20180808_1129.py +++ b/proposals/migrations/0014_auto_20180808_1129.py @@ -8,45 +8,75 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0013_proposal_public'), + ("proposals", "0013_proposal_public"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='applicants', - field=models.ManyToManyField(related_name='applicants', to=settings.AUTH_USER_MODEL, verbose_name='Uitvoerende(n) (inclusief uzelf)'), + model_name="proposal", + name="applicants", + field=models.ManyToManyField( + related_name="applicants", + to=settings.AUTH_USER_MODEL, + verbose_name="Uitvoerende(n) (inclusief uzelf)", + ), ), migrations.AlterField( - model_name='proposal', - name='pdf', - field=models.FileField(blank=True, upload_to=''), + model_name="proposal", + name="pdf", + field=models.FileField(blank=True, upload_to=""), ), migrations.AlterField( - model_name='proposal', - name='pre_assessment_pdf', - field=models.FileField(blank=True, upload_to='', validators=[main.validators.validate_pdf_or_doc], verbose_name='Upload hier uw aanvraag (in .pdf of .doc(x)-formaat)'), + model_name="proposal", + name="pre_assessment_pdf", + field=models.FileField( + blank=True, + upload_to="", + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Upload hier uw aanvraag (in .pdf of .doc(x)-formaat)", + ), ), migrations.AlterField( - model_name='wmo', - name='is_behavioristic', - field=models.CharField(blank=True, choices=[('Y', 'ja'), ('N', 'nee'), ('?', 'twijfel')], help_text='Een handeling of opgelegde gedragsregel varieert tussen het afnemen van weefsel bij een deelnemer tot de deelnemer een knop/toets in laten drukken. Bij observatieonderzoek waarbij er niets van de deelnemers gevraagd wordt, deze dus uitsluitend geobserveerd worden in hun leven zoals het ook had plaatsgevonden zonder de observatie, slechts dan kan "nee" ingevuld worden.', max_length=1, verbose_name='Worden de deelnemers aan een handeling onderworpen of worden hen gedragsregels opgelegd (zoals gedefinieerd door de WMO)?'), + model_name="wmo", + name="is_behavioristic", + field=models.CharField( + blank=True, + choices=[("Y", "ja"), ("N", "nee"), ("?", "twijfel")], + help_text='Een handeling of opgelegde gedragsregel varieert tussen het afnemen van weefsel bij een deelnemer tot de deelnemer een knop/toets in laten drukken. Bij observatieonderzoek waarbij er niets van de deelnemers gevraagd wordt, deze dus uitsluitend geobserveerd worden in hun leven zoals het ook had plaatsgevonden zonder de observatie, slechts dan kan "nee" ingevuld worden.', + max_length=1, + verbose_name="Worden de deelnemers aan een handeling onderworpen of worden hen gedragsregels opgelegd (zoals gedefinieerd door de WMO)?", + ), ), migrations.AlterField( - model_name='wmo', - name='is_medical', - field=models.CharField(blank=True, choices=[('Y', 'ja'), ('N', 'nee'), ('?', 'twijfel')], help_text='De definitie van medisch-wetenschappelijk onderzoek is: Medisch-wetenschappelijk onderzoek is onderzoek dat als doel heeft het beantwoorden van een vraag op het gebied van ziekte en gezondheid (etiologie, pathogenese, verschijnselen/symptomen, diagnose, preventie, uitkomst of behandeling van ziekte), door het op systematische wijze vergaren en bestuderen van gegevens. Het onderzoek beoogt bij te dragen aan medische kennis die ook geldend is voor populaties buiten de directe onderzoekspopulatie. (CCMO-notitie, Definitie medisch-wetenschappelijk onderzoek, 2005, ccmo.nl)', max_length=1, verbose_name='Is de onderzoeksvraag medisch-wetenschappelijk van aard (zoals gedefinieerd door de WMO)?'), + model_name="wmo", + name="is_medical", + field=models.CharField( + blank=True, + choices=[("Y", "ja"), ("N", "nee"), ("?", "twijfel")], + help_text="De definitie van medisch-wetenschappelijk onderzoek is: Medisch-wetenschappelijk onderzoek is onderzoek dat als doel heeft het beantwoorden van een vraag op het gebied van ziekte en gezondheid (etiologie, pathogenese, verschijnselen/symptomen, diagnose, preventie, uitkomst of behandeling van ziekte), door het op systematische wijze vergaren en bestuderen van gegevens. Het onderzoek beoogt bij te dragen aan medische kennis die ook geldend is voor populaties buiten de directe onderzoekspopulatie. (CCMO-notitie, Definitie medisch-wetenschappelijk onderzoek, 2005, ccmo.nl)", + max_length=1, + verbose_name="Is de onderzoeksvraag medisch-wetenschappelijk van aard (zoals gedefinieerd door de WMO)?", + ), ), migrations.AlterField( - model_name='wmo', - name='metc', - field=models.CharField(choices=[('Y', 'ja'), ('N', 'nee'), ('?', 'twijfel')], default=None, max_length=1, verbose_name='Vindt de dataverzameling plaats binnen het UMC Utrecht of andere instelling waar toetsing door een METC verplicht is gesteld?'), + model_name="wmo", + name="metc", + field=models.CharField( + choices=[("Y", "ja"), ("N", "nee"), ("?", "twijfel")], + default=None, + max_length=1, + verbose_name="Vindt de dataverzameling plaats binnen het UMC Utrecht of andere instelling waar toetsing door een METC verplicht is gesteld?", + ), ), migrations.AlterField( - model_name='wmo', - name='metc_decision_pdf', - field=models.FileField(blank=True, upload_to='', validators=[main.validators.validate_pdf_or_doc], verbose_name='Upload hier de beslissing van het METC (in .pdf of .doc(x)-formaat)'), + model_name="wmo", + name="metc_decision_pdf", + field=models.FileField( + blank=True, + upload_to="", + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Upload hier de beslissing van het METC (in .pdf of .doc(x)-formaat)", + ), ), ] diff --git a/proposals/migrations/0015_auto_20181004_1043.py b/proposals/migrations/0015_auto_20181004_1043.py index 6e39a8ae6..d2715743d 100644 --- a/proposals/migrations/0015_auto_20181004_1043.py +++ b/proposals/migrations/0015_auto_20181004_1043.py @@ -6,20 +6,22 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0014_auto_20180808_1129'), + ("proposals", "0014_auto_20180808_1129"), ] operations = [ migrations.AddField( - model_name='proposal', - name='has_minor_revision', - field=models.BooleanField(default=False, verbose_name='Is er een revisie geweest na het indienen van deze studie?'), + model_name="proposal", + name="has_minor_revision", + field=models.BooleanField( + default=False, + verbose_name="Is er een revisie geweest na het indienen van deze studie?", + ), ), migrations.AddField( - model_name='proposal', - name='minor_revision_description', - field=models.TextField(blank=True, null=True, verbose_name='Leg uit'), + model_name="proposal", + name="minor_revision_description", + field=models.TextField(blank=True, null=True, verbose_name="Leg uit"), ), ] diff --git a/proposals/migrations/0016_auto_20181005_1011.py b/proposals/migrations/0016_auto_20181005_1011.py index 7cda03093..9cc12087d 100644 --- a/proposals/migrations/0016_auto_20181005_1011.py +++ b/proposals/migrations/0016_auto_20181005_1011.py @@ -7,25 +7,37 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0015_auto_20181004_1043'), + ("proposals", "0015_auto_20181004_1043"), ] operations = [ migrations.AddField( - model_name='proposal', - name='is_pre_approved', - field=models.NullBooleanField(default=None, verbose_name='Heeft u formele toestemming van een ethische toetsingcommissie, uitgezonderd deze EtCL commissie?'), + model_name="proposal", + name="is_pre_approved", + field=models.NullBooleanField( + default=None, + verbose_name="Heeft u formele toestemming van een ethische toetsingcommissie, uitgezonderd deze EtCL commissie?", + ), ), migrations.AddField( - model_name='proposal', - name='pre_approval_institute', - field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Welk instituut heeft de studie goedgekeurd?'), + model_name="proposal", + name="pre_approval_institute", + field=models.CharField( + blank=True, + max_length=200, + null=True, + verbose_name="Welk instituut heeft de studie goedgekeurd?", + ), ), migrations.AddField( - model_name='proposal', - name='pre_approval_pdf', - field=models.FileField(blank=True, upload_to='', validators=[main.validators.validate_pdf_or_doc], verbose_name='Upload hier uw formele toestemmingsbrief van dit instituut (in .pdf of .doc(x)-formaat)'), + model_name="proposal", + name="pre_approval_pdf", + field=models.FileField( + blank=True, + upload_to="", + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Upload hier uw formele toestemmingsbrief van dit instituut (in .pdf of .doc(x)-formaat)", + ), ), ] diff --git a/proposals/migrations/0017_proposal_reviewing_committee.py b/proposals/migrations/0017_proposal_reviewing_committee.py index 473345201..acc29e201 100644 --- a/proposals/migrations/0017_proposal_reviewing_committee.py +++ b/proposals/migrations/0017_proposal_reviewing_committee.py @@ -7,17 +7,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('auth', '0008_alter_user_username_max_length'), - ('proposals', '0016_auto_20181005_1011'), + ("auth", "0008_alter_user_username_max_length"), + ("proposals", "0016_auto_20181005_1011"), ] operations = [ migrations.AddField( - model_name='proposal', - name='reviewing_committee', - field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='auth.Group', verbose_name='Door welke comissie dient deze studie te worden beoordeeld?'), + model_name="proposal", + name="reviewing_committee", + field=models.ForeignKey( + default=1, + on_delete=django.db.models.deletion.CASCADE, + to="auth.Group", + verbose_name="Door welke comissie dient deze studie te worden beoordeeld?", + ), preserve_default=False, ), ] diff --git a/proposals/migrations/0018_auto_20190124_1533.py b/proposals/migrations/0018_auto_20190124_1533.py index a27777e31..bc67c1416 100644 --- a/proposals/migrations/0018_auto_20190124_1533.py +++ b/proposals/migrations/0018_auto_20190124_1533.py @@ -8,30 +8,47 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0017_proposal_reviewing_committee'), + ("proposals", "0017_proposal_reviewing_committee"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='funding', - field=models.ManyToManyField(blank=True, to='proposals.Funding', verbose_name='Hoe wordt dit onderzoek gefinancierd?'), + model_name="proposal", + name="funding", + field=models.ManyToManyField( + blank=True, + to="proposals.Funding", + verbose_name="Hoe wordt dit onderzoek gefinancierd?", + ), ), migrations.AlterField( - model_name='proposal', - name='relation', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='proposals.Relation', verbose_name='In welke hoedanigheid bent u betrokken bij deze UiL OTS studie?'), + model_name="proposal", + name="relation", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="proposals.Relation", + verbose_name="In welke hoedanigheid bent u betrokken bij deze UiL OTS studie?", + ), ), migrations.AlterField( - model_name='proposal', - name='reviewing_committee', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='auth.Group', verbose_name='Door welke comissie dient deze studie te worden beoordeeld?'), + model_name="proposal", + name="reviewing_committee", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="auth.Group", + verbose_name="Door welke comissie dient deze studie te worden beoordeeld?", + ), ), migrations.AlterField( - model_name='proposal', - name='summary', - field=models.TextField(blank=True, validators=[main.validators.MaxWordsValidator(200)], verbose_name='Geef een duidelijke, bondige beschrijving van de onderzoeksvraag of -vragen. Gebruik maximaal 200 woorden.'), + model_name="proposal", + name="summary", + field=models.TextField( + blank=True, + validators=[main.validators.MaxWordsValidator(200)], + verbose_name="Geef een duidelijke, bondige beschrijving van de onderzoeksvraag of -vragen. Gebruik maximaal 200 woorden.", + ), ), ] diff --git a/proposals/migrations/0019_auto_20190401_1343.py b/proposals/migrations/0019_auto_20190401_1343.py index 889d48190..ad45c6279 100644 --- a/proposals/migrations/0019_auto_20190401_1343.py +++ b/proposals/migrations/0019_auto_20190401_1343.py @@ -8,71 +8,133 @@ class Migration(migrations.Migration): - dependencies = [ - ('auth', '0008_alter_user_username_max_length'), - ('proposals', '0018_auto_20190124_1533'), + ("auth", "0008_alter_user_username_max_length"), + ("proposals", "0018_auto_20190124_1533"), ] operations = [ migrations.CreateModel( - name='Institution', + name="Institution", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('order', models.PositiveIntegerField(unique=True)), - ('description', models.CharField(max_length=200)), - ('reviewing_chamber', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='auth.Group')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("order", models.PositiveIntegerField(unique=True)), + ("description", models.CharField(max_length=200)), + ( + "reviewing_chamber", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="auth.Group" + ), + ), ], ), migrations.AlterField( - model_name='proposal', - name='is_pre_approved', - field=models.NullBooleanField(default=None, verbose_name='Heeft u formele toestemming van een ethische toetsingcommissie, uitgezonderd deze FETC-GW commissie?'), + model_name="proposal", + name="is_pre_approved", + field=models.NullBooleanField( + default=None, + verbose_name="Heeft u formele toestemming van een ethische toetsingcommissie, uitgezonderd deze FETC-GW commissie?", + ), ), migrations.AlterField( - model_name='proposal', - name='other_applicants', - field=models.BooleanField(default=False, verbose_name='Zijn er nog andere onderzoekers bij deze studie betrokken die geaffilieerd zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of UiL OTS?'), + model_name="proposal", + name="other_applicants", + field=models.BooleanField( + default=False, + verbose_name="Zijn er nog andere onderzoekers bij deze studie betrokken die geaffilieerd zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of UiL OTS?", + ), ), migrations.AlterField( - model_name='proposal', - name='other_stakeholders', - field=models.BooleanField(default=False, verbose_name='Zijn er nog andere onderzoekers bij deze studie betrokken die niet geaffilieerd zijn aan een van de onderzoeksinstituten van de Faculteit Geestwetenschappen van de UU? '), + model_name="proposal", + name="other_stakeholders", + field=models.BooleanField( + default=False, + verbose_name="Zijn er nog andere onderzoekers bij deze studie betrokken die niet geaffilieerd zijn aan een van de onderzoeksinstituten van de Faculteit Geestwetenschappen van de UU? ", + ), ), migrations.AlterField( - model_name='proposal', - name='relation', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='proposals.Relation', verbose_name='In welke hoedanigheid bent u betrokken bij deze studie?'), + model_name="proposal", + name="relation", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="proposals.Relation", + verbose_name="In welke hoedanigheid bent u betrokken bij deze studie?", + ), ), migrations.AlterField( - model_name='proposal', - name='status', - field=models.PositiveIntegerField(choices=[(1, 'Concept'), (40, 'Opgestuurd ter beoordeling door eindverantwoordelijke'), (50, 'Opgestuurd ter beoordeling door FETC-GW'), (55, 'Studie is beoordeeld door FETC-GW'), (60, 'Studie is beoordeeld door FETC-GW')], default=1), + model_name="proposal", + name="status", + field=models.PositiveIntegerField( + choices=[ + (1, "Concept"), + (40, "Opgestuurd ter beoordeling door eindverantwoordelijke"), + (50, "Opgestuurd ter beoordeling door FETC-GW"), + (55, "Studie is beoordeeld door FETC-GW"), + (60, "Studie is beoordeeld door FETC-GW"), + ], + default=1, + ), ), migrations.AlterField( - model_name='proposal', - name='supervisor', - field=models.ForeignKey(blank=True, help_text='Aan het einde van de procedure kunt u deze studie ter verificatie naar uw eindverantwoordelijke sturen. De eindverantwoordelijke zal de studie vervolgens kunnen aanpassen en indienen bij de FETC-GW.', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Eindverantwoordelijke onderzoeker'), + model_name="proposal", + name="supervisor", + field=models.ForeignKey( + blank=True, + help_text="Aan het einde van de procedure kunt u deze studie ter verificatie naar uw eindverantwoordelijke sturen. De eindverantwoordelijke zal de studie vervolgens kunnen aanpassen en indienen bij de FETC-GW.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="Eindverantwoordelijke onderzoeker", + ), ), migrations.AlterField( - model_name='proposal', - name='title', - field=models.CharField(help_text='De titel die u hier opgeeft is zichtbaar voor de FETC-GW-leden en, wanneer de studie is goedgekeurd, ook voor alle medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een studie die u heeft ingediend.', max_length=200, unique=True, verbose_name='Wat is de titel van uw studie? Deze titel zal worden gebruikt in alle formele correspondentie.'), + model_name="proposal", + name="title", + field=models.CharField( + help_text="De titel die u hier opgeeft is zichtbaar voor de FETC-GW-leden en, wanneer de studie is goedgekeurd, ook voor alle medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een studie die u heeft ingediend.", + max_length=200, + unique=True, + verbose_name="Wat is de titel van uw studie? Deze titel zal worden gebruikt in alle formele correspondentie.", + ), ), migrations.AlterField( - model_name='wmo', - name='metc', - field=models.CharField(blank=True, choices=[('Y', 'ja'), ('N', 'nee'), ('?', 'twijfel')], default=None, max_length=1, verbose_name='Vindt de dataverzameling plaats binnen het UMC Utrecht of andere instelling waar toetsing door een METC verplicht is gesteld?'), + model_name="wmo", + name="metc", + field=models.CharField( + blank=True, + choices=[("Y", "ja"), ("N", "nee"), ("?", "twijfel")], + default=None, + max_length=1, + verbose_name="Vindt de dataverzameling plaats binnen het UMC Utrecht of andere instelling waar toetsing door een METC verplicht is gesteld?", + ), ), migrations.AlterField( - model_name='wmo', - name='metc_application', - field=models.BooleanField(default=False, verbose_name='Uw studie moet beoordeeld worden door de METC, maar dient nog wel bij de FETC-GW te worden geregistreerd. Is deze studie al aangemeld bij een METC?'), + model_name="wmo", + name="metc_application", + field=models.BooleanField( + default=False, + verbose_name="Uw studie moet beoordeeld worden door de METC, maar dient nog wel bij de FETC-GW te worden geregistreerd. Is deze studie al aangemeld bij een METC?", + ), ), migrations.AddField( - model_name='proposal', - name='institution', - field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.PROTECT, to='proposals.Institution', verbose_name='Aan welk onderzoeksinstituut bent u verbonden?'), + model_name="proposal", + name="institution", + field=models.ForeignKey( + default=1, + on_delete=django.db.models.deletion.PROTECT, + to="proposals.Institution", + verbose_name="Aan welk onderzoeksinstituut bent u verbonden?", + ), preserve_default=False, ), ] diff --git a/proposals/migrations/0020_auto_20190401_1348.py b/proposals/migrations/0020_auto_20190401_1348.py index c0bd75b98..03433cdbc 100644 --- a/proposals/migrations/0020_auto_20190401_1348.py +++ b/proposals/migrations/0020_auto_20190401_1348.py @@ -6,24 +6,23 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0019_auto_20190401_1343'), + ("proposals", "0019_auto_20190401_1343"), ] operations = [ migrations.AlterModelOptions( - name='institution', - options={'ordering': ['order']}, + name="institution", + options={"ordering": ["order"]}, ), migrations.AddField( - model_name='institution', - name='description_en', + model_name="institution", + name="description_en", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='institution', - name='description_nl', + model_name="institution", + name="description_nl", field=models.CharField(max_length=200, null=True), ), ] diff --git a/proposals/migrations/0021_auto_20190926_1559.py b/proposals/migrations/0021_auto_20190926_1559.py index eabb6f7a3..b3af10480 100644 --- a/proposals/migrations/0021_auto_20190926_1559.py +++ b/proposals/migrations/0021_auto_20190926_1559.py @@ -6,15 +6,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0020_auto_20190401_1348'), + ("proposals", "0020_auto_20190401_1348"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='reference_number', + model_name="proposal", + name="reference_number", field=models.CharField(max_length=20, unique=True), ), ] diff --git a/proposals/migrations/0022_auto_20191107_1438.py b/proposals/migrations/0022_auto_20191107_1438.py index d75baae1a..f12efe740 100644 --- a/proposals/migrations/0022_auto_20191107_1438.py +++ b/proposals/migrations/0022_auto_20191107_1438.py @@ -6,15 +6,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0021_auto_20190926_1559'), + ("proposals", "0021_auto_20190926_1559"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='title', - field=models.CharField(help_text='De titel die u hier opgeeft is zichtbaar voor de FETC-GW-leden en, wanneer de studie is goedgekeurd, ook voor alle medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een studie die u heeft ingediend.', max_length=200, verbose_name='Wat is de titel van uw studie? Deze titel zal worden gebruikt in alle formele correspondentie.'), + model_name="proposal", + name="title", + field=models.CharField( + help_text="De titel die u hier opgeeft is zichtbaar voor de FETC-GW-leden en, wanneer de studie is goedgekeurd, ook voor alle medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een studie die u heeft ingediend.", + max_length=200, + verbose_name="Wat is de titel van uw studie? Deze titel zal worden gebruikt in alle formele correspondentie.", + ), ), ] diff --git a/proposals/migrations/0023_auto_20200428_1337.py b/proposals/migrations/0023_auto_20200428_1337.py index 573817864..8c8bc954d 100644 --- a/proposals/migrations/0023_auto_20200428_1337.py +++ b/proposals/migrations/0023_auto_20200428_1337.py @@ -4,30 +4,44 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0022_auto_20191107_1438'), + ("proposals", "0022_auto_20191107_1438"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='inform_local_staff', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='

      U hebt aangegeven dat u gebruik wilt gaan maken van één van de faciliteiten van het UiL OTS, namelijk de database, Zep software en/of het UiL OTS lab. Het lab supportteam van het UiL OTS zou graag op de hoogte willen worden gesteld van aankomende studies. Daarom vragen wij hier u toestemming om delen van deze aanvraag door te sturen naar het lab supportteam.

      Vindt u het goed dat de volgende delen uit de aanvraag worden doorgestuurd:

      - Uw naam en de namen van de andere betrokkenen
      - De eindverantwoordelijke van de studie
      - De titel van de studie
      - De beoogde startdatum
      - Van welke faciliteiten u gebruik wilt maken (database, lab, Zep software)'), + model_name="proposal", + name="inform_local_staff", + field=models.BooleanField( + blank=True, + default=None, + null=True, + verbose_name="

      U hebt aangegeven dat u gebruik wilt gaan maken van één van de faciliteiten van het UiL OTS, namelijk de database, Zep software en/of het UiL OTS lab. Het lab supportteam van het UiL OTS zou graag op de hoogte willen worden gesteld van aankomende studies. Daarom vragen wij hier u toestemming om delen van deze aanvraag door te sturen naar het lab supportteam.

      Vindt u het goed dat de volgende delen uit de aanvraag worden doorgestuurd:

      - Uw naam en de namen van de andere betrokkenen
      - De eindverantwoordelijke van de studie
      - De titel van de studie
      - De beoogde startdatum
      - Van welke faciliteiten u gebruik wilt maken (database, lab, Zep software)", + ), ), migrations.AlterField( - model_name='proposal', - name='is_pre_approved', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='Heeft u formele toestemming van een ethische toetsingcommissie, uitgezonderd deze FETC-GW commissie?'), + model_name="proposal", + name="is_pre_approved", + field=models.BooleanField( + blank=True, + default=None, + null=True, + verbose_name="Heeft u formele toestemming van een ethische toetsingcommissie, uitgezonderd deze FETC-GW commissie?", + ), ), migrations.AlterField( - model_name='proposal', - name='status_review', + model_name="proposal", + name="status_review", field=models.BooleanField(blank=True, default=None, null=True), ), migrations.AlterField( - model_name='proposal', - name='studies_similar', - field=models.BooleanField(blank=True, help_text='Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is sprake van in essentie hetzelfde traject. Denk hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van een set verhaaltjes te lezen krijgt, en de andere groep in taak X de andere helft. Of aan interventieonderzoek waarin drie vergelijkbare groepen op hetzelfde moment een verschillende interventie-variant krijgen (specificeer dan wel bij de beschrijving van de interventie welke varianten precies gebruikt worden).', null=True, verbose_name='Doorlopen alle deelnemersgroepen in essentie hetzelfde traject?'), + model_name="proposal", + name="studies_similar", + field=models.BooleanField( + blank=True, + help_text="Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is sprake van in essentie hetzelfde traject. Denk hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van een set verhaaltjes te lezen krijgt, en de andere groep in taak X de andere helft. Of aan interventieonderzoek waarin drie vergelijkbare groepen op hetzelfde moment een verschillende interventie-variant krijgen (specificeer dan wel bij de beschrijving van de interventie welke varianten precies gebruikt worden).", + null=True, + verbose_name="Doorlopen alle deelnemersgroepen in essentie hetzelfde traject?", + ), ), ] diff --git a/proposals/migrations/0023_auto_20201203_0906.py b/proposals/migrations/0023_auto_20201203_0906.py index 927ecb1dc..9259d1aad 100644 --- a/proposals/migrations/0023_auto_20201203_0906.py +++ b/proposals/migrations/0023_auto_20201203_0906.py @@ -8,20 +8,31 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0022_auto_20191107_1438'), + ("proposals", "0022_auto_20191107_1438"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='applicants', - field=models.ManyToManyField(help_text='Klik in het vlak hiernaast en type een aantal letters van de voornaam, achternaam, of Solis ID van de persoon die u toe wilt voegen. Klik vervolgens om de persoon toe te voegen. Merk op dat het laden even kan duren.', related_name='applicants', to=settings.AUTH_USER_MODEL, verbose_name='Uitvoerende(n) (inclusief uzelf)'), + model_name="proposal", + name="applicants", + field=models.ManyToManyField( + help_text="Klik in het vlak hiernaast en type een aantal letters van de voornaam, achternaam, of Solis ID van de persoon die u toe wilt voegen. Klik vervolgens om de persoon toe te voegen. Merk op dat het laden even kan duren.", + related_name="applicants", + to=settings.AUTH_USER_MODEL, + verbose_name="Uitvoerende(n) (inclusief uzelf)", + ), ), migrations.AlterField( - model_name='proposal', - name='supervisor', - field=models.ForeignKey(blank=True, help_text='Aan het einde van de procedure kunt u deze studie ter verificatie naar uw eindverantwoordelijke\n sturen. De eindverantwoordelijke zal de studie vervolgens kunnen aanpassen en indienen bij de FETC-GW.\n

      Tip: Type een aantal letters van de voornaam, achternaam, of Solis ID van\n de persoon die u toe wilt voegen in de zoekbalk hiernaast. Merk op dat het laden even kan duren.', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Eindverantwoordelijke onderzoeker'), + model_name="proposal", + name="supervisor", + field=models.ForeignKey( + blank=True, + help_text="Aan het einde van de procedure kunt u deze studie ter verificatie naar uw eindverantwoordelijke\n sturen. De eindverantwoordelijke zal de studie vervolgens kunnen aanpassen en indienen bij de FETC-GW.\n

      Tip: Type een aantal letters van de voornaam, achternaam, of Solis ID van\n de persoon die u toe wilt voegen in de zoekbalk hiernaast. Merk op dat het laden even kan duren.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="Eindverantwoordelijke onderzoeker", + ), ), ] diff --git a/proposals/migrations/0024_remove_wmo_is_behavioristic.py b/proposals/migrations/0024_remove_wmo_is_behavioristic.py index 6773249a9..b4783d8f9 100644 --- a/proposals/migrations/0024_remove_wmo_is_behavioristic.py +++ b/proposals/migrations/0024_remove_wmo_is_behavioristic.py @@ -6,14 +6,13 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0023_auto_20201203_0906'), + ("proposals", "0023_auto_20201203_0906"), ] operations = [ migrations.RemoveField( - model_name='wmo', - name='is_behavioristic', + model_name="wmo", + name="is_behavioristic", ), ] diff --git a/proposals/migrations/0025_merge_20201222_1654.py b/proposals/migrations/0025_merge_20201222_1654.py index 763ab150b..be1655a4b 100644 --- a/proposals/migrations/0025_merge_20201222_1654.py +++ b/proposals/migrations/0025_merge_20201222_1654.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0024_remove_wmo_is_behavioristic'), - ('proposals', '0023_auto_20200428_1337'), + ("proposals", "0024_remove_wmo_is_behavioristic"), + ("proposals", "0023_auto_20200428_1337"), ] - operations = [ - ] + operations = [] diff --git a/proposals/migrations/0026_auto_20210112_1632.py b/proposals/migrations/0026_auto_20210112_1632.py index c457cc98d..19d8a775d 100644 --- a/proposals/migrations/0026_auto_20210112_1632.py +++ b/proposals/migrations/0026_auto_20210112_1632.py @@ -6,20 +6,30 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0025_merge_20201222_1654'), + ("proposals", "0025_merge_20201222_1654"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='applicants', - field=models.ManyToManyField(related_name='applicants', to=settings.AUTH_USER_MODEL, verbose_name='Uitvoerende(n) (inclusief uzelf)'), + model_name="proposal", + name="applicants", + field=models.ManyToManyField( + related_name="applicants", + to=settings.AUTH_USER_MODEL, + verbose_name="Uitvoerende(n) (inclusief uzelf)", + ), ), migrations.AlterField( - model_name='proposal', - name='parent', - field=models.ForeignKey(help_text='Dit veld toont enkel studies waar u zelf een medeuitvoerende bent.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='proposals.Proposal', verbose_name='Te kopiëren studie'), + model_name="proposal", + name="parent", + field=models.ForeignKey( + help_text="Dit veld toont enkel studies waar u zelf een medeuitvoerende bent.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="children", + to="proposals.Proposal", + verbose_name="Te kopiëren studie", + ), ), ] diff --git a/proposals/migrations/0027_auto_20210118_1735.py b/proposals/migrations/0027_auto_20210118_1735.py index 8b20ce1fc..c67507236 100644 --- a/proposals/migrations/0027_auto_20210118_1735.py +++ b/proposals/migrations/0027_auto_20210118_1735.py @@ -5,15 +5,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0026_auto_20210112_1632'), + ("proposals", "0026_auto_20210112_1632"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='studies_number', - field=models.PositiveIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(10)], verbose_name='Hoeveel verschillende trajecten zijn er?'), + model_name="proposal", + name="studies_number", + field=models.PositiveIntegerField( + default=1, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(10), + ], + verbose_name="Hoeveel verschillende trajecten zijn er?", + ), ), ] diff --git a/proposals/migrations/0028_auto_20210125_1159.py b/proposals/migrations/0028_auto_20210125_1159.py index 6b1be609f..a649268d6 100644 --- a/proposals/migrations/0028_auto_20210125_1159.py +++ b/proposals/migrations/0028_auto_20210125_1159.py @@ -7,25 +7,42 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0027_auto_20210118_1735'), + ("proposals", "0027_auto_20210118_1735"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='parent', - field=models.ForeignKey(help_text='Dit veld toont enkel studies waar u zelf een medeuitvoerende bent.', null=True, on_delete=django.db.models.deletion.CASCADE, to='proposals.Proposal', verbose_name='Te kopiëren studie'), + model_name="proposal", + name="parent", + field=models.ForeignKey( + help_text="Dit veld toont enkel studies waar u zelf een medeuitvoerende bent.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="proposals.Proposal", + verbose_name="Te kopiëren studie", + ), ), migrations.AlterField( - model_name='proposal', - name='pdf', - field=models.FileField(blank=True, storage=proposals.utils.proposal_utils.OverwriteStorage(), upload_to=proposals.utils.proposal_utils.FilenameFactory('Proposal')), + model_name="proposal", + name="pdf", + field=models.FileField( + blank=True, + storage=proposals.utils.proposal_utils.OverwriteStorage(), + upload_to=proposals.utils.proposal_utils.FilenameFactory("Proposal"), + ), ), migrations.AlterField( - model_name='wmo', - name='metc_decision_pdf', - field=models.FileField(blank=True, storage=proposals.utils.proposal_utils.OverwriteStorage(), upload_to=proposals.utils.proposal_utils.FilenameFactory('METC_Decision'), validators=[main.validators.validate_pdf_or_doc], verbose_name='Upload hier de beslissing van het METC (in .pdf of .doc(x)-formaat)'), + model_name="wmo", + name="metc_decision_pdf", + field=models.FileField( + blank=True, + storage=proposals.utils.proposal_utils.OverwriteStorage(), + upload_to=proposals.utils.proposal_utils.FilenameFactory( + "METC_Decision" + ), + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Upload hier de beslissing van het METC (in .pdf of .doc(x)-formaat)", + ), ), ] diff --git a/proposals/migrations/0029_auto_20210129_1717.py b/proposals/migrations/0029_auto_20210129_1717.py index 8ee0a28d5..d7ca8b9ca 100644 --- a/proposals/migrations/0029_auto_20210129_1717.py +++ b/proposals/migrations/0029_auto_20210129_1717.py @@ -6,15 +6,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0028_auto_20210125_1159'), + ("proposals", "0028_auto_20210125_1159"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='pre_assessment_pdf', - field=models.FileField(blank=True, upload_to=proposals.utils.proposal_utils.FilenameFactory('Preassessment'), validators=[main.validators.validate_pdf_or_doc], verbose_name='Upload hier uw aanvraag (in .pdf of .doc(x)-formaat)'), + model_name="proposal", + name="pre_assessment_pdf", + field=models.FileField( + blank=True, + upload_to=proposals.utils.proposal_utils.FilenameFactory( + "Preassessment" + ), + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Upload hier uw aanvraag (in .pdf of .doc(x)-formaat)", + ), ), ] diff --git a/proposals/migrations/0030_auto_20210201_1514.py b/proposals/migrations/0030_auto_20210201_1514.py index 89311ed04..b1c52e34a 100644 --- a/proposals/migrations/0030_auto_20210201_1514.py +++ b/proposals/migrations/0030_auto_20210201_1514.py @@ -5,15 +5,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0029_auto_20210129_1717'), + ("proposals", "0029_auto_20210129_1717"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='parent', - field=models.ForeignKey(help_text='Dit veld toont enkel studies waar u zelf een medeuitvoerende bent.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='proposals.Proposal', verbose_name='Te kopiëren studie'), + model_name="proposal", + name="parent", + field=models.ForeignKey( + help_text="Dit veld toont enkel studies waar u zelf een medeuitvoerende bent.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="children", + to="proposals.Proposal", + verbose_name="Te kopiëren studie", + ), ), ] diff --git a/proposals/migrations/0031_auto_20210201_1519.py b/proposals/migrations/0031_auto_20210201_1519.py index a842d302c..97e1558fd 100644 --- a/proposals/migrations/0031_auto_20210201_1519.py +++ b/proposals/migrations/0031_auto_20210201_1519.py @@ -6,15 +6,21 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0030_auto_20210201_1514'), + ("proposals", "0030_auto_20210201_1514"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='pre_approval_pdf', - field=models.FileField(blank=True, upload_to=proposals.utils.proposal_utils.FilenameFactory('Pre_Approval'), validators=[main.validators.validate_pdf_or_doc], verbose_name='Upload hier uw formele toestemmingsbrief van dit instituut (in .pdf of .doc(x)-formaat)'), + model_name="proposal", + name="pre_approval_pdf", + field=models.FileField( + blank=True, + upload_to=proposals.utils.proposal_utils.FilenameFactory( + "Pre_Approval" + ), + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Upload hier uw formele toestemmingsbrief van dit instituut (in .pdf of .doc(x)-formaat)", + ), ), ] diff --git a/proposals/migrations/0032_proposal_avg_understood.py b/proposals/migrations/0032_proposal_avg_understood.py index 1efbe9b9e..dfa303d79 100644 --- a/proposals/migrations/0032_proposal_avg_understood.py +++ b/proposals/migrations/0032_proposal_avg_understood.py @@ -4,15 +4,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0031_auto_20210201_1519'), + ("proposals", "0031_auto_20210201_1519"), ] operations = [ migrations.AddField( - model_name='proposal', - name='avg_understood', + model_name="proposal", + name="avg_understood", field=models.BooleanField(default=None, null=True), ), ] diff --git a/proposals/migrations/0033_auto_20210521_1154.py b/proposals/migrations/0033_auto_20210521_1154.py index 9e4c24677..68b8b9534 100644 --- a/proposals/migrations/0033_auto_20210521_1154.py +++ b/proposals/migrations/0033_auto_20210521_1154.py @@ -6,20 +6,25 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0032_proposal_avg_understood'), + ("proposals", "0032_proposal_avg_understood"), ] operations = [ migrations.AddField( - model_name='proposal', - name='dmp_file', - field=models.FileField(blank=True, storage=proposals.utils.proposal_utils.OverwriteStorage(), upload_to=proposals.utils.proposal_utils.FilenameFactory('DMP'), validators=[main.validators.validate_pdf_or_doc], verbose_name='Als u een Data Management Plan heeft voor deze studie, kunt u kiezen om deze hier bij te voegen. Het aanleveren van een DMP vergemakkelijkt het toetsingsproces aanzienlijk.'), + model_name="proposal", + name="dmp_file", + field=models.FileField( + blank=True, + storage=proposals.utils.proposal_utils.OverwriteStorage(), + upload_to=proposals.utils.proposal_utils.FilenameFactory("DMP"), + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Als u een Data Management Plan heeft voor deze studie, kunt u kiezen om deze hier bij te voegen. Het aanleveren van een DMP vergemakkelijkt het toetsingsproces aanzienlijk.", + ), ), migrations.AlterField( - model_name='proposal', - name='avg_understood', + model_name="proposal", + name="avg_understood", field=models.BooleanField(default=False), ), ] diff --git a/proposals/migrations/0034_auto_20211213_1503.py b/proposals/migrations/0034_auto_20211213_1503.py index f026a0ed4..43c269528 100644 --- a/proposals/migrations/0034_auto_20211213_1503.py +++ b/proposals/migrations/0034_auto_20211213_1503.py @@ -5,119 +5,228 @@ import django.db.models.deletion import main.validators import proposals.utils.proposal_utils -import proposals.validators -class Migration(migrations.Migration): +def AVGUnderstoodValidator(): + """This was formerly a validator, imported from proposals.validators, + but it is currently no longer required, so it has been removed. + To prevent an error, it has been replaced with this stub.""" + pass + +class Migration(migrations.Migration): dependencies = [ - ('proposals', '0033_auto_20210521_1154'), + ("proposals", "0033_auto_20210521_1154"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='avg_understood', - field=models.BooleanField(default=False, validators=[proposals.validators.AVGUnderstoodValidator], verbose_name='Ik heb kennis genomen van het bovenstaande en begrijp mijn verantwoordelijkheden ten opzichte van de AVG.'), - ), - migrations.AlterField( - model_name='proposal', - name='date_start', - field=models.DateField(blank=True, null=True, verbose_name='Wat is de beoogde startdatum van het onderzoek waarvoor deze aanvraag wordt ingediend?'), - ), - migrations.AlterField( - model_name='proposal', - name='dmp_file', - field=models.FileField(blank=True, storage=proposals.utils.proposal_utils.OverwriteStorage(), upload_to=proposals.utils.proposal_utils.FilenameFactory('DMP'), validators=[main.validators.validate_pdf_or_doc], verbose_name='Als je een Data Management Plan hebt voor deze aanvraag, kan je kiezen om deze hier bij te voegen. Het aanleveren van een DMP vergemakkelijkt het toetsingsproces aanzienlijk.'), - ), - migrations.AlterField( - model_name='proposal', - name='funding_name', - field=models.CharField(blank=True, help_text='De titel die je hier opgeeft zal in de formele toestemmingsbrief gebruikt worden.', max_length=200, verbose_name='Wat is de naam van het gefinancierde project?'), - ), - migrations.AlterField( - model_name='proposal', - name='has_minor_revision', - field=models.BooleanField(default=False, verbose_name='Is er een revisie geweest na het indienen van deze aanvraag?'), - ), - migrations.AlterField( - model_name='proposal', - name='inform_local_staff', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='

      Je hebt aangegeven dat je gebruik wilt gaan maken van één van de faciliteiten van het UiL OTS, namelijk de database, Zep software en/of het UiL OTS lab. Het lab supportteam van het UiL OTS zou graag op de hoogte willen worden gesteld van aankomende onderzoeken. Daarom vragen wij hier jouw toestemming om delen van deze aanvraag door te sturen naar het lab supportteam.

      Vind je het goed dat de volgende delen uit de aanvraag worden doorgestuurd:

      - Jouw naam en de namen van de andere betrokkenen
      - De eindverantwoordelijke van het onderzoek
      - De titel van het onderzoek
      - De beoogde startdatum
      - Van welke faciliteiten je gebruik wil maken (database, lab, Zep software)'), - ), - migrations.AlterField( - model_name='proposal', - name='institution', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='proposals.Institution', verbose_name='Aan welk onderzoeksinstituut ben je verbonden?'), - ), - migrations.AlterField( - model_name='proposal', - name='is_pre_approved', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='Heb je formele toestemming van een ethische toetsingcommissie, uitgezonderd deze FETC-GW commissie?'), - ), - migrations.AlterField( - model_name='proposal', - name='is_revision', - field=models.BooleanField(default=False, verbose_name='Is deze aanvraag een revisie van of amendement op een ingediende aanvraag?'), - ), - migrations.AlterField( - model_name='proposal', - name='other_applicants', - field=models.BooleanField(default=False, verbose_name='Zijn er nog andere onderzoekers bij deze aanvraag betrokken die geaffilieerd zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of UiL OTS?'), - ), - migrations.AlterField( - model_name='proposal', - name='other_stakeholders', - field=models.BooleanField(default=False, verbose_name='Zijn er nog andere onderzoekers bij deze aanvraag betrokken die niet geaffilieerd zijn aan een van de onderzoeksinstituten van de Faculteit Geestwetenschappen van de UU? '), - ), - migrations.AlterField( - model_name='proposal', - name='parent', - field=models.ForeignKey(help_text='Dit veld toont enkel aanvragen waar je zelf een medeuitvoerende bent.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='proposals.Proposal', verbose_name='Te kopiëren aanvraag'), - ), - migrations.AlterField( - model_name='proposal', - name='pre_approval_institute', - field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Welk instituut heeft de aanvraag goedgekeurd?'), - ), - migrations.AlterField( - model_name='proposal', - name='pre_approval_pdf', - field=models.FileField(blank=True, upload_to=proposals.utils.proposal_utils.FilenameFactory('Pre_Approval'), validators=[main.validators.validate_pdf_or_doc], verbose_name='Upload hier je formele toestemmingsbrief van dit instituut (in .pdf of .doc(x)-formaat)'), - ), - migrations.AlterField( - model_name='proposal', - name='pre_assessment_pdf', - field=models.FileField(blank=True, upload_to=proposals.utils.proposal_utils.FilenameFactory('Preassessment'), validators=[main.validators.validate_pdf_or_doc], verbose_name='Upload hier je aanvraag (in .pdf of .doc(x)-formaat)'), - ), - migrations.AlterField( - model_name='proposal', - name='relation', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='proposals.Relation', verbose_name='In welke hoedanigheid ben je betrokken bij dit onderzoek?'), - ), - migrations.AlterField( - model_name='proposal', - name='reviewing_committee', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='auth.Group', verbose_name='Door welke comissie dient deze aanvraag te worden beoordeeld?'), - ), - migrations.AlterField( - model_name='proposal', - name='status', - field=models.PositiveIntegerField(choices=[(1, 'Concept'), (40, 'Opgestuurd ter beoordeling door eindverantwoordelijke'), (50, 'Opgestuurd ter beoordeling door FETC-GW'), (55, 'Aanvraag is beoordeeld door FETC-GW'), (60, 'Aanvraag is beoordeeld door FETC-GW')], default=1), - ), - migrations.AlterField( - model_name='proposal', - name='supervisor', - field=models.ForeignKey(blank=True, help_text='Aan het einde van de procedure kan je deze aanvraag ter\n verificatie naar je eindverantwoordelijke sturen. De\n eindverantwoordelijke zal de aanvraag vervolgens kunnen aanpassen en\n indienen bij de FETC-GW.

      Tip: Type een\n aantal letters van de voornaam, achternaam, of Solis ID van het\n persoon die je toe wilt voegen in de zoekbalk hiernaast.\n Merk op dat het laden even kan duren.', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Eindverantwoordelijke onderzoeker'), - ), - migrations.AlterField( - model_name='proposal', - name='title', - field=models.CharField(help_text='De titel die je hier opgeeft is zichtbaar voor de FETC-GW-leden en, wanneer de aanvraag is goedgekeurd, ook voor alle medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een aanvraag die je hebt ingediend.', max_length=200, verbose_name='Wat is de titel van je aanvraag? Deze titel zal worden gebruikt in alle formele correspondentie.'), - ), - migrations.AlterField( - model_name='wmo', - name='metc_application', - field=models.BooleanField(default=False, verbose_name='Je onderzoek moet beoordeeld worden door een METC, maar dient nog wel bij de FETC-GW te worden geregistreerd. Is dit onderzoek al aangemeld bij een METC?'), + model_name="proposal", + name="avg_understood", + field=models.BooleanField( + default=False, + validators=[AVGUnderstoodValidator], + verbose_name="Ik heb kennis genomen van het bovenstaande en begrijp mijn verantwoordelijkheden ten opzichte van de AVG.", + ), + ), + migrations.AlterField( + model_name="proposal", + name="date_start", + field=models.DateField( + blank=True, + null=True, + verbose_name="Wat is de beoogde startdatum van het onderzoek waarvoor deze aanvraag wordt ingediend?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="dmp_file", + field=models.FileField( + blank=True, + storage=proposals.utils.proposal_utils.OverwriteStorage(), + upload_to=proposals.utils.proposal_utils.FilenameFactory("DMP"), + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Als je een Data Management Plan hebt voor deze aanvraag, kan je kiezen om deze hier bij te voegen. Het aanleveren van een DMP vergemakkelijkt het toetsingsproces aanzienlijk.", + ), + ), + migrations.AlterField( + model_name="proposal", + name="funding_name", + field=models.CharField( + blank=True, + help_text="De titel die je hier opgeeft zal in de formele toestemmingsbrief gebruikt worden.", + max_length=200, + verbose_name="Wat is de naam van het gefinancierde project?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="has_minor_revision", + field=models.BooleanField( + default=False, + verbose_name="Is er een revisie geweest na het indienen van deze aanvraag?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="inform_local_staff", + field=models.BooleanField( + blank=True, + default=None, + null=True, + verbose_name="

      Je hebt aangegeven dat je gebruik wilt gaan maken van één van de faciliteiten van het UiL OTS, namelijk de database, Zep software en/of het UiL OTS lab. Het lab supportteam van het UiL OTS zou graag op de hoogte willen worden gesteld van aankomende onderzoeken. Daarom vragen wij hier jouw toestemming om delen van deze aanvraag door te sturen naar het lab supportteam.

      Vind je het goed dat de volgende delen uit de aanvraag worden doorgestuurd:

      - Jouw naam en de namen van de andere betrokkenen
      - De eindverantwoordelijke van het onderzoek
      - De titel van het onderzoek
      - De beoogde startdatum
      - Van welke faciliteiten je gebruik wil maken (database, lab, Zep software)", + ), + ), + migrations.AlterField( + model_name="proposal", + name="institution", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="proposals.Institution", + verbose_name="Aan welk onderzoeksinstituut ben je verbonden?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="is_pre_approved", + field=models.BooleanField( + blank=True, + default=None, + null=True, + verbose_name="Heb je formele toestemming van een ethische toetsingcommissie, uitgezonderd deze FETC-GW commissie?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="is_revision", + field=models.BooleanField( + default=False, + verbose_name="Is deze aanvraag een revisie van of amendement op een ingediende aanvraag?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="other_applicants", + field=models.BooleanField( + default=False, + verbose_name="Zijn er nog andere onderzoekers bij deze aanvraag betrokken die geaffilieerd zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of UiL OTS?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="other_stakeholders", + field=models.BooleanField( + default=False, + verbose_name="Zijn er nog andere onderzoekers bij deze aanvraag betrokken die niet geaffilieerd zijn aan een van de onderzoeksinstituten van de Faculteit Geestwetenschappen van de UU? ", + ), + ), + migrations.AlterField( + model_name="proposal", + name="parent", + field=models.ForeignKey( + help_text="Dit veld toont enkel aanvragen waar je zelf een medeuitvoerende bent.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="children", + to="proposals.Proposal", + verbose_name="Te kopiëren aanvraag", + ), + ), + migrations.AlterField( + model_name="proposal", + name="pre_approval_institute", + field=models.CharField( + blank=True, + max_length=200, + null=True, + verbose_name="Welk instituut heeft de aanvraag goedgekeurd?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="pre_approval_pdf", + field=models.FileField( + blank=True, + upload_to=proposals.utils.proposal_utils.FilenameFactory( + "Pre_Approval" + ), + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Upload hier je formele toestemmingsbrief van dit instituut (in .pdf of .doc(x)-formaat)", + ), + ), + migrations.AlterField( + model_name="proposal", + name="pre_assessment_pdf", + field=models.FileField( + blank=True, + upload_to=proposals.utils.proposal_utils.FilenameFactory( + "Preassessment" + ), + validators=[main.validators.validate_pdf_or_doc], + verbose_name="Upload hier je aanvraag (in .pdf of .doc(x)-formaat)", + ), + ), + migrations.AlterField( + model_name="proposal", + name="relation", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="proposals.Relation", + verbose_name="In welke hoedanigheid ben je betrokken bij dit onderzoek?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="reviewing_committee", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + to="auth.Group", + verbose_name="Door welke comissie dient deze aanvraag te worden beoordeeld?", + ), + ), + migrations.AlterField( + model_name="proposal", + name="status", + field=models.PositiveIntegerField( + choices=[ + (1, "Concept"), + (40, "Opgestuurd ter beoordeling door eindverantwoordelijke"), + (50, "Opgestuurd ter beoordeling door FETC-GW"), + (55, "Aanvraag is beoordeeld door FETC-GW"), + (60, "Aanvraag is beoordeeld door FETC-GW"), + ], + default=1, + ), + ), + migrations.AlterField( + model_name="proposal", + name="supervisor", + field=models.ForeignKey( + blank=True, + help_text="Aan het einde van de procedure kan je deze aanvraag ter\n verificatie naar je eindverantwoordelijke sturen. De\n eindverantwoordelijke zal de aanvraag vervolgens kunnen aanpassen en\n indienen bij de FETC-GW.

      Tip: Type een\n aantal letters van de voornaam, achternaam, of Solis ID van het\n persoon die je toe wilt voegen in de zoekbalk hiernaast.\n Merk op dat het laden even kan duren.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="Eindverantwoordelijke onderzoeker", + ), + ), + migrations.AlterField( + model_name="proposal", + name="title", + field=models.CharField( + help_text="De titel die je hier opgeeft is zichtbaar voor de FETC-GW-leden en, wanneer de aanvraag is goedgekeurd, ook voor alle medewerkers die in het archief van deze portal kijken. De titel mag niet identiek zijn aan een vorige titel van een aanvraag die je hebt ingediend.", + max_length=200, + verbose_name="Wat is de titel van je aanvraag? Deze titel zal worden gebruikt in alle formele correspondentie.", + ), + ), + migrations.AlterField( + model_name="wmo", + name="metc_application", + field=models.BooleanField( + default=False, + verbose_name="Je onderzoek moet beoordeeld worden door een METC, maar dient nog wel bij de FETC-GW te worden geregistreerd. Is dit onderzoek al aangemeld bij een METC?", + ), ), ] diff --git a/proposals/migrations/0035_auto_20220607_1315.py b/proposals/migrations/0035_auto_20220607_1315.py index abde2c4c0..a3b280893 100644 --- a/proposals/migrations/0035_auto_20220607_1315.py +++ b/proposals/migrations/0035_auto_20220607_1315.py @@ -6,21 +6,32 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('proposals', '0034_auto_20211213_1503'), + ("proposals", "0034_auto_20211213_1503"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='studies_similar', - field=models.BooleanField(blank=True, help_text='Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is sprake van in essentie hetzelfde traject. Denk hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van een set verhaaltjes te lezen krijgt, en de andere groep in taak X de andere helft. Of aan interventieonderzoek waarin drie vergelijkbare groepen op hetzelfde moment een verschillende interventie-variant krijgen (specificeer dan wel bij de beschrijving van de interventie welke varianten precies gebruikt worden). Let op: als verschillende groepen deelnemers verschillende soorten taken krijgen, dan zijn dit verschillende trajecten.', null=True, verbose_name='Doorlopen alle deelnemersgroepen in essentie hetzelfde traject?'), + model_name="proposal", + name="studies_similar", + field=models.BooleanField( + blank=True, + help_text="Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is sprake van in essentie hetzelfde traject. Denk hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van een set verhaaltjes te lezen krijgt, en de andere groep in taak X de andere helft. Of aan interventieonderzoek waarin drie vergelijkbare groepen op hetzelfde moment een verschillende interventie-variant krijgen (specificeer dan wel bij de beschrijving van de interventie welke varianten precies gebruikt worden). Let op: als verschillende groepen deelnemers verschillende soorten taken krijgen, dan zijn dit verschillende trajecten.", + null=True, + verbose_name="Doorlopen alle deelnemersgroepen in essentie hetzelfde traject?", + ), ), migrations.AlterField( - model_name='proposal', - name='supervisor', - field=models.ForeignKey(blank=True, help_text='Aan het einde van de procedure kan je deze aanvraag ter\n verificatie naar je eindverantwoordelijke sturen. De\n eindverantwoordelijke zal de aanvraag vervolgens kunnen aanpassen en\n indienen bij de FETC-GW.

      NB: als je je\n eindverantwoordelijke niet kunt vinden met dit veld, moeten zij\n waarschijnlijk eerst één keer inloggen in deze portal. Je kunt nog wel\n verder met de aanvraag, maar vergeet dit veld niet in te vullen voor je de\n aanvraag indient.', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Eindverantwoordelijke onderzoeker'), + model_name="proposal", + name="supervisor", + field=models.ForeignKey( + blank=True, + help_text="Aan het einde van de procedure kan je deze aanvraag ter\n verificatie naar je eindverantwoordelijke sturen. De\n eindverantwoordelijke zal de aanvraag vervolgens kunnen aanpassen en\n indienen bij de FETC-GW.

      NB: als je je\n eindverantwoordelijke niet kunt vinden met dit veld, moeten zij\n waarschijnlijk eerst één keer inloggen in deze portal. Je kunt nog wel\n verder met de aanvraag, maar vergeet dit veld niet in te vullen voor je de\n aanvraag indient.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="Eindverantwoordelijke onderzoeker", + ), ), ] diff --git a/proposals/migrations/0036_proposal_self_assesment.py b/proposals/migrations/0036_proposal_self_assesment.py index 5d1b1eff6..ddfd22a63 100644 --- a/proposals/migrations/0036_proposal_self_assesment.py +++ b/proposals/migrations/0036_proposal_self_assesment.py @@ -4,15 +4,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0035_auto_20220607_1315'), + ("proposals", "0035_auto_20220607_1315"), ] operations = [ migrations.AddField( - model_name='proposal', - name='self_assesment', - field=models.TextField(blank=True, max_length=500, verbose_name='Wat zijn de belangrijkste ethische kwesties in dit onderzoek en beschrijf kort hoe ga je daarmee omgaat.'), + model_name="proposal", + name="self_assesment", + field=models.TextField( + blank=True, + max_length=500, + verbose_name="Wat zijn de belangrijkste ethische kwesties in dit onderzoek en beschrijf kort hoe ga je daarmee omgaat.", + ), ), ] diff --git a/proposals/migrations/0037_rename_self_assesment_proposal_self_assessment.py b/proposals/migrations/0037_rename_self_assesment_proposal_self_assessment.py index 9662a8831..83c48fb41 100644 --- a/proposals/migrations/0037_rename_self_assesment_proposal_self_assessment.py +++ b/proposals/migrations/0037_rename_self_assesment_proposal_self_assessment.py @@ -4,15 +4,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0036_proposal_self_assesment'), + ("proposals", "0036_proposal_self_assesment"), ] operations = [ migrations.RenameField( - model_name='proposal', - old_name='self_assesment', - new_name='self_assessment', + model_name="proposal", + old_name="self_assesment", + new_name="self_assessment", ), ] diff --git a/proposals/migrations/0038_auto_20220830_1357.py b/proposals/migrations/0038_auto_20220830_1357.py index 56a11c130..ed27ee484 100644 --- a/proposals/migrations/0038_auto_20220830_1357.py +++ b/proposals/migrations/0038_auto_20220830_1357.py @@ -4,20 +4,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0037_rename_self_assesment_proposal_self_assessment'), + ("proposals", "0037_rename_self_assesment_proposal_self_assessment"), ] operations = [ migrations.AddField( - model_name='proposal', - name='student_program', - field=models.CharField(blank=True, max_length=200, verbose_name='Wat is je studierichting?'), + model_name="proposal", + name="student_program", + field=models.CharField( + blank=True, max_length=200, verbose_name="Wat is je studierichting?" + ), ), migrations.AlterField( - model_name='proposal', - name='studies_similar', - field=models.BooleanField(blank=True, help_text='Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is sprake van in essentie hetzelfde traject, en voldoet één set documenten voor de informed consent. Denk hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van een set verhaaltjes te lezen krijgt, en de andere groep in taak X de andere helft. Of aan interventieonderzoek waarin drie vergelijkbare groepen op hetzelfde moment een verschillende interventie-variant krijgen (specificeer dan wel bij de beschrijving van de interventie welke varianten precies gebruikt worden). Let op: als verschillende groepen deelnemers verschillende soorten taken krijgen, dan kan dit niet en zijn dit afzonderlijke trajecten.', null=True, verbose_name='Kan voor alle deelnemersgroepen dezelfde informatiebrief en toestemmingsverklaring gebruikt worden?'), + model_name="proposal", + name="studies_similar", + field=models.BooleanField( + blank=True, + help_text="Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is sprake van in essentie hetzelfde traject, en voldoet één set documenten voor de informed consent. Denk hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van een set verhaaltjes te lezen krijgt, en de andere groep in taak X de andere helft. Of aan interventieonderzoek waarin drie vergelijkbare groepen op hetzelfde moment een verschillende interventie-variant krijgen (specificeer dan wel bij de beschrijving van de interventie welke varianten precies gebruikt worden). Let op: als verschillende groepen deelnemers verschillende soorten taken krijgen, dan kan dit niet en zijn dit afzonderlijke trajecten.", + null=True, + verbose_name="Kan voor alle deelnemersgroepen dezelfde informatiebrief en toestemmingsverklaring gebruikt worden?", + ), ), ] diff --git a/proposals/migrations/0039_auto_20220830_1526.py b/proposals/migrations/0039_auto_20220830_1526.py index 2289aabab..0336d73b5 100644 --- a/proposals/migrations/0039_auto_20220830_1526.py +++ b/proposals/migrations/0039_auto_20220830_1526.py @@ -5,29 +5,42 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0038_auto_20220830_1357'), + ("proposals", "0038_auto_20220830_1357"), ] operations = [ migrations.CreateModel( - name='StudentContext', + name="StudentContext", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('order', models.PositiveIntegerField(unique=True)), - ('description', models.CharField(max_length=200)), - ('description_nl', models.CharField(max_length=200, null=True)), - ('description_en', models.CharField(max_length=200, null=True)), - ('needs_details', models.BooleanField(default=False)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("order", models.PositiveIntegerField(unique=True)), + ("description", models.CharField(max_length=200)), + ("description_nl", models.CharField(max_length=200, null=True)), + ("description_en", models.CharField(max_length=200, null=True)), + ("needs_details", models.BooleanField(default=False)), ], options={ - 'ordering': ['order'], + "ordering": ["order"], }, ), migrations.AddField( - model_name='proposal', - name='student_context', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='proposals.studentcontext', verbose_name='In welke context doe je dit onderzoek?'), + model_name="proposal", + name="student_context", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="proposals.studentcontext", + verbose_name="In welke context doe je dit onderzoek?", + ), ), ] diff --git a/proposals/migrations/0040_auto_20220830_1634.py b/proposals/migrations/0040_auto_20220830_1634.py index 21751278b..88e85d5f1 100644 --- a/proposals/migrations/0040_auto_20220830_1634.py +++ b/proposals/migrations/0040_auto_20220830_1634.py @@ -5,20 +5,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0039_auto_20220830_1526'), + ("proposals", "0039_auto_20220830_1526"), ] operations = [ migrations.AddField( - model_name='proposal', - name='student_context_details', - field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Namelijk:'), + model_name="proposal", + name="student_context_details", + field=models.CharField( + blank=True, max_length=200, null=True, verbose_name="Namelijk:" + ), ), migrations.AlterField( - model_name='proposal', - name='relation', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='proposals.relation', verbose_name='In welke hoedanigheid ben je betrokken bij dit onderzoek?'), + model_name="proposal", + name="relation", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="proposals.relation", + verbose_name="In welke hoedanigheid ben je betrokken bij dit onderzoek?", + ), ), ] diff --git a/proposals/migrations/0041_alter_proposal_funding_name.py b/proposals/migrations/0041_alter_proposal_funding_name.py index 0530d177f..869054df2 100644 --- a/proposals/migrations/0041_alter_proposal_funding_name.py +++ b/proposals/migrations/0041_alter_proposal_funding_name.py @@ -4,15 +4,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0040_auto_20220830_1634'), + ("proposals", "0040_auto_20220830_1634"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='funding_name', - field=models.CharField(blank=True, help_text='De titel die je hier opgeeft zal in de formele toestemmingsbrief gebruikt worden.', max_length=200, verbose_name='Wat is de naam van het gefinancierde project en wat is het projectnummer?'), + model_name="proposal", + name="funding_name", + field=models.CharField( + blank=True, + help_text="De titel die je hier opgeeft zal in de formele toestemmingsbrief gebruikt worden.", + max_length=200, + verbose_name="Wat is de naam van het gefinancierde project en wat is het projectnummer?", + ), ), ] diff --git a/proposals/migrations/0042_proposal_student_justification.py b/proposals/migrations/0042_proposal_student_justification.py index d07381a3a..e914c3638 100644 --- a/proposals/migrations/0042_proposal_student_justification.py +++ b/proposals/migrations/0042_proposal_student_justification.py @@ -4,15 +4,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0041_alter_proposal_funding_name'), + ("proposals", "0041_alter_proposal_funding_name"), ] operations = [ migrations.AddField( - model_name='proposal', - name='student_justification', - field=models.TextField(blank=True, max_length=500, verbose_name='Studenten (die mensgebonden onderzoek uitvoeren binnen hun studieprogramma) hoeven in principe geen aanvraag in te dienen bij de FETC-GW. Bespreek met je begeleider of je daadwerkelijk een aanvraag moet indienen. Als dat niet hoeft kun je nu je aanvraag afbreken. Als dat wel moet, geef dan hier aan wat de reden is:'), + model_name="proposal", + name="student_justification", + field=models.TextField( + blank=True, + max_length=500, + verbose_name="Studenten (die mensgebonden onderzoek uitvoeren binnen hun studieprogramma) hoeven in principe geen aanvraag in te dienen bij de FETC-GW. Bespreek met je begeleider of je daadwerkelijk een aanvraag moet indienen. Als dat niet hoeft kun je nu je aanvraag afbreken. Als dat wel moet, geef dan hier aan wat de reden is:", + ), ), ] diff --git a/proposals/migrations/0043_auto_20221025_1057.py b/proposals/migrations/0043_auto_20221025_1057.py index 0da4e7a26..07635ce51 100644 --- a/proposals/migrations/0043_auto_20221025_1057.py +++ b/proposals/migrations/0043_auto_20221025_1057.py @@ -4,20 +4,28 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0042_proposal_student_justification'), + ("proposals", "0042_proposal_student_justification"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='date_start', - field=models.DateField(blank=True, help_text='NB: Voor een aanvraag van een onderzoek dat al gestart is voordat de FETC-GW de aanvraag heeft goedgekeurd kan geen formele goedkeuring meer gegeven worden; de FETC-GW geeft in die gevallen een post-hoc advies.', null=True, verbose_name='Wat is de beoogde startdatum van het onderzoek waarvoor deze aanvraag wordt ingediend?'), + model_name="proposal", + name="date_start", + field=models.DateField( + blank=True, + help_text="NB: Voor een aanvraag van een onderzoek dat al gestart is voordat de FETC-GW de aanvraag heeft goedgekeurd kan geen formele goedkeuring meer gegeven worden; de FETC-GW geeft in die gevallen een post-hoc advies.", + null=True, + verbose_name="Wat is de beoogde startdatum van het onderzoek waarvoor deze aanvraag wordt ingediend?", + ), ), migrations.AlterField( - model_name='proposal', - name='student_justification', - field=models.TextField(blank=True, max_length=500, verbose_name='Studenten (die mensgebonden onderzoek uitvoeren binnen hun studieprogramma) hoeven in principe geen aanvraag in te dienen bij de FETC-GW. Bespreek met je begeleider of je daadwerkelijk een aanvraag moet indienen. Als dat niet hoeft kun je nu je aanvraag afbreken. Als dat wel moet, geef dan hier aan wat de reden is:'), + model_name="proposal", + name="student_justification", + field=models.TextField( + blank=True, + max_length=500, + verbose_name="Studenten (die mensgebonden onderzoek uitvoeren binnen hun studieprogramma) hoeven in principe geen aanvraag in te dienen bij de FETC-GW. Bespreek met je begeleider of je daadwerkelijk een aanvraag moet indienen. Als dat niet hoeft kun je nu je aanvraag afbreken. Als dat wel moet, geef dan hier aan wat de reden is:", + ), ), ] diff --git a/proposals/migrations/0044_auto_20221206_1518.py b/proposals/migrations/0044_auto_20221206_1518.py index 2490a8033..b7e3db739 100644 --- a/proposals/migrations/0044_auto_20221206_1518.py +++ b/proposals/migrations/0044_auto_20221206_1518.py @@ -4,20 +4,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0043_auto_20221025_1057'), + ("proposals", "0043_auto_20221025_1057"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='inform_local_staff', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='

      Je hebt aangegeven dat je gebruik wilt gaan maken van één van de faciliteiten van het ILS, namelijk de database, Zep software en/of het ILS lab. Het lab supportteam van het ILS zou graag op de hoogte willen worden gesteld van aankomende onderzoeken. Daarom vragen wij hier jouw toestemming om delen van deze aanvraag door te sturen naar het lab supportteam.

      Vind je het goed dat de volgende delen uit de aanvraag worden doorgestuurd:

      - Jouw naam en de namen van de andere betrokkenen
      - De eindverantwoordelijke van het onderzoek
      - De titel van het onderzoek
      - De beoogde startdatum
      - Van welke faciliteiten je gebruik wil maken (database, lab, Zep software)'), + model_name="proposal", + name="inform_local_staff", + field=models.BooleanField( + blank=True, + default=None, + null=True, + verbose_name="

      Je hebt aangegeven dat je gebruik wilt gaan maken van één van de faciliteiten van het ILS, namelijk de database, Zep software en/of het ILS lab. Het lab supportteam van het ILS zou graag op de hoogte willen worden gesteld van aankomende onderzoeken. Daarom vragen wij hier jouw toestemming om delen van deze aanvraag door te sturen naar het lab supportteam.

      Vind je het goed dat de volgende delen uit de aanvraag worden doorgestuurd:

      - Jouw naam en de namen van de andere betrokkenen
      - De eindverantwoordelijke van het onderzoek
      - De titel van het onderzoek
      - De beoogde startdatum
      - Van welke faciliteiten je gebruik wil maken (database, lab, Zep software)", + ), ), migrations.AlterField( - model_name='proposal', - name='other_applicants', - field=models.BooleanField(default=False, verbose_name='Zijn er nog andere onderzoekers bij deze aanvraag betrokken die geaffilieerd zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of ILS?'), + model_name="proposal", + name="other_applicants", + field=models.BooleanField( + default=False, + verbose_name="Zijn er nog andere onderzoekers bij deze aanvraag betrokken die geaffilieerd zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of ILS?", + ), ), ] diff --git a/proposals/migrations/0045_alter_proposal_self_assessment.py b/proposals/migrations/0045_alter_proposal_self_assessment.py index 6e6686877..e47d95310 100644 --- a/proposals/migrations/0045_alter_proposal_self_assessment.py +++ b/proposals/migrations/0045_alter_proposal_self_assessment.py @@ -5,15 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0044_auto_20221206_1518'), + ("proposals", "0044_auto_20221206_1518"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='self_assessment', - field=models.TextField(blank=True, validators=[main.validators.MaxWordsValidator(300)], verbose_name='Wat zijn de belangrijkste ethische kwesties in dit onderzoek en beschrijf kort hoe ga je daarmee omgaat. Gebruik maximaal 300 woorden.'), + model_name="proposal", + name="self_assessment", + field=models.TextField( + blank=True, + validators=[main.validators.MaxWordsValidator(300)], + verbose_name="Wat zijn de belangrijkste ethische kwesties in dit onderzoek en beschrijf kort hoe ga je daarmee omgaat. Gebruik maximaal 300 woorden.", + ), ), ] diff --git a/proposals/migrations/0046_auto_20230711_1634.py b/proposals/migrations/0046_auto_20230711_1634.py index d88ad49d1..4a96bce28 100644 --- a/proposals/migrations/0046_auto_20230711_1634.py +++ b/proposals/migrations/0046_auto_20230711_1634.py @@ -5,30 +5,48 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0045_alter_proposal_self_assessment'), + ("proposals", "0045_alter_proposal_self_assessment"), ] operations = [ migrations.AddField( - model_name='proposal', - name='translated_forms', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='Worden de informed consent formulieren nog vertaald naar een andere taal dan Nederlands of Engels?'), + model_name="proposal", + name="translated_forms", + field=models.BooleanField( + blank=True, + default=None, + null=True, + verbose_name="Worden de informed consent formulieren nog vertaald naar een andere taal dan Nederlands of Engels?", + ), ), migrations.AddField( - model_name='proposal', - name='translated_forms_languages', - field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='Andere talen:'), + model_name="proposal", + name="translated_forms_languages", + field=models.CharField( + blank=True, + default=None, + max_length=255, + null=True, + verbose_name="Andere talen:", + ), ), migrations.AlterField( - model_name='proposal', - name='comments', - field=models.TextField(blank=True, validators=[main.validators.MaxWordsValidator(1000)], verbose_name='Ruimte voor eventuele opmerkingen. Gebruik maximaal 1000 woorden.'), + model_name="proposal", + name="comments", + field=models.TextField( + blank=True, + validators=[main.validators.MaxWordsValidator(1000)], + verbose_name="Ruimte voor eventuele opmerkingen. Gebruik maximaal 1000 woorden.", + ), ), migrations.AlterField( - model_name='proposal', - name='self_assessment', - field=models.TextField(blank=True, validators=[main.validators.MaxWordsValidator(1000)], verbose_name='Wat zijn de belangrijkste ethische kwesties in dit onderzoek en beschrijf kort hoe ga je daarmee omgaat. Gebruik maximaal 1000 woorden.'), + model_name="proposal", + name="self_assessment", + field=models.TextField( + blank=True, + validators=[main.validators.MaxWordsValidator(1000)], + verbose_name="Wat zijn de belangrijkste ethische kwesties in dit onderzoek en beschrijf kort hoe ga je daarmee omgaat. Gebruik maximaal 1000 woorden.", + ), ), ] diff --git a/proposals/migrations/0047_auto_20230718_1626.py b/proposals/migrations/0047_auto_20230718_1626.py index 64ea89125..2c44a8986 100644 --- a/proposals/migrations/0047_auto_20230718_1626.py +++ b/proposals/migrations/0047_auto_20230718_1626.py @@ -4,24 +4,32 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0046_auto_20230711_1634'), + ("proposals", "0046_auto_20230711_1634"), ] operations = [ migrations.RemoveField( - model_name='proposal', - name='public', + model_name="proposal", + name="public", ), migrations.AddField( - model_name='proposal', - name='embargo', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='Als de deelnemers van je onderzoek moeten worden misleid, kan je ervoor kiezen je applicatie pas later op te laten nemen in het semi-publieke archief. Wil je dat jouw onderzoek tijdelijk onder embargo wordt geplaatst?'), + model_name="proposal", + name="embargo", + field=models.BooleanField( + blank=True, + default=None, + null=True, + verbose_name="Als de deelnemers van je onderzoek moeten worden misleid, kan je ervoor kiezen je applicatie pas later op te laten nemen in het semi-publieke archief. Wil je dat jouw onderzoek tijdelijk onder embargo wordt geplaatst?", + ), ), migrations.AddField( - model_name='proposal', - name='embargo_end_date', - field=models.DateField(blank=True, null=True, verbose_name='Vanaf welke datum mag je onderzoek wel in het archief worden weergegeven?'), + model_name="proposal", + name="embargo_end_date", + field=models.DateField( + blank=True, + null=True, + verbose_name="Vanaf welke datum mag je onderzoek wel in het archief worden weergegeven?", + ), ), ] diff --git a/proposals/migrations/0048_auto_20231016_1202.py b/proposals/migrations/0048_auto_20231016_1202.py index d05e09b71..bcc8ceb39 100644 --- a/proposals/migrations/0048_auto_20231016_1202.py +++ b/proposals/migrations/0048_auto_20231016_1202.py @@ -5,21 +5,29 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('proposals', '0047_auto_20230718_1626'), + ("proposals", "0047_auto_20230718_1626"), ] operations = [ migrations.AlterField( - model_name='proposal', - name='applicants', - field=models.ManyToManyField(related_name='applicants', to=settings.AUTH_USER_MODEL, verbose_name='Uitvoerenden, inclusief uzelf. Let op! De andere onderzoekers moeten ten minste één keer zijn ingelogd op dit portaal om ze te kunnen selecteren.'), + model_name="proposal", + name="applicants", + field=models.ManyToManyField( + related_name="applicants", + to=settings.AUTH_USER_MODEL, + verbose_name="Uitvoerenden, inclusief uzelf. Let op! De andere onderzoekers moeten ten minste één keer zijn ingelogd op dit portaal om ze te kunnen selecteren.", + ), ), migrations.AlterField( - model_name='proposal', - name='embargo', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='Als de deelnemers van je onderzoek moeten worden misleid, kan je ervoor kiezen je applicatie pas later op te laten nemen in het publieke archief en het archief voor gebruikers van dit portaal. Wil je dat jouw onderzoek tijdelijk onder embargo wordt geplaatst?'), + model_name="proposal", + name="embargo", + field=models.BooleanField( + blank=True, + default=None, + null=True, + verbose_name="Als de deelnemers van je onderzoek moeten worden misleid, kan je ervoor kiezen je applicatie pas later op te laten nemen in het publieke archief en het archief voor gebruikers van dit portaal. Wil je dat jouw onderzoek tijdelijk onder embargo wordt geplaatst?", + ), ), ] diff --git a/proposals/migrations/0049_alter_proposal_supervisor.py b/proposals/migrations/0049_alter_proposal_supervisor.py new file mode 100644 index 000000000..98a2f8d4e --- /dev/null +++ b/proposals/migrations/0049_alter_proposal_supervisor.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.20 on 2023-10-26 09:38 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("proposals", "0048_auto_20231016_1202"), + ] + + operations = [ + migrations.AlterField( + model_name="proposal", + name="supervisor", + field=models.ForeignKey( + blank=True, + help_text="Je aanvraag moet, als je alles hebt ingevuld, via de portal \n naar je promotor of begeleider gestuurd worden. Deze persoon \n is de eindverantwoordelijk onderzoeker, en zal de aanvraag \n vervolgens waar nodig kunnen aanpassen en indienen bij de FETC-GW.\n

      Belangrijk: als je je promotor of \n begeleider niet kunt vinden met dit veld, dan moeten zij \n waarschijnlijk eerst één keer inloggen in deze portal. \n Je kunt nog wel verder met de aanvraag, maar vergeet dit veld \n niet in te vullen voor je de aanvraag indient. Je aanvraag \n zal dan namelijk niet in behandeling kunnen worden genomen.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="Promotor/Begeleider", + ), + ), + ] diff --git a/proposals/migrations/0050_alter_proposal_other_applicants.py b/proposals/migrations/0050_alter_proposal_other_applicants.py new file mode 100644 index 000000000..cd3b0dc56 --- /dev/null +++ b/proposals/migrations/0050_alter_proposal_other_applicants.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.23 on 2023-11-10 14:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("proposals", "0049_alter_proposal_supervisor"), + ] + + operations = [ + migrations.AlterField( + model_name="proposal", + name="other_applicants", + field=models.BooleanField( + default=False, + help_text='Werk je samen met een onderzoeker of organisatie buiten de UU en is je onderzoek niet strikt anoniem? Neem dan contact op met de privacy officer. Er moeten dan wellicht afspraken worden gemaakt over de verwerking van persoonsgegevens.', + verbose_name="Zijn er nog andere onderzoekers bij deze aanvraag betrokken die geaffilieerd zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of ILS?", + ), + ), + ] diff --git a/proposals/migrations/0050_auto_20231116_1413.py b/proposals/migrations/0050_auto_20231116_1413.py new file mode 100644 index 000000000..b5adf91e5 --- /dev/null +++ b/proposals/migrations/0050_auto_20231116_1413.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.20 on 2023-11-16 13:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("proposals", "0049_alter_proposal_supervisor"), + ] + + operations = [ + migrations.RemoveField( + model_name="proposal", + name="avg_understood", + ), + migrations.AddField( + model_name="proposal", + name="privacy_officer", + field=models.BooleanField( + blank=True, + default=None, + null=True, + verbose_name="Ik heb mijn aanvraag en de documenten voor deelnemers besproken met de privacy officer.", + ), + ), + ] diff --git a/proposals/migrations/0051_merge_20231121_1606.py b/proposals/migrations/0051_merge_20231121_1606.py new file mode 100644 index 000000000..a6fa2718d --- /dev/null +++ b/proposals/migrations/0051_merge_20231121_1606.py @@ -0,0 +1,12 @@ +# Generated by Django 3.2.23 on 2023-11-21 15:06 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("proposals", "0050_alter_proposal_other_applicants"), + ("proposals", "0050_auto_20231116_1413"), + ] + + operations = [] diff --git a/proposals/migrations/0052_alter_proposal_studies_similar.py b/proposals/migrations/0052_alter_proposal_studies_similar.py new file mode 100644 index 000000000..a7d366dd7 --- /dev/null +++ b/proposals/migrations/0052_alter_proposal_studies_similar.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.20 on 2023-12-05 10:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("proposals", "0051_merge_20231121_1606"), + ] + + operations = [ + migrations.AlterField( + model_name="proposal", + name="studies_similar", + field=models.BooleanField( + blank=True, + help_text="Daar waar de verschillen klein en qua belasting of risico irrelevant zijn is sprake van in essentie hetzelfde traject, en voldoet één set documenten voor de informed consent. Denk hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van een set verhaaltjes te lezen krijgt, en de andere groep in taak X de andere helft. Of aan interventieonderzoek waarin drie vergelijkbare groepen op hetzelfde moment een verschillende interventie-variant krijgen (specificeer dan wel bij de beschrijving van de interventie welke varianten precies gebruikt worden). Let op: als verschillende groepen deelnemers verschillende soorten taken krijgen, dan kan dit niet en zijn dit afzonderlijke trajecten.", + null=True, + verbose_name="Kan voor alle deelnemers dezelfde informatiebrief en, indien van toepassing, dezelfde toestemmingsverklaring gebruikt worden?", + ), + ), + ] diff --git a/proposals/migrations/0053_auto_20240201_1557.py b/proposals/migrations/0053_auto_20240201_1557.py new file mode 100644 index 000000000..e7f4636c1 --- /dev/null +++ b/proposals/migrations/0053_auto_20240201_1557.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.23 on 2024-02-01 14:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("proposals", "0052_alter_proposal_studies_similar"), + ] + + operations = [ + migrations.AlterField( + model_name="proposal", + name="other_stakeholders", + field=models.BooleanField( + default=False, + verbose_name="Zijn er nog andere onderzoekers bij deze aanvraag betrokken die niet geaffilieerd zijn aan een van de onderzoeksinstituten van de Faculteit Geestwetenschappen van de UU? Zoja, vermeld diens naam en affiliatie.", + ), + ), + migrations.AlterField( + model_name="proposal", + name="stakeholders", + field=models.TextField( + blank=True, verbose_name="Naam en affiliatie van andere betrokkenen" + ), + ), + ] diff --git a/proposals/mixins.py b/proposals/mixins.py index 0a018bfd9..a3c2d0b15 100644 --- a/proposals/mixins.py +++ b/proposals/mixins.py @@ -14,29 +14,29 @@ from .forms import ProposalForm from .utils.proposal_utils import pdf_link_callback + class ProposalMixin(UserFormKwargsMixin): model = Proposal form_class = ProposalForm - success_message = _('Aanvraag %(title)s bewerkt') + success_message = _("Aanvraag %(title)s bewerkt") def get_next_url(self): """If the Proposal has a Wmo model attached, go to update, else, go to create""" proposal = self.object - if hasattr(proposal, 'wmo'): - return reverse('proposals:wmo_update', args=(proposal.pk,)) + if hasattr(proposal, "wmo"): + return reverse("proposals:wmo_update", args=(proposal.pk,)) else: - return reverse('proposals:wmo_create', args=(proposal.pk,)) + return reverse("proposals:wmo_create", args=(proposal.pk,)) class ProposalContextMixin: - def current_user_is_supervisor(self): return self.object.supervisor == self.request.user def get_context_data(self, **kwargs): context = super(ProposalContextMixin, self).get_context_data(**kwargs) - context['is_supervisor'] = self.current_user_is_supervisor() - context['is_practice'] = self.object.is_practice() + context["is_supervisor"] = self.current_user_is_supervisor() + context["is_practice"] = self.object.is_practice() return context @@ -92,8 +92,8 @@ def get_content_disposition(self): cd = "inline" self.content_disposition = '{}; filename="{}"'.format( - cd, - self.get_pdf_filename()) + cd, self.get_pdf_filename() + ) return self.content_disposition @@ -104,8 +104,8 @@ def get_pdf_response(self, context, dest=None, **response_kwargs): if not dest: # Create a Django response object, and specify content_type as pdf # This is the default when using this view - response = HttpResponse(content_type='application/pdf') - response['Content-Disposition'] = self.get_content_disposition() + response = HttpResponse(content_type="application/pdf") + response["Content-Disposition"] = self.get_content_disposition() dest = response # find the template and render it. @@ -130,12 +130,11 @@ def get_pdf_response(self, context, dest=None, **response_kwargs): ) if pisa_status.err: - return HttpResponse('We had some errors
      ' + html + '
      ') + return HttpResponse("We had some errors
      " + html + "
      ") return dest def render_to_response(self, context, **response_kwargs): - - response = HttpResponse(content_type='application/pdf') - response['Content-Disposition'] = self.get_content_disposition() + response = HttpResponse(content_type="application/pdf") + response["Content-Disposition"] = self.get_content_disposition() return self.get_pdf_response(context, **response_kwargs, dest=response) diff --git a/proposals/models.py b/proposals/models.py index 864266d5e..c5de4c55b 100644 --- a/proposals/models.py +++ b/proposals/models.py @@ -11,11 +11,11 @@ from django.utils.functional import lazy from django.utils.safestring import mark_safe + mark_safe_lazy = lazy(mark_safe, str) -from main.models import YES, YES_NO_DOUBT +from main.models import YesNoDoubt from main.validators import MaxWordsValidator, validate_pdf_or_doc -from .validators import AVGUnderstoodValidator from .utils import available_urls, FilenameFactory, OverwriteStorage from datetime import date, timedelta @@ -24,11 +24,11 @@ SUMMARY_MAX_WORDS = 200 SELF_ASSESSMENT_MAX_WORDS = 1000 COMMENTS_MAX_WORDS = 1000 -PROPOSAL_FILENAME = FilenameFactory('Proposal') -PREASSESSMENT_FILENAME = FilenameFactory('Preassessment') -DMP_FILENAME = FilenameFactory('DMP') -METC_DECISION_FILENAME = FilenameFactory('METC_Decision') -PRE_APPROVAL_FILENAME = FilenameFactory('Pre_Approval') +PROPOSAL_FILENAME = FilenameFactory("Proposal") +PREASSESSMENT_FILENAME = FilenameFactory("Preassessment") +DMP_FILENAME = FilenameFactory("DMP") +METC_DECISION_FILENAME = FilenameFactory("METC_Decision") +PRE_APPROVAL_FILENAME = FilenameFactory("Pre_Approval") class Relation(models.Model): @@ -39,18 +39,19 @@ class Relation(models.Model): check_pre_assessment = models.BooleanField(default=True) class Meta: - ordering = ['order'] + ordering = ["order"] def __str__(self): return self.description + class StudentContext(models.Model): order = models.PositiveIntegerField(unique=True) description = models.CharField(max_length=200) needs_details = models.BooleanField(default=False) class Meta: - ordering = ['order'] + ordering = ["order"] def __str__(self): return self.description @@ -64,7 +65,7 @@ class Funding(models.Model): requires_review = models.BooleanField(default=False) class Meta: - ordering = ['order'] + ordering = ["order"] def __str__(self): return self.description @@ -79,83 +80,86 @@ class Institution(models.Model): ) class Meta: - ordering = ['order'] + ordering = ["order"] def __str__(self): return self.description -class ProposalQuerySet(models.QuerySet): +class ProposalQuerySet(models.QuerySet): DECISION_MADE = 55 def archive_pre_filter(self): - return self.filter(status__gte=self.DECISION_MADE, - status_review=True, - in_archive=True, + return self.filter( + status__gte=self.DECISION_MADE, + status_review=True, + in_archive=True, ) def no_embargo(self): - return self.filter(models.Q(embargo_end_date__isnull=True) - | models.Q(embargo_end_date__lt=date.today()) - ) + return self.filter( + models.Q(embargo_end_date__isnull=True) + | models.Q(embargo_end_date__lt=date.today()) + ) def public_archive(self): - two_years_ago = ( - date.today() - - timedelta(weeks=104) - ) - return self.archive_pre_filter().no_embargo().filter( - date_confirmed__gt=two_years_ago, - ).order_by( - "-date_reviewed" + two_years_ago = date.today() - timedelta(weeks=104) + return ( + self.archive_pre_filter() + .no_embargo() + .filter( + date_confirmed__gt=two_years_ago, + ) + .order_by("-date_reviewed") ) def export(self): - return self.archive_pre_filter().order_by( - "-date_reviewed" - ) + return self.archive_pre_filter().order_by("-date_reviewed") def users_only_archive(self, committee): - return self.archive_pre_filter().no_embargo().filter( - is_pre_assessment=False, - reviewing_committee=committee, - ).select_related( - # this optimizes the loading a bit - 'supervisor', 'parent', 'relation', - 'parent__supervisor', 'parent__relation', - ).prefetch_related( - 'applicants', 'review_set', 'parent__review_set', 'study_set', - 'study_set__observation', 'study_set__session_set', - 'study_set__intervention', 'study_set__session_set__task_set' + return ( + self.archive_pre_filter() + .no_embargo() + .filter( + is_pre_assessment=False, + reviewing_committee=committee, + ) + .select_related( + # this optimizes the loading a bit + "supervisor", + "parent", + "relation", + "parent__supervisor", + "parent__relation", + ) + .prefetch_related( + "applicants", + "review_set", + "parent__review_set", + "study_set", + "study_set__observation", + "study_set__session_set", + "study_set__intervention", + "study_set__session_set__task_set", + ) ) class Proposal(models.Model): - objects = ProposalQuerySet.as_manager() - DRAFT = 1 - SUBMITTED_TO_SUPERVISOR = 40 - SUBMITTED = 50 - DECISION_MADE = 55 - WMO_DECISION_MADE = 60 - STATUSES = ( - (DRAFT, _('Concept')), - - (SUBMITTED_TO_SUPERVISOR, - _('Opgestuurd ter beoordeling door eindverantwoordelijke')), - (SUBMITTED, _('Opgestuurd ter beoordeling door FETC-GW')), - - (DECISION_MADE, _('Aanvraag is beoordeeld door FETC-GW')), - (WMO_DECISION_MADE, _('Aanvraag is beoordeeld door FETC-GW')), - ) + class Statuses(models.IntegerChoices): + DRAFT = 1, _("Concept") + SUBMITTED_TO_SUPERVISOR = 40, _( + "Opgestuurd ter beoordeling door eindverantwoordelijke" + ) + SUBMITTED = 50, _("Opgestuurd ter beoordeling door FETC-GW") + DECISION_MADE = 55, _("Aanvraag is beoordeeld door FETC-GW") + WMO_DECISION_MADE = 60, _("Aanvraag is beoordeeld door FETC-GW") - COURSE = 1 - EXPLORATION = 2 - PRACTICE_REASONS = ( - (COURSE, _('in het kader van een cursus')), - (EXPLORATION, _('om de portal te exploreren')), - ) + class PracticeReasons(models.IntegerChoices): + COURSE = 1, _("om de portal te exploreren") + EXPLORATION = 2, _("in het kader van een cursus") # Fields of a proposal reference_number = models.CharField( @@ -165,46 +169,48 @@ class Proposal(models.Model): reviewing_committee = models.ForeignKey( Group, - verbose_name=_( - 'Door welke comissie dient deze aanvraag te worden beoordeeld?' - ), + verbose_name=_("Door welke comissie dient deze aanvraag te worden beoordeeld?"), help_text="", on_delete=models.PROTECT, ) institution = models.ForeignKey( Institution, - verbose_name=_( - 'Aan welk onderzoeksinstituut ben je verbonden?' - ), + verbose_name=_("Aan welk onderzoeksinstituut ben je verbonden?"), on_delete=models.PROTECT, ) date_start = models.DateField( - _('Wat is de beoogde startdatum van het onderzoek waarvoor deze aanvraag wordt ingediend?'), - help_text=_("NB: Voor een aanvraag van een onderzoek dat al gestart is voordat \ + _( + "Wat is de beoogde startdatum van het onderzoek waarvoor deze aanvraag wordt ingediend?" + ), + help_text=_( + "NB: Voor een aanvraag van een onderzoek dat al gestart is voordat \ de FETC-GW de aanvraag heeft goedgekeurd kan geen formele goedkeuring meer \ -gegeven worden; de FETC-GW geeft in die gevallen een post-hoc advies."), +gegeven worden; de FETC-GW geeft in die gevallen een post-hoc advies." + ), blank=True, null=True, ) title = models.CharField( _( - 'Wat is de titel van je aanvraag? Deze titel zal worden gebruikt in ' - 'alle formele correspondentie.' + "Wat is de titel van je aanvraag? Deze titel zal worden gebruikt in " + "alle formele correspondentie." ), max_length=200, unique=False, - help_text=_('De titel die je hier opgeeft is zichtbaar voor de \ + help_text=_( + "De titel die je hier opgeeft is zichtbaar voor de \ FETC-GW-leden en, wanneer de aanvraag is goedgekeurd, ook voor alle \ medewerkers die in het archief van deze portal kijken. De titel mag niet \ -identiek zijn aan een vorige titel van een aanvraag die je hebt ingediend.'), +identiek zijn aan een vorige titel van een aanvraag die je hebt ingediend." + ), ) summary = models.TextField( _( - 'Geef een duidelijke, bondige beschrijving van de onderzoeksvraag of -vragen. Gebruik maximaal 200 woorden.' + "Geef een duidelijke, bondige beschrijving van de onderzoeksvraag of -vragen. Gebruik maximaal 200 woorden." ), validators=[MaxWordsValidator(SUMMARY_MAX_WORDS)], blank=True, @@ -212,33 +218,54 @@ class Proposal(models.Model): other_applicants = models.BooleanField( _( - 'Zijn er nog andere onderzoekers bij deze aanvraag betrokken die geaffilieerd zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of ILS?' + "Zijn er nog andere onderzoekers bij deze aanvraag betrokken die geaffilieerd zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of ILS?" ), default=False, + help_text=mark_safe_lazy( + _( + "Werk je samen met een onderzoeker of " + "organisatie buiten de UU en is je " + "onderzoek niet strikt anoniem? Neem dan " + "contact op met de privacy ' + "officer. " + "Er moeten dan wellicht afspraken worden " + "gemaakt over de verwerking van " + "persoonsgegevens." + ) + ), ) other_stakeholders = models.BooleanField( - mark_safe_lazy(_('Zijn er nog andere onderzoekers bij deze aanvraag betrokken ' - 'die niet geaffilieerd zijn aan een van de ' - 'onderzoeksinstituten van de Faculteit Geestwetenschappen van de ' - 'UU? ')), # Note: form labels with HTML are hard-coded in form Meta classes + mark_safe_lazy( + _( + "Zijn er nog andere onderzoekers bij deze aanvraag betrokken " + "die niet geaffilieerd zijn aan een van de " + "onderzoeksinstituten van de Faculteit Geestwetenschappen van de " + "UU? Zoja, vermeld diens naam en affiliatie." + ) + ), # Note: form labels with HTML are hard-coded in form Meta classes default=False, ) stakeholders = models.TextField( - _('Andere betrokkenen'), + _("Naam en affiliatie van andere betrokkenen"), blank=True, ) translated_forms = models.BooleanField( - mark_safe_lazy(_('Worden de informed consent formulieren nog vertaald naar een andere taal dan Nederlands of Engels?')), + mark_safe_lazy( + _( + "Worden de informed consent formulieren nog vertaald naar een andere taal dan Nederlands of Engels?" + ) + ), default=None, blank=True, null=True, ) translated_forms_languages = models.CharField( - _('Andere talen:'), + _("Andere talen:"), max_length=255, default=None, blank=True, @@ -247,34 +274,35 @@ class Proposal(models.Model): funding = models.ManyToManyField( Funding, - verbose_name=_('Hoe wordt dit onderzoek gefinancierd?'), + verbose_name=_("Hoe wordt dit onderzoek gefinancierd?"), blank=True, ) funding_details = models.CharField( - _('Namelijk'), + _("Namelijk"), max_length=200, blank=True, ) funding_name = models.CharField( - _('Wat is de naam van het gefinancierde project en wat is het projectnummer?'), + _("Wat is de naam van het gefinancierde project en wat is het projectnummer?"), max_length=200, blank=True, help_text=_( - 'De titel die je hier opgeeft zal in de formele toestemmingsbrief ' - 'gebruikt worden.' + "De titel die je hier opgeeft zal in de formele toestemmingsbrief " + "gebruikt worden." ), ) comments = models.TextField( - _('Ruimte voor eventuele opmerkingen. Gebruik maximaal 1000 woorden.'), + _("Ruimte voor eventuele opmerkingen. Gebruik maximaal 1000 woorden."), validators=[MaxWordsValidator(COMMENTS_MAX_WORDS)], blank=True, ) inform_local_staff = models.BooleanField( - _('

      Je hebt aangegeven dat je gebruik wilt gaan maken van één \ + _( + "

      Je hebt aangegeven dat je gebruik wilt gaan maken van één \ van de faciliteiten van het ILS, namelijk de database, Zep software \ en/of het ILS lab. Het lab supportteam van het ILS zou graag op \ de hoogte willen worden gesteld van aankomende onderzoeken. \ @@ -287,27 +315,30 @@ class Proposal(models.Model): - De titel van het onderzoek
      \ - De beoogde startdatum
      \ - Van welke faciliteiten je gebruik wil maken (database, lab, \ -Zep software)'), +Zep software)" + ), default=None, blank=True, - null=True + null=True, ) embargo = models.BooleanField( - _('Als de deelnemers van je onderzoek moeten worden misleid, kan \ + _( + "Als de deelnemers van je onderzoek moeten worden misleid, kan \ je ervoor kiezen je applicatie pas later op te laten nemen in het \ publieke archief en het archief voor gebruikers \ van dit portaal. Wil je dat jouw onderzoek tijdelijk onder \ - embargo wordt geplaatst?'), - default=None, - blank=True, - null=True + embargo wordt geplaatst?" + ), + default=None, + blank=True, + null=True, ) embargo_end_date = models.DateField( - _('Vanaf welke datum mag je onderzoek wel in het archief worden weergegeven?'), + _("Vanaf welke datum mag je onderzoek wel in het archief worden weergegeven?"), blank=True, - null=True + null=True, ) in_archive = models.BooleanField(default=False) @@ -315,7 +346,7 @@ class Proposal(models.Model): is_pre_assessment = models.BooleanField(default=False) pre_assessment_pdf = models.FileField( - _('Upload hier je aanvraag (in .pdf of .doc(x)-formaat)'), + _("Upload hier je aanvraag (in .pdf of .doc(x)-formaat)"), blank=True, upload_to=PREASSESSMENT_FILENAME, validators=[validate_pdf_or_doc], @@ -323,15 +354,16 @@ class Proposal(models.Model): is_pre_approved = models.BooleanField( _( - 'Heb je formele toestemming van een ethische toetsingcommissie, ' - 'uitgezonderd deze FETC-GW commissie?'), + "Heb je formele toestemming van een ethische toetsingcommissie, " + "uitgezonderd deze FETC-GW commissie?" + ), default=None, null=True, blank=True, ) pre_approval_institute = models.CharField( - _('Welk instituut heeft de aanvraag goedgekeurd?'), + _("Welk instituut heeft de aanvraag goedgekeurd?"), max_length=200, blank=True, null=True, @@ -339,34 +371,38 @@ class Proposal(models.Model): pre_approval_pdf = models.FileField( _( - 'Upload hier je formele toestemmingsbrief van dit instituut (in ' - '.pdf of .doc(x)-formaat)'), + "Upload hier je formele toestemmingsbrief van dit instituut (in " + ".pdf of .doc(x)-formaat)" + ), blank=True, upload_to=PRE_APPROVAL_FILENAME, validators=[validate_pdf_or_doc], ) in_course = models.BooleanField( - _('Ik vul de portal in in het kader van een cursus'), + _("Ik vul de portal in in het kader van een cursus"), default=False, ) is_exploration = models.BooleanField( - _('Ik vul de portal in om de portal te exploreren'), + _("Ik vul de portal in om de portal te exploreren"), default=False, ) pdf = models.FileField( - blank = True, + blank=True, upload_to=PROPOSAL_FILENAME, storage=OverwriteStorage(), ) # Fields with respect to Studies studies_similar = models.BooleanField( - _('Kan voor alle deelnemersgroepen dezelfde informatiebrief en \ - toestemmingsverklaring gebruikt worden?'), - help_text=_('Daar waar de verschillen klein en qua belasting of \ + _( + "Kan voor alle deelnemers dezelfde informatiebrief en, indien van \ + toepassing, dezelfde toestemmingsverklaring gebruikt worden?" + ), + help_text=_( + "Daar waar de verschillen klein en qua belasting of \ risico irrelevant zijn is sprake van in essentie hetzelfde traject, en \ voldoet één set documenten voor de informed consent. Denk \ hierbij aan taakonderzoek waarin de ene groep in taak X de ene helft van \ @@ -376,21 +412,22 @@ class Proposal(models.Model): dan wel bij de beschrijving van de interventie welke varianten precies \ gebruikt worden). Let op: als verschillende groepen deelnemers verschillende \ soorten taken krijgen, dan kan dit niet en zijn dit afzonderlijke \ -trajecten.'), +trajecten." + ), blank=True, null=True, ) studies_number = models.PositiveIntegerField( - _('Hoeveel verschillende trajecten zijn er?'), + _("Hoeveel verschillende trajecten zijn er?"), default=1, validators=[MinValueValidator(1), MaxValueValidator(10)], ) # Status status = models.PositiveIntegerField( - choices=STATUSES, - default=DRAFT, + choices=Statuses.choices, + default=Statuses.DRAFT, ) status_review = models.BooleanField( @@ -399,27 +436,30 @@ class Proposal(models.Model): blank=True, ) - avg_understood = models.BooleanField( - _('Ik heb kennis genomen van het bovenstaande en begrijp mijn verantwoordelijkheden ten opzichte van de AVG.'), - default=False, - null=False, - validators=[AVGUnderstoodValidator], + privacy_officer = models.BooleanField( + _( + "Ik heb mijn aanvraag en de documenten voor deelnemers besproken met de privacy officer." + ), + default=None, + null=True, + blank=True, ) dmp_file = models.FileField( - _('Als je een Data Management Plan hebt voor deze aanvraag, ' - 'kan je kiezen om deze hier bij te voegen. Het aanleveren van een ' - 'DMP vergemakkelijkt het toetsingsproces aanzienlijk.'), + _( + "Als je een Data Management Plan hebt voor deze aanvraag, " + "kan je kiezen om deze hier bij te voegen. Het aanleveren van een " + "DMP vergemakkelijkt het toetsingsproces aanzienlijk." + ), blank=True, validators=[validate_pdf_or_doc], upload_to=DMP_FILENAME, storage=OverwriteStorage(), ) - # Confirmation confirmation_comments = models.TextField( - _('Ruimte voor eventuele opmerkingen'), + _("Ruimte voor eventuele opmerkingen"), blank=True, ) @@ -431,46 +471,48 @@ class Proposal(models.Model): date_submitted = models.DateTimeField(null=True) date_reviewed = models.DateTimeField(null=True) date_confirmed = models.DateField( - _('Datum bevestigingsbrief verstuurd'), + _("Datum bevestigingsbrief verstuurd"), null=True, ) has_minor_revision = models.BooleanField( - _('Is er een revisie geweest na het indienen van deze aanvraag?'), + _("Is er een revisie geweest na het indienen van deze aanvraag?"), default=False, ) minor_revision_description = models.TextField( - _('Leg uit'), + _("Leg uit"), null=True, blank=True, ) self_assessment = models.TextField( - _('Wat zijn de belangrijkste ethische kwesties in dit onderzoek en ' - 'beschrijf kort hoe ga je daarmee omgaat. Gebruik maximaal 1000 ' - 'woorden.'), + _( + "Wat zijn de belangrijkste ethische kwesties in dit onderzoek en " + "beschrijf kort hoe ga je daarmee omgaat. Gebruik maximaal 1000 " + "woorden." + ), blank=True, validators=[ - MaxWordsValidator( - SELF_ASSESSMENT_MAX_WORDS - ), - ] + MaxWordsValidator(SELF_ASSESSMENT_MAX_WORDS), + ], ) # References to other models relation = models.ForeignKey( Relation, - verbose_name=_('In welke hoedanigheid ben je betrokken \ -bij dit onderzoek?'), + verbose_name=_( + "In welke hoedanigheid ben je betrokken \ +bij dit onderzoek?" + ), on_delete=models.CASCADE, blank=False, null=True, ) student_program = models.CharField( - verbose_name=_('Wat is je studierichting?'), - max_length = 200, + verbose_name=_("Wat is je studierichting?"), + max_length=200, blank=True, ) @@ -483,70 +525,90 @@ class Proposal(models.Model): ) student_context_details = models.CharField( - verbose_name=_('Namelijk:'), + verbose_name=_("Namelijk:"), max_length=200, blank=True, null=True, ) student_justification = models.TextField( - verbose_name=_('Studenten (die mensgebonden onderzoek uitvoeren binnen hun \ + verbose_name=_( + "Studenten (die mensgebonden onderzoek uitvoeren binnen hun \ studieprogramma) hoeven in principe geen aanvraag in te dienen bij de \ FETC-GW. Bespreek met je begeleider of je daadwerkelijk een aanvraag \ moet indienen. Als dat niet hoeft kun je nu je aanvraag afbreken. \ -Als dat wel moet, geef dan hier aan wat de reden is:'), +Als dat wel moet, geef dan hier aan wat de reden is:" + ), max_length=500, blank=True, ) created_by = models.ForeignKey( settings.AUTH_USER_MODEL, - related_name='created_by', + related_name="created_by", on_delete=models.CASCADE, ) applicants = models.ManyToManyField( settings.AUTH_USER_MODEL, - verbose_name=_('Uitvoerenden, inclusief uzelf. Let op! De andere onderzoekers moeten \ - ten minste één keer zijn ingelogd op dit portaal om ze te kunnen selecteren.'), - related_name='applicants', + verbose_name=_( + "Uitvoerenden, inclusief uzelf. Let op! De andere onderzoekers moeten \ + ten minste één keer zijn ingelogd op dit portaal om ze te kunnen selecteren." + ), + related_name="applicants", ) supervisor = models.ForeignKey( settings.AUTH_USER_MODEL, - verbose_name=_('Eindverantwoordelijke onderzoeker'), + verbose_name=_("Promotor/Begeleider"), blank=True, null=True, - help_text=_('''Aan het einde van de procedure kan je deze aanvraag ter - verificatie naar je eindverantwoordelijke sturen. De - eindverantwoordelijke zal de aanvraag vervolgens kunnen aanpassen en - indienen bij de FETC-GW.

      NB: als je je - eindverantwoordelijke niet kunt vinden met dit veld, moeten zij - waarschijnlijk eerst één keer inloggen in deze portal. Je kunt nog wel - verder met de aanvraag, maar vergeet dit veld niet in te vullen voor je de - aanvraag indient.'''), + help_text=_( + """Je aanvraag moet, als je alles hebt ingevuld, via de portal + naar je promotor of begeleider gestuurd worden. Deze persoon + is de eindverantwoordelijk onderzoeker, en zal de aanvraag + vervolgens waar nodig kunnen aanpassen en indienen bij de FETC-GW. +

      Belangrijk: als je je promotor of + begeleider niet kunt vinden met dit veld, dan moeten zij + waarschijnlijk eerst één keer inloggen in deze portal. + Je kunt nog wel verder met de aanvraag, maar vergeet dit veld + niet in te vullen voor je de aanvraag indient. Je aanvraag + zal dan namelijk niet in behandeling kunnen worden genomen.""" + ), on_delete=models.CASCADE, ) # Copying an existing Proposal parent = models.ForeignKey( - 'self', + "self", null=True, - related_name='children', - verbose_name=_('Te kopiëren aanvraag'), + related_name="children", + verbose_name=_("Te kopiëren aanvraag"), help_text=_( - 'Dit veld toont enkel aanvragen waar je zelf een medeuitvoerende ' - 'bent.'), + "Dit veld toont enkel aanvragen waar je zelf een medeuitvoerende " "bent." + ), on_delete=models.CASCADE, ) is_revision = models.BooleanField( - _( - 'Is deze aanvraag een revisie van of amendement op een ingediende aanvraag?' - ), + _("Is deze aanvraag een revisie van of amendement op een ingediende aanvraag?"), default=False, ) + @property + def is_revisable(self): + """A check to see if a proposal is revisable. For use in Querysets, + keep in mind to also check if the user is one of the applicants + or the supervisor.""" + if ( + not self.is_pre_assessment + and not self.status_review + and self.status == self.Statuses.DECISION_MADE + and not self.children.all() + ): + return True + return False + def is_practice(self): return self.in_course or self.is_exploration @@ -569,7 +631,7 @@ def continue_url(self): def committee_prefixed_refnum(self): """Returns the reference number including the reviewing committee""" parts = (self.reviewing_committee.name, self.reference_number) - return '-'.join(parts) + return "-".join(parts) def available_urls(self): """Returns the available URLs for this Proposal""" @@ -577,13 +639,11 @@ def available_urls(self): def first_study(self): """Returns the first Study in this Proposal, or None if there's none.""" - return self.study_set.order_by('order')[ - 0] if self.study_set.count() else None + return self.study_set.order_by("order")[0] if self.study_set.count() else None def last_study(self): """Returns the last Study in this Proposal, or None if there's none.""" - return self.study_set.order_by('-order')[ - 0] if self.study_set.count() else None + return self.study_set.order_by("-order")[0] if self.study_set.count() else None def current_study(self): """ @@ -605,7 +665,7 @@ def current_session(self): - If no Sessions have yet been created, None is returned. """ current_session = None - for study in self.study_set.all().prefetch_related('session_set'): + for study in self.study_set.all().prefetch_related("session_set"): for session in study.session_set.all(): current_session = session if session.tasks_duration is None: @@ -614,22 +674,22 @@ def current_session(self): def amendment_or_revision(self): if self.is_revision and self.parent: - return _('Amendement') if self.parent.status_review else _('Revisie') + return _("Amendement") if self.parent.status_review else _("Revisie") def type(self): """ Returns the type of a Study: either normal, revision, amendment, preliminary assessment or practice """ - result = _('Normaal') + result = _("Normaal") amendment_or_revision = self.amendment_or_revision() if amendment_or_revision is not None: result = amendment_or_revision elif self.is_pre_assessment: - result = _('Voortoetsing') + result = _("Voortoetsing") elif self.is_practice(): - result = _('Oefening') + result = _("Oefening") elif self.is_pre_approved: - result = _('Extern getoetst') + result = _("Extern getoetst") return result @@ -637,16 +697,16 @@ def supervisor_decision(self): """Returns the Decision of the supervisor for this Proposal (if any and in current stage)""" from reviews.models import Review, Decision - if self.supervisor and self.status == Proposal.SUBMITTED_TO_SUPERVISOR: + if self.supervisor and self.status == Proposal.Statuses.SUBMITTED_TO_SUPERVISOR: decisions = Decision.objects.filter( - review__proposal=self, - review__stage=Review.SUPERVISOR - ).order_by('-pk') + review__proposal=self, review__stage=Review.Stages.SUPERVISOR + ).order_by("-pk") if decisions: return decisions[0] from reviews.utils import start_supervisor_phase + start_supervisor_phase(self) return self.supervisor_decision() @@ -658,7 +718,7 @@ def latest_review(self): def enforce_wmo(self): """Send proposal back to draft phase with WMO enforced.""" - self.status = self.DRAFT + self.status = self.Statuses.DRAFT self.save() self.wmo.enforced_by_commission = True self.wmo.save() @@ -667,11 +727,13 @@ def mark_reviewed(self, continuation, time=None): """Finalize a proposal after a decision has been made.""" if time is None: time = timezone.now() - self.status = self.DECISION_MADE + self.status = self.Statuses.DECISION_MADE # Importing here to prevent circular import from reviews.models import Review + self.status_review = continuation in [ - Review.GO, Review.GO_POST_HOC + Review.Continuations.GO, + Review.Continuations.GO_POST_HOC, ] self.date_reviewed = time self.generate_pdf() @@ -682,11 +744,9 @@ def generate_pdf(self, force_overwrite=False): The currently existing PDF will not be overwritten unless the force_overwrite keyword is True.""" from proposals.utils import generate_pdf + pdf = generate_pdf(self) - if (force_overwrite is True - or not self.use_canonical_pdf - or not self.pdf - ): + if force_overwrite is True or not self.use_canonical_pdf or not self.pdf: self.pdf.save( PROPOSAL_FILENAME(self, "document.pdf"), pdf, @@ -699,16 +759,6 @@ def generate_pdf(self, force_overwrite=False): ) return pdf - @property - def pdf_template_name(self): - """Determine the correct PDf template for this proposal.""" - template_name = 'proposals/proposal_pdf.html' - if self.is_pre_approved: - template_name = 'proposals/proposal_pdf_pre_approved.html' - elif self.is_pre_assessment: - template_name = 'proposals/proposal_pdf_pre_assessment.html' - return template_name - def use_canonical_pdf(self): """Returns False if this proposal should regenerate its PDF on request. Proposals that have already been decided on should @@ -718,44 +768,45 @@ def use_canonical_pdf(self): def __str__(self): if self.is_practice(): - return '{} ({}) (Practice)'.format(self.title, self.created_by) - return '{} ({})'.format(self.title, self.created_by) + return "{} ({}) (Practice)".format(self.title, self.created_by) + return "{} ({})".format(self.title, self.created_by) class Wmo(models.Model): - NO_WMO = 0 - WAITING = 1 - JUDGED = 2 - WMO_STATUSES = ( - (NO_WMO, _('Geen beoordeling door METC noodzakelijk')), - (WAITING, _('In afwachting beslissing METC')), - (JUDGED, _('Beslissing METC geüpload')), - ) + class WMOStatuses(models.IntegerChoices): + NO_WMO = 0, _("Geen beoordeling door METC noodzakelijk") + WAITING = 1, _("In afwachting beslissing METC") + JUDGED = 2, _("Beslissing METC geüpload") metc = models.CharField( - _('Vindt de dataverzameling plaats binnen het UMC Utrecht of \ -andere instelling waar toetsing door een METC verplicht is gesteld?'), + _( + "Vindt de dataverzameling plaats binnen het UMC Utrecht of \ +andere instelling waar toetsing door een METC verplicht is gesteld?" + ), max_length=1, - choices=YES_NO_DOUBT, + choices=YesNoDoubt.choices, blank=True, default=None, ) metc_details = models.TextField( - _('Licht toe'), + _("Licht toe"), blank=True, ) metc_institution = models.CharField( - _('Welke instelling?'), + _("Welke instelling?"), max_length=200, blank=True, ) is_medical = models.CharField( - _('Is de onderzoeksvraag medisch-wetenschappelijk van aard \ -(zoals gedefinieerd door de WMO)?'), - help_text=_('De definitie van medisch-wetenschappelijk onderzoek is: \ + _( + "Is de onderzoeksvraag medisch-wetenschappelijk van aard \ +(zoals gedefinieerd door de WMO)?" + ), + help_text=_( + "De definitie van medisch-wetenschappelijk onderzoek is: \ Medisch-wetenschappelijk onderzoek is onderzoek dat als doel heeft het \ beantwoorden van een vraag op het gebied van ziekte en gezondheid \ (etiologie, pathogenese, verschijnselen/symptomen, diagnose, preventie, \ @@ -763,28 +814,32 @@ class Wmo(models.Model): vergaren en bestuderen van gegevens. Het onderzoek beoogt bij te dragen \ aan medische kennis die ook geldend is voor populaties buiten de directe \ onderzoekspopulatie. (CCMO-notitie, Definitie medisch-wetenschappelijk \ -onderzoek, 2005, ccmo.nl)'), +onderzoek, 2005, ccmo.nl)" + ), max_length=1, - choices=YES_NO_DOUBT, + choices=YesNoDoubt.choices, blank=True, ) - metc_application = models.BooleanField( - _('Je onderzoek moet beoordeeld worden door een METC, maar dient nog \ + _( + "Je onderzoek moet beoordeeld worden door een METC, maar dient nog \ wel bij de FETC-GW te worden geregistreerd. Is dit onderzoek al aangemeld \ -bij een METC?'), +bij een METC?" + ), default=False, ) metc_decision = models.BooleanField( - _('Is de METC al tot een beslissing gekomen?'), + _("Is de METC al tot een beslissing gekomen?"), default=False, ) metc_decision_pdf = models.FileField( - _('Upload hier de beslissing van het METC \ -(in .pdf of .doc(x)-formaat)'), + _( + "Upload hier de beslissing van het METC \ +(in .pdf of .doc(x)-formaat)" + ), blank=True, validators=[validate_pdf_or_doc], upload_to=METC_DECISION_FILENAME, @@ -793,8 +848,8 @@ class Wmo(models.Model): # Status status = models.PositiveIntegerField( - choices=WMO_STATUSES, - default=NO_WMO, + choices=WMOStatuses.choices, + default=WMOStatuses.NO_WMO, ) enforced_by_commission = models.BooleanField(default=False) @@ -812,14 +867,19 @@ def save(self, *args, **kwargs): super(Wmo, self).save(*args, **kwargs) def update_status(self): - if self.metc == YES or self.is_medical == YES or self.enforced_by_commission: + if ( + self.metc == YesNoDoubt.YES + or self.is_medical == YesNoDoubt.YES + or self.enforced_by_commission + ): if self.metc_decision and self.metc_decision_pdf: - self.status = self.JUDGED + self.status = self.WMOStatuses.JUDGED else: - self.status = self.WAITING + self.status = self.WMOStatuses.WAITING else: - self.status = self.NO_WMO + self.status = self.WMOStatuses.NO_WMO def __str__(self): - return _('WMO {title}, status {status}').format( - title=self.proposal.title, status=self.status) + return _("WMO {title}, status {status}").format( + title=self.proposal.title, status=self.status + ) diff --git a/proposals/static/proposals/images/edit-undo.png b/proposals/static/proposals/images/edit-undo.png new file mode 100644 index 000000000..8b0fef9a8 Binary files /dev/null and b/proposals/static/proposals/images/edit-undo.png differ diff --git a/proposals/static/proposals/js/copy.js b/proposals/static/proposals/js/copy.js deleted file mode 100644 index cedf6f664..000000000 --- a/proposals/static/proposals/js/copy.js +++ /dev/null @@ -1,10 +0,0 @@ -$(function () { - $('#id_parent').change(function () { - // Get the displayed value - let chosen = $( "#id_parent option:selected" ).text(); - // Split on the ( and trim to remove the user part - chosen = chosen.split('(')[0].trim(); - // Set it as the new title - $('#id_title').val(chosen); - }) -}); \ No newline at end of file diff --git a/proposals/static/proposals/pdf_font/OpenSans-BoldItalic.ttf b/proposals/static/proposals/pdf_font/OpenSans-BoldItalic.ttf new file mode 100644 index 000000000..eba75d742 Binary files /dev/null and b/proposals/static/proposals/pdf_font/OpenSans-BoldItalic.ttf differ diff --git a/proposals/static/proposals/pdf_font/OpenSans-Italic.ttf b/proposals/static/proposals/pdf_font/OpenSans-Italic.ttf new file mode 100644 index 000000000..b0884744c Binary files /dev/null and b/proposals/static/proposals/pdf_font/OpenSans-Italic.ttf differ diff --git a/proposals/templates/easy_pdf/base.html b/proposals/templates/easy_pdf/base.html index d888592f0..0c1e8350d 100644 --- a/proposals/templates/easy_pdf/base.html +++ b/proposals/templates/easy_pdf/base.html @@ -1,59 +1,60 @@ - - {{ title|default:"" }} - - {% block style_base %} - {% comment %} + + {{ title|default:"" }} + {% block style_base %} + {% comment %} See DEFAULT_CSS in https://github.com/chrisglass/xhtml2pdf/blob/master/xhtml2pdf/default.py for base style. - {% endcomment %} + {% endcomment %} + {% block layout_style %} + + {% endblock %} - @frame footer { - -pdf-frame-content: page-footer; - bottom: 0cm; - margin-left: 1cm; - margin-right: 1cm; - height: 1cm; - } - } - - {%endblock%} - {% block extra_style %}{% endblock %} - {% endblock %} - - -

      - {%block page_header%} - {%endblock%} + {% block extra_style %}{% endblock %} + {% endblock %} - {%block content%} - {%endblock%} -
      + + +
      + {% block page_header %}{% endblock %} - + - - \ No newline at end of file + {% endcomment %} + {% endblock %} + +
      + + diff --git a/proposals/templates/proposals/compare_documents.html b/proposals/templates/proposals/compare_documents.html index 058749a64..146114de3 100644 --- a/proposals/templates/proposals/compare_documents.html +++ b/proposals/templates/proposals/compare_documents.html @@ -1,7 +1,7 @@ {% extends 'base/base.html' %} + {% load static %} {% load i18n %} - {% load describe_documents %} {% block header_title %} @@ -48,17 +48,17 @@

      {% trans 'Vergelijk documenten' %}

      - {% blocktrans %} - Hier kan je twee versies van een document vergelijken. Standaard - geeft hij een gecombineerde versie weer, waarbij tekst - die verwijderd is in het rood is gemarkeerd en nieuwe tekst - in het groen is gemarkeerd. + {% blocktrans trimmed %} + Hier kan je twee versies van een document vergelijken. Standaard + geeft hij een gecombineerde versie weer, waarbij tekst + die verwijderd is in het rood is gemarkeerd en nieuwe tekst + in het groen is gemarkeerd. {% endblocktrans %}

      - {% blocktrans %} - Je kan ook de bestanden naast elkaar bekijken, met dezelfde - markeringen. Klik hiervoor op 'Bekijk apart'. + {% blocktrans trimmed %} + Je kan ook de bestanden naast elkaar bekijken, met dezelfde + markeringen. Klik hiervoor op 'Bekijk apart'. {% endblocktrans %}

      @@ -68,40 +68,30 @@

      - - + +

      -
      -
      -

      - {% trans "Oud" %}: - {{ old_name }} -

      -
      -
      -

      - {% trans "Nieuw" %}: - {{ new_name }} -

      -
      +
      +
      +

      + {% trans "Oud" %}: + {{ old_name }} +

      +
      +
      +

      + {% trans "Nieuw" %}: + {{ new_name }} +

      +
      - -
      - - -
      - +
      + + +
      {% endblock %} diff --git a/proposals/templates/proposals/diff/intervention.html b/proposals/templates/proposals/diff/intervention.html deleted file mode 100644 index c29f558f7..000000000 --- a/proposals/templates/proposals/diff/intervention.html +++ /dev/null @@ -1,32 +0,0 @@ -{% load i18n %} - -{% if study.has_intervention or p_study.has_intervention %} -

      {% trans "Het interventieonderzoek" %}

      - - {% if study.has_intervention and not p_study.has_intervention %} -
      - {% trans "De revisie bevat interventieonderzoek, terwijl de originele aanvraag dat niet bevat." %} -
      - {% elif not study.has_intervention and p_study.has_intervention %} -
      - {% trans "De revisie bevat geen interventieonderzoek, terwijl de originele aanvraag dat wel bevat." %} -
      - {% endif %} - - {% with intervention=study.intervention p_intervention=p_study.intervention %} - {% if not intervention or not p_intervention or intervention.version == p_intervention.version %} - {% include "studies/study_title.html" %} - - {% if intervention.version == 1 %} - {% include "proposals/diff/intervention_v1.html" %} - {% elif intervention.version == 2 %} - {% include "proposals/diff/intervention_v2.html" %} - {% endif %} - - {% else %} -
      - {% trans "De revisie en de originele aanvraag hebben beide een interventieonderzoek, maar deze zijn niet te vergelijken. Dit komt doordat de revisie een andere versie van het formulier gebruikt." %} -
      - {% endif %} - {% endwith %} -{% endif %} \ No newline at end of file diff --git a/proposals/templates/proposals/diff/intervention_v1.html b/proposals/templates/proposals/diff/intervention_v1.html deleted file mode 100644 index 523a83b85..000000000 --- a/proposals/templates/proposals/diff/intervention_v1.html +++ /dev/null @@ -1,103 +0,0 @@ -{% load i18n %} -{% load get_field_name %} -{% load proposal_filters %} - - - - - - - - - - - - - {% if intervention.setting.all|needs_details or p_intervention.setting.all|needs_details %} - - - - - - {% endif %} - {% if study.has_children and intervention.setting.all|needs_details:"needs_supervision" or p_study.has_children and p_intervention.setting.all|needs_details:"needs_supervision" %} - - - - - - {% if not intervention.supervision or not p_intervention.supervision %} - - - - - - {% endif %} - {% endif %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% if intervention.has_controls or p_intervention.has_controls %} - - - - - - {% endif %} -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "interventions" "intervention" "setting" %}{{ p_intervention.setting.all|unordered_list }}{{ intervention.setting.all|unordered_list }}
      {% get_verbose_field_name "interventions" "intervention" "setting_details" %}{{ p_intervention.setting_details }}{{ intervention.setting_details }}
      {% get_verbose_field_name "interventions" "intervention" "supervision" %} - {% if p_intervention %} - {{ p_intervention.supervision|yesno:_("ja,nee,") }} - {% endif %} - - {% if intervention %} - {{ intervention.supervision|yesno:_("ja,nee,") }} - {% endif %} -
      {% get_verbose_field_name "interventions" "intervention" "leader_has_coc" %} - {% if p_intervention %} - {{ p_intervention.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} - - {% if intervention %} - {{ intervention.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} -
      {% get_verbose_field_name "interventions" "intervention" "period" %}{{ p_intervention.period }}{{ intervention.period }}
      {% get_verbose_field_name "interventions" "intervention" "amount_per_week" %}{{ p_intervention.amount_per_week }}{{ intervention.amount_per_week }}
      {% get_verbose_field_name "interventions" "intervention" "duration" %}{{ p_intervention.duration }}{{ intervention.duration }}
      {% get_verbose_field_name "interventions" "intervention" "measurement" %}{{ p_intervention.measurement }}{{ intervention.measurement }}
      {% get_verbose_field_name "interventions" "intervention" "experimenter" %}{{ p_intervention.experimenter }}{{ intervention.experimenter }}
      {% get_verbose_field_name "interventions" "intervention" "description" %}{{ p_intervention.description }}{{ intervention.description }}
      {% get_verbose_field_name "interventions" "intervention" "has_controls" %} - {% if p_intervention %} - {{ p_intervention.has_controls|yesno:_("ja,nee") }} - {% endif %} - - {% if intervention %} - {{ intervention.has_controls|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "interventions" "intervention" "controls_description" %}{{ p_intervention.controls_description }}{{ intervention.controls_description }}
      diff --git a/proposals/templates/proposals/diff/intervention_v2.html b/proposals/templates/proposals/diff/intervention_v2.html deleted file mode 100644 index db9d05ebf..000000000 --- a/proposals/templates/proposals/diff/intervention_v2.html +++ /dev/null @@ -1,125 +0,0 @@ -{% load i18n %} -{% load get_field_name %} -{% load proposal_filters %} - - - - - - - - - - - - - {% if intervention.setting.all|needs_details or p_intervention.setting.all|needs_details %} - - - - - - {% endif %} - {% if study.has_children and intervention.setting.all|needs_details:"needs_supervision" or p_study.has_children and p_intervention.setting.all|needs_details:"needs_supervision" %} - - - - - - {% if not intervention.supervision or not p_intervention.supervision %} - - - - - - {% endif %} - {% endif %} - - - - - - - - - - - {% if p_intervention.multiple_sessions or intervention.multiple_sessions %} - - - - - - {% endif %} - - - - - - - - - - - - - - - - - - - - - - - - - - {% if intervention.has_controls or p_intervention.has_controls %} - - - - - - {% endif %} - {% if intervention.extra_task or p_intervention.extra_task %} - - - - - - {% endif %} -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "interventions" "intervention" "setting" %}{{ p_intervention.setting.all|unordered_list }}{{ intervention.setting.all|unordered_list }}
      {% get_verbose_field_name "interventions" "intervention" "setting_details" %}{{ p_intervention.setting_details }}{{ intervention.setting_details }}
      {% get_verbose_field_name "interventions" "intervention" "supervision" %} - {% if p_intervention %} - {{ p_intervention.supervision|yesno:_("ja,nee,") }} - {% endif %} - - {% if intervention %} - {{ intervention.supervision|yesno:_("ja,nee,") }} - {% endif %} -
      {% get_verbose_field_name "interventions" "intervention" "leader_has_coc" %} - {% if p_intervention %} - {{ p_intervention.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} - - {% if intervention %} - {{ intervention.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} -
      {% get_verbose_field_name "interventions" "intervention" "period" %}{{ p_intervention.period }}{{ intervention.period }}
      {% get_verbose_field_name "interventions" "intervention" "multiple_sessions" %} - {% if p_intervention %} - {{ p_intervention.multiple_sessions|yesno:_("ja,nee,") }} - {% endif %} - - {% if intervention %} - {{ intervention.multiple_sessions|yesno:_("ja,nee,") }} - {% endif %} -
      {% get_verbose_field_name "interventions" "intervention" "session_frequency" %}{{ p_intervention.session_frequency }}{{ intervention.session_frequency }}
      {% get_verbose_field_name "interventions" "intervention" "duration" %}{{ p_intervention.duration }}{{ intervention.duration }}
      {% get_verbose_field_name "interventions" "intervention" "measurement" %}{{ p_intervention.measurement }}{{ intervention.measurement }}
      {% get_verbose_field_name "interventions" "intervention" "experimenter" %}{{ p_intervention.experimenter }}{{ intervention.experimenter }}
      {% get_verbose_field_name "interventions" "intervention" "description" %}{{ p_intervention.description }}{{ intervention.description }}
      {% get_verbose_field_name "interventions" "intervention" "has_controls" %} - {% if p_intervention %} - {{ p_intervention.has_controls|yesno:_("ja,nee") }} - {% endif %} - - {% if intervention %} - {{ intervention.has_controls|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "interventions" "intervention" "controls_description" %}{{ p_intervention.controls_description }}{{ intervention.controls_description }}
      {% get_verbose_field_name "interventions" "intervention" "extra_task" %}{{ p_intervention.extra_task }}{{ intervention.extra_task }}
      diff --git a/proposals/templates/proposals/diff/observation.html b/proposals/templates/proposals/diff/observation.html deleted file mode 100644 index 8292c94ff..000000000 --- a/proposals/templates/proposals/diff/observation.html +++ /dev/null @@ -1,33 +0,0 @@ -{% load i18n %} - -{% if study.has_observation or p_study.has_observation %} -

      {% trans "Het observatieonderzoek" %}

      - - {% if study.has_observation and not p_study.has_observation %} -
      - {% trans "De revisie bevat observatieonderzoek, terwijl de originele aanvraag dat niet bevat." %} -
      - {% elif not study.has_observation and p_study.has_observation %} -
      - {% trans "De revisie bevat geen observatieonderzoek, terwijl de originele aanvraag dat wel bevat." %} -
      - {% endif %} - - {% with observation=study.observation p_observation=p_study.observation %} - {% if not observation or not p_observation or observation.version == p_observation.version %} - {% include "studies/study_title.html" %} - - {% if observation.version == 1 %} - {% include "proposals/diff/observation_v1.html" %} - {% elif observation.version == 2 %} - {% include "proposals/diff/observation_v2.html" %} - {% endif %} - - {% else %} -
      - {% trans "De revisie en de originele aanvraag hebben beide een observatieonderzoek, maar deze zijn niet te vergelijken. Dit komt doordat de revisie een andere versie van het formulier gebruikt." %} -
      - {% endif %} - {% endwith %} - -{% endif %} \ No newline at end of file diff --git a/proposals/templates/proposals/diff/observation_v1.html b/proposals/templates/proposals/diff/observation_v1.html deleted file mode 100644 index 74e3892da..000000000 --- a/proposals/templates/proposals/diff/observation_v1.html +++ /dev/null @@ -1,155 +0,0 @@ -{% load i18n %} -{% load get_field_name %} -{% load proposal_filters %} - - - - - - - - - - - - - - {% if observation.setting.all|needs_details or p_observation.setting.all|needs_details %} - - - - - - {% endif %} - {% if study.has_children and observation.setting.all|needs_details:"needs_supervision" or p_study.has_children and p_observation.setting.all|needs_details:"needs_supervision" %} - - - - - - {% if not observation.supervision or not p_observation.supervision %} - - - - - - {% endif %} - {% endif %} - - - - - - - - - - - - - - - - - - - - - - - - - - {% if observation.is_nonpublic_space or p_observation.is_nonpublic_space %} - - - - - - {% endif %} - - - - - - {% if observation.needs_approval or p_observation.is_nonpublic_space %} - - - - - - - - - - - {% endif %} - - - - - - {% if observation.registrations.all|needs_details or p_observation.registrations.all|needs_details %} - - - - - - {% endif %} -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "observations" "observation" "setting" %}{{ p_observation.setting.all|unordered_list }}{{ observation.setting.all|unordered_list }}
      {% get_verbose_field_name "observations" "observation" "setting_details" %}{{ p_observation.setting_details }}{{ observation.setting_details }}
      {% get_verbose_field_name "observations" "observation" "supervision" %} - {% if p_observation %} - {{ p_observation.supervision|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.supervision|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "leader_has_coc" %} - {% if p_observation %} - {{ p_observation.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} - - {% if observation %} - {{ observation.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "days" %}{{ p_observation.days }}{{ observation.days }}
      {% get_verbose_field_name "observations" "observation" "mean_hours" %}{{ p_observation.mean_hours }}{{ observation.mean_hours }}
      {% get_verbose_field_name "observations" "observation" "is_anonymous" %} - {% if p_observation %} - {{ p_observation.is_anonymous|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.is_anonymous|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "is_in_target_group" %} - {% if p_observation %} - {{ p_observation.is_in_target_group|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.is_in_target_group|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "is_nonpublic_space" %} - {% if p_observation %} - {{ p_observation.is_nonpublic_space|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.is_nonpublic_space|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "has_advanced_consent" %} - {% if p_observation %} - {{ p_observation.has_advanced_consent|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.has_advanced_consent|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "needs_approval" %} - {% if p_observation %} - {{ p_observation.needs_approval|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.needs_approval|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "approval_institution" %}{{ p_observation.approval_institution }}{{ observation.approval_institution }}
      {% get_verbose_field_name "observations" "observation" "approval_document" %}{% trans "Download" %}{% trans "Download" %}
      {% get_verbose_field_name "observations" "observation" "registrations" %}{{ p_observation.registrations.all|unordered_list }}{{ observation.registrations.all|unordered_list }}
      {% get_verbose_field_name "observations" "observation" "registrations_details" %}{{ p_observation.registrations_details }}{{ observation.registrations_details }}
      diff --git a/proposals/templates/proposals/diff/observation_v2.html b/proposals/templates/proposals/diff/observation_v2.html deleted file mode 100644 index 3899ad06a..000000000 --- a/proposals/templates/proposals/diff/observation_v2.html +++ /dev/null @@ -1,174 +0,0 @@ -{% load i18n %} -{% load get_field_name %} -{% load proposal_filters %} - - - - - - - - - - - - - - {% if observation.setting.all|needs_details or p_observation.setting.all|needs_details %} - - - - - - {% endif %} - {% if study.has_children and observation.setting.all|needs_details:"needs_supervision" or p_study.has_children and p_observation.setting.all|needs_details:"needs_supervision" %} - - - - - - {% if not observation.supervision or not p_observation.supervision %} - - - - - - {% endif %} - {% endif %} - - - - - - - - - - - - - - - - - - - - - {% if observation.is_anonymous or p_observation.is_anonymous %} - - - - - - {% endif %} - - - - - - {% if observation.is_in_target_group or p_observation.is_in_target_group %} - - - - - - {% endif %} - - - - - - {% if observation.is_nonpublic_space or p_observation.is_nonpublic_space %} - - - - - - - - - - - {% endif %} - - - - - - {% if observation.needs_approval or p_observation.is_nonpublic_space %} - - - - - - {% endif %} - - - - - - {% if observation.registrations.all|needs_details or p_observation.registrations.all|needs_details %} - - - - - - {% endif %} -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "observations" "observation" "setting" %}{{ p_observation.setting.all|unordered_list }}{{ observation.setting.all|unordered_list }}
      {% get_verbose_field_name "observations" "observation" "setting_details" %}{{ p_observation.setting_details }}{{ observation.setting_details }}
      {% get_verbose_field_name "observations" "observation" "supervision" %} - {% if p_observation %} - {{ p_observation.supervision|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.supervision|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "leader_has_coc" %} - {% if p_observation %} - {{ p_observation.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} - - {% if observation %} - {{ observation.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "details_who" %}{{ p_observation.details_who }}{{ observation.details_who }}
      {% get_verbose_field_name "observations" "observation" "details_why" %}{{ p_observation.details_why }}{{ observation.details_why }}
      {% get_verbose_field_name "observations" "observation" "details_frequency" %}{{ p_observation.details_frequency }}{{ observation.details_frequency }}
      {% get_verbose_field_name "observations" "observation" "is_anonymous" %} - {% if p_observation %} - {{ p_observation.is_anonymous|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.is_anonymous|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "is_anonymous_details" %}{{ p_observation.is_anonymous_details }}{{ observation.is_anonymous_details }}
      {% get_verbose_field_name "observations" "observation" "is_in_target_group" %} - {% if p_observation %} - {{ p_observation.is_in_target_group|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.is_in_target_group|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "is_in_target_group_details" %}{{ p_observation.is_in_target_group_details }}{{ observation.is_in_target_group_details }}
      {% get_verbose_field_name "observations" "observation" "is_nonpublic_space" %} - {% if p_observation %} - {{ p_observation.is_nonpublic_space|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.is_nonpublic_space|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "is_nonpublic_space_details" %}{{ p_observation.is_nonpublic_space_details }}{{ observation.is_nonpublic_space_details }}
      {% get_verbose_field_name "observations" "observation" "has_advanced_consent" %} - {% if p_observation %} - {{ p_observation.has_advanced_consent|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.has_advanced_consent|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "needs_approval" %} - {% if p_observation %} - {{ p_observation.needs_approval|yesno:_("ja,nee") }} - {% endif %} - - {% if observation %} - {{ observation.needs_approval|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "observations" "observation" "approval_institution" %}{{ p_observation.approval_institution }}{{ observation.approval_institution }}
      {% get_verbose_field_name "observations" "observation" "registrations" %}{{ p_observation.registrations.all|unordered_list }}{{ observation.registrations.all|unordered_list }}
      {% get_verbose_field_name "observations" "observation" "registrations_details" %}{{ p_observation.registrations_details }}{{ observation.registrations_details }}
      diff --git a/proposals/templates/proposals/diff/sessions.html b/proposals/templates/proposals/diff/sessions.html deleted file mode 100644 index 84b1ec92c..000000000 --- a/proposals/templates/proposals/diff/sessions.html +++ /dev/null @@ -1,185 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} -{% load diff_tags %} - -{% if study.has_sessions or p_study.has_sessions %} -

      {% trans "Het takenonderzoek en interviews" %}

      - - {% if study.has_sessions and not p_study.has_sessions %} -
      - {% trans "De revisie bevat takenonderzoek, terwijl de originele aanvraag dat niet bevat." %} -
      - {% elif not study.has_sessions and p_study.has_sessions %} -
      - {% trans "De revisie bevat geen takenonderzoek, terwijl de originele aanvraag dat wel bevat." %} -
      - {% endif %} - - {% include "studies/study_title.html" %} - - - - - - - - - - - -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "studies" "study" "sessions_number" %}{{ p_study.sessions_number }}{{ study.sessions_number }}
      - - {% get_zipped_sessions_lists zipped_sessions study p_study %} - - {% for session, p_session in zipped_sessions %} -
      - {% include "tasks/session_title.html" %} -
      - - - - - - - - - - - - {% if session.setting.all|needs_details or p_session.setting.all|needs_details %} - - - - - - {% endif %} - {% if study.has_children and session.setting.all|needs_details:"needs_supervision" or p_study.has_children and p_session.setting.all|needs_details:"needs_supervision" %} - - - - - - {% if not session.supervision or not p_session.supervision %} - - - - - - {% endif %} - {% endif %} - - - - - -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "tasks" "session" "setting" %}{{ p_session.setting.all|unordered_list }}{{ session.setting.all|unordered_list }}
      {% get_verbose_field_name "tasks" "session" "setting_details" %}{{ p_session.setting_details }}{{ session.setting_details }}
      {% get_verbose_field_name "tasks" "session" "supervision" %} - {% if p_session %} - {{ p_session.supervision|yesno:_("ja,nee,") }} - {% endif %} - - {% if session %} - {{ session.supervision|yesno:_("ja,nee,") }} - {% endif %} -
      {% get_verbose_field_name "tasks" "session" "leader_has_coc" %} - {% if p_session %} - {{ p_session.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} - - {% if session %} - {{ session.leader_has_coc|yesno:_("ja,nee,") }} - {% endif %} -
      {% get_verbose_field_name "tasks" "session" "tasks_number" %}{{ p_session.tasks_number }}{{ session.tasks_number }}
      - - {% get_zipped_tasks_lists zipped_tasks session p_session %} - - {% for task, p_task in zipped_tasks %} -
      - {% include "tasks/task_title.html" %} -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - {% if task.registrations.all|needs_details or p_task.registrations.all|needs_details %} - - - - - - {% endif %} - {% if task.registrations.all|needs_details:"needs_kind" or p_task.registrations.all|needs_details:"needs_kind" %} - - - - - - {% if task.registration_kinds.all|needs_details or p_task.registration_kinds.all|needs_details %} - - - - - - {% endif %} - {% endif %} - - - - - - {% if task.feedback or p_task.feedback %} - - - - - - {% endif %} -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "tasks" "task" "name" %}{{ p_task.name }}{{ task.name }}
      {% get_verbose_field_name "tasks" "task" "description" %}{{ p_task.description }}{{ task.description }}
      {% get_verbose_field_name "tasks" "task" "duration" %}{{ p_task.duration }}{{ task.duration }}
      {% get_verbose_field_name "tasks" "task" "registrations" %}{{ p_task.registrations.all|unordered_list }}{{ task.registrations.all|unordered_list }}
      {% get_verbose_field_name "tasks" "task" "registrations_details" %}{{ p_task.registrations_details }}{{ task.registrations_details }}
      {% get_verbose_field_name "tasks" "task" "registration_kinds" %}{{ p_task.registration_kinds.all|unordered_list }}{{ task.registration_kinds.all|unordered_list }}
      {% get_verbose_field_name "tasks" "task" "registration_kinds_details" %}{{ p_task.registration_kinds_details }}{{ task.registration_kinds_details }}
      {% get_verbose_field_name "tasks" "task" "feedback" %} - {% if p_task %} - {{ p_task.feedback|yesno:_("ja,nee") }} - {% endif %} - - {% if task %} - {{ task.feedback|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "tasks" "task" "feedback_details" %}{{ p_task.feedback_details }}{{ task.feedback_details }}
      - {% endfor %} - -

      {% trans "Overzicht van het takenonderzoek" %}

      - - - - - - - - - - - -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "tasks" "session" "tasks_duration" session.net_duration %}{{ p_session.tasks_duration }}{{ session.tasks_duration }}
      - {% endfor %} - -{% endif %} \ No newline at end of file diff --git a/proposals/templates/proposals/diff/study.html b/proposals/templates/proposals/diff/study.html deleted file mode 100644 index f92a321b5..000000000 --- a/proposals/templates/proposals/diff/study.html +++ /dev/null @@ -1,279 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load static %} -{% load uil_filters %} -{% load get_field_name %} -{% load diff_tags %} - -{% for study, p_study in proposal.study_set.all|zip_equalize_lists:p_proposal.study_set.all %} -

      {% trans "De deelnemers" %}

      - {% include "studies/study_title.html" %} - - {% if study and not p_study %} -
      - {% trans "Dit traject is nieuw in de revisie." %} -
      - {% elif not study and p_study %} -
      - {% trans "Dit traject is weggehaald uit de revisie" %} -
      - {% endif %} - - - - - - - - - - - - - {% if study|has_adults or p_study|has_adults %} - - - - - - {% if study.legally_incapable or p_study.legally_incapable %} - - - - - - {% endif %} - {% endif %} - - - - - - - {% if study.has_special_details %} - - - - - - {% if study.special_details.all|medical_traits %} - - - - - - {% if study.traits.all|needs_details %} - - - - - - {% endif %} - {% endif %} - {% endif %} - - {% if study|necessity_required or p_study|necessity_required %} - - - - - - - - - - - {% endif %} - - - - - - {% if study.recruitment.all|needs_details or p_study.recruitment.all|needs_details %} - - - - - - {% endif %} - - - - - - {% if study.compensation.needs_details or p_study.compensation.needs_details %} - - - - - - {% endif %} - - - - - - {% if study.hierarchy or p_study.hierarchy %} - - - - - - {% endif %} -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "studies" "study" "age_groups" %}{{ p_study.age_groups.all|unordered_list }}{{ study.age_groups.all|unordered_list }}
      {% get_verbose_field_name "studies" "study" "legally_incapable" %} - {# You're going to see this a lot, so lemme explain. #} - {# One would think `yesno` has a 'None' option. It does! #} - {# But if you reference an attribute of None, Django will #} - {# insert 'False' instead.... So this if is the only way #} - {# to not display anything if one of the two studies is None #} - {% if p_study %} - {{ p_study.legally_incapable|yesno:_("ja,nee") }} - {% endif %} - - {% if study %} - {{ study.legally_incapable|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "studies" "study" "legally_incapable_details" %}{{ p_study.legally_incapable_details }}{{ study.legally_incapable_details }}
      {% get_verbose_field_name "studies" "study" "has_special_details" %}{{ p_study.has_special_details|yesno:_("ja,nee") }}{{ study.has_special_details|yesno:_("ja,nee") }}
      {% get_verbose_field_name "studies" "study" "special_details" %}{{ p_study.special_details.all|unordered_list }}{{ study.special_details.all|unordered_list }}
      {% get_verbose_field_name "studies" "study" "traits" %}{{ p_study.traits.all|unordered_list }}{{ study.traits.all|unordered_list }}
      {% get_verbose_field_name "studies" "study" "traits_details" %}{{ p_study.traits_details }}{{ study.traits_details }}
      {% get_verbose_field_name "studies" "study" "necessity" %}{{ p_study.get_necessity_display }}{{ study.get_necessity_display }}
      {% get_verbose_field_name "studies" "study" "necessity_reason" %}{{ p_study.necessity_reason }}{{ study.necessity_reason }}
      {% get_verbose_field_name "studies" "study" "recruitment" %}{{ p_study.recruitment.all|unordered_list }}{{ study.recruitment.all|unordered_list }}
      {% get_verbose_field_name "studies" "study" "recruitment_details" %}{{ p_study.recruitment_details }}{{ study.recruitment_details }}
      {% get_verbose_field_name "studies" "study" "compensation" %}{{ p_study.compensation }}{{ study.compensation }}
      {% get_verbose_field_name "studies" "study" "compensation_details" %}{{ p_study.compensation_details }}{{ study.compensation_details }}
      {% get_verbose_field_name "studies" "study" "hierarchy" %}{{ p_study.hierarchy }}{{ study.hierarchy }}
      {% get_verbose_field_name "studies" "study" "hierarchy_details" %}{{ p_study.hierarchy_details }}{{ study.hierarchy_details }}
      - - {% include 'proposals/diff/intervention.html' %} - - {% include 'proposals/diff/observation.html' %} - - {% include 'proposals/diff/sessions.html' %} - -

      {% trans "Overzicht en eigen beoordeling van het gehele onderzoek" %}

      -
      - {% include "studies/study_title.html" %} -
      - - - - - - - {% if study.has_sessions or p_study.has_sessions %} - - - - - - {% if study.deception == 'Y' or study.deception == '?' or p_study.deception == 'Y' or p_study.deception == '?' %} - - - - - - {% endif %} - {% endif %} - - - - - - {% if study.negativity == 'Y' or study.negativity == '?' or p_study.negativity == 'Y' or p_study.negativity == '?' %} - - - - - - {% endif %} - - - - - - {% if study.stressful == 'Y' or study.stressful == '?' or p_study.stressful == 'Y' or p_study.stressful == '?' %} - - - - - - {% endif %} - - - - - - {% if study.risk == 'Y' or study.risk == '?' or p_study.risk == 'Y' or p_study.risk == '?' %} - - - - - - {% endif %} -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "studies" "study" "deception" %}{{ p_study.get_deception_display }}{{ study.get_deception_display }}
      {% get_verbose_field_name "studies" "study" "deception_details" %}{{ p_study.deception_details }}{{ study.deception_details }}
      {% get_verbose_field_name "studies" "study" "negativity" %}{{ p_study.get_negativity_display }}{{ study.get_negativity_display }}
      {% get_verbose_field_name "studies" "study" "negativity_details" %}{{ p_study.negativity_details }}{{ study.negativity_details }}
      {% get_verbose_field_name "studies" "study" "stressful" %}{{ p_study.get_stressful_display }}{{ study.get_stressful_display }}
      {% get_verbose_field_name "studies" "study" "stressful_details" %}{{ p_study.stressful_details }}{{ study.stressful_details }}
      {% get_verbose_field_name "studies" "study" "risk" %}{{ p_study.get_risk_display }}{{ study.get_risk_display }}
      {% get_verbose_field_name "studies" "study" "risk_details" %}{{ p_study.risk_details }}{{ study.risk_details }}
      - -

      {% trans "Informed consent formulieren voor het onderzoek" %}

      - {% include "studies/study_title.html" %} - - {% get_study_documents documents study %} - {% get_study_documents p_documents p_study %} - - - - - - - - - - - - - {% if proposal.translated_forms or p_proposal.translated_forms %} - - - - - - {% endif %} - - - {% if p_documents.informed_consent %} - - {% else %} - - {% endif %} - - {% if documents.informed_consent %} - - {% else %} - - {% endif %} - - - - {% if p_documents.briefing %} - - {% else %} - - {% endif %} - - {% if documents.briefing %} - - {% else %} - - {% endif %} - - - - - - - {% if study.passive_consent or p_study.passive_consent %} - - - - - - {% endif %} -
      {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
      {% get_verbose_field_name "proposals" "proposal" "translated_forms" %}{{ p_proposal.translated_forms|yesno:_("ja,nee") }}{{ proposal.translated_forms|yesno:_("ja,nee") }}
      {% get_verbose_field_name "proposals" "proposal" "translated_forms_languages" %}{{ p_proposal.translated_forms_languages }}{{ proposal.translated_forms_languages }}
      {% get_verbose_field_name "studies" "documents" "informed_consent" %}{% trans "Download" %}{% trans "Download" %}
      {% get_verbose_field_name "studies" "documents" "briefing" %}{% trans "Download" %}{% trans "Download" %}
      {% get_verbose_field_name "studies" "study" "passive_consent" %} - {% if p_study %} - {{ p_study.passive_consent|yesno:_("ja,nee") }} - {% endif %} - - {% if study %} - {{ study.passive_consent|yesno:_("ja,nee") }} - {% endif %} -
      {% get_verbose_field_name "studies" "study" "passive_consent_details" %}{{ p_study.passive_consent_details }}{{ study.passive_consent_details }}
      -{% endfor %} \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/intervention_v1.html b/proposals/templates/proposals/pdf/intervention_v1.html deleted file mode 100644 index c0bc276b5..000000000 --- a/proposals/templates/proposals/pdf/intervention_v1.html +++ /dev/null @@ -1,50 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "setting" %}
      {{ intervention.setting.all|unordered_list }}
      -
      - {% if intervention.setting.all|needs_details %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "setting_details" %}
      {{ intervention.setting_details }}
      -
      - {% endif %} - {% if study.has_children and intervention.setting.all|needs_details:"needs_supervision" %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "supervision" %}
      {{ intervention.supervision|yesno:_("ja,nee") }}
      -
      - {% if not intervention.supervision %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "leader_has_coc" %}
      {{ intervention.leader_has_coc|yesno:_("ja,nee") }}
      -
      - {% endif %} - {% endif %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "period" %}
      {{ intervention.period }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "amount_per_week" %}
      {{ intervention.amount_per_week }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "duration" %}
      {{ intervention.duration }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "measurement" %}
      {{ intervention.measurement }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "experimenter" %}
      {{ intervention.experimenter }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "description" %}
      {{ intervention.description }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "has_controls" %}
      {{ intervention.has_controls|yesno:_("ja,nee") }}
      -
      - {% if intervention.has_controls %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "controls_description" %}
      {{ intervention.controls_description }}
      -
      - {% endif %} -
      \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/intervention_v2.html b/proposals/templates/proposals/pdf/intervention_v2.html deleted file mode 100644 index 52e2b9e31..000000000 --- a/proposals/templates/proposals/pdf/intervention_v2.html +++ /dev/null @@ -1,60 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "setting" %}
      {{ intervention.setting.all|unordered_list }}
      -
      - {% if intervention.setting.all|needs_details %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "setting_details" %}
      {{ intervention.setting_details }}
      -
      - {% endif %} - {% if study.has_children and intervention.setting.all|needs_details:"needs_supervision" %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "supervision" %}
      {{ intervention.supervision|yesno:_("ja,nee") }}
      -
      - {% if not intervention.supervision %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "leader_has_coc" %}
      {{ intervention.leader_has_coc|yesno:_("ja,nee") }}
      -
      - {% endif %} - {% endif %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "period" %}
      {{ intervention.period }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "multiple_sessions" %}
      {{ intervention.multiple_sessions|yesno:_("ja,nee") }}
      -
      - {% if intervention.multiple_sessions %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "session_frequency" %}
      {{ intervention.session_frequency }}
      -
      - {% endif %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "duration" %}
      {{ intervention.duration }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "measurement" %}
      {{ intervention.measurement }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "experimenter" %}
      {{ intervention.experimenter }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "description" %}
      {{ intervention.description }}
      -
      -
      -
      {% get_verbose_field_name "interventions" "intervention" "has_controls" %}
      {{ intervention.has_controls|yesno:_("ja,nee") }}
      -
      - {% if intervention.has_controls %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "controls_description" %}
      {{ intervention.controls_description }}
      -
      - {% endif %} - {% if not intervention.settings_contains_schools %} -
      -
      {% get_verbose_field_name "interventions" "intervention" "extra_task" %}
      {{ intervention.extra_task|yesno:_("ja,nee") }}
      -
      - {% endif %} -
      \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/observation_v1.html b/proposals/templates/proposals/pdf/observation_v1.html deleted file mode 100644 index a42250132..000000000 --- a/proposals/templates/proposals/pdf/observation_v1.html +++ /dev/null @@ -1,65 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - -
      -
      -
      {% get_verbose_field_name "observations" "observation" "setting" %}
      {{ observation.setting.all|unordered_list }}
      -
      - {% if observation.setting.all|needs_details %} -
      -
      {% get_verbose_field_name "observations" "observation" "setting_details" %}
      {{ observation.setting_details }}
      -
      - {% endif %} - {% if study.has_children and observation.setting.all|needs_details:"needs_supervision" %} -
      -
      {% get_verbose_field_name "observations" "observation" "supervision" %}
      {{ observation.supervision|yesno:_("ja,nee") }}
      -
      - {% if not observation.supervision %} -
      -
      {% get_verbose_field_name "observations" "observation" "leader_has_coc" %}
      {{ observation.leader_has_coc|yesno:_("ja,nee") }}
      -
      - {% endif %} - {% endif %} -
      -
      {% get_verbose_field_name "observations" "observation" "days" %}
      {{ observation.days }}
      -
      -
      -
      {% get_verbose_field_name "observations" "observation" "mean_hours" %}
      {{ observation.mean_hours }}
      -
      -
      -
      {% get_verbose_field_name "observations" "observation" "is_anonymous" %}
      {{ observation.is_anonymous|yesno:_("ja,nee") }}
      -
      -
      -
      {% get_verbose_field_name "observations" "observation" "is_in_target_group" %}
      {{ observation.is_in_target_group|yesno:_("ja,nee") }}
      -
      -
      -
      {% get_verbose_field_name "observations" "observation" "is_nonpublic_space" %}
      {{ observation.is_nonpublic_space|yesno:_("ja,nee") }}
      -
      - {% if observation.is_nonpublic_space %} -
      -
      {% get_verbose_field_name "observations" "observation" "has_advanced_consent" %}
      {{ observation.has_advanced_consent|yesno:_("ja,nee") }}
      -
      - {% endif %} -
      -
      {% get_verbose_field_name "observations" "observation" "needs_approval" %}
      {{ observation.needs_approval|yesno:_("ja,nee") }}
      -
      - {% if observation.needs_approval %} -
      -
      {% get_verbose_field_name "observations" "observation" "approval_institution" %}
      {{ observation.approval_institution }}
      -
      - {% if not proposal.is_practice %} -
      -
      {% get_verbose_field_name "observations" "observation" "approval_document" %}
      -
      - {% endif %} - {% endif %} -
      -
      {% get_verbose_field_name "observations" "observation" "registrations" %}
      {{ observation.registrations.all|unordered_list }}
      -
      - {% if observation.registrations.all|needs_details %} -
      -
      {% get_verbose_field_name "observations" "observation" "registrations_details" %}
      {{ observation.registrations_details }}
      -
      - {% endif %} -
      \ No newline at end of file diff --git a/proposals/templates/proposals/pdf/observation_v2.html b/proposals/templates/proposals/pdf/observation_v2.html deleted file mode 100644 index 6b9c5a5f2..000000000 --- a/proposals/templates/proposals/pdf/observation_v2.html +++ /dev/null @@ -1,83 +0,0 @@ -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - -
      -
      -
      {% get_verbose_field_name "observations" "observation" "setting" %}
      {{ observation.setting.all|unordered_list }}
      -
      - {% if observation.setting.all|needs_details %} -
      -
      {% get_verbose_field_name "observations" "observation" "setting_details" %}
      {{ observation.setting_details }}
      -
      - {% endif %} - {% if study.has_children and observation.setting.all|needs_details:"needs_supervision" %} -
      -
      {% get_verbose_field_name "observations" "observation" "supervision" %}
      {{ observation.supervision|yesno:_("ja,nee") }}
      -
      - {% if not observation.supervision %} -
      -
      {% get_verbose_field_name "observations" "observation" "leader_has_coc" %}
      {{ observation.leader_has_coc|yesno:_("ja,nee") }}
      -
      - {% endif %} - {% endif %} -
      -
      {% get_verbose_field_name "observations" "observation" "details_who"|safe %}
      {{ observation.details_who }}
      -
      -
      -
      {% get_verbose_field_name "observations" "observation" "details_why"|safe %}
      {{ observation.details_why }}
      -
      -
      -
      {% get_verbose_field_name "observations" "observation" "details_frequency"|safe %}
      {{ observation.details_frequency }}
      -
      -
      -
      {% get_verbose_field_name "observations" "observation" "is_anonymous" %}
      {{ observation.is_anonymous|yesno:_("ja,nee") }}
      -
      - {% if observation.is_anonymous %} -
      -
      {% get_verbose_field_name "observations" "observation" "is_anonymous_details" %}
      {{ observation.is_anonymous_details }}
      -
      - {% endif %} -
      -
      {% get_verbose_field_name "observations" "observation" "is_in_target_group" %}
      {{ observation.is_in_target_group|yesno:_("ja,nee") }}
      -
      - {% if observation.is_in_target_group %} -
      -
      {% get_verbose_field_name "observations" "observation" "is_in_target_group_details" %}
      {{ observation.is_in_target_group_details }}
      -
      - {% endif %} -
      -
      {% get_verbose_field_name "observations" "observation" "is_nonpublic_space" %}
      {{ observation.is_nonpublic_space|yesno:_("ja,nee") }}
      -
      - {% if observation.is_nonpublic_space %} -
      -
      {% get_verbose_field_name "observations" "observation" "is_nonpublic_space_details" %}
      {{ observation.is_nonpublic_space_details }}
      -
      -
      -
      {% get_verbose_field_name "observations" "observation" "has_advanced_consent" %}
      {{ observation.has_advanced_consent|yesno:_("ja,nee") }}
      -
      - {% if not observation.has_advanced_consent %} -
      -
      {% get_verbose_field_name "observations" "observation" "has_advanced_consent_details" %}
      {{ observation.has_advanced_consent_details }}
      -
      - {% endif %} - {% endif %} - {% if observation.setting.all|needs_details:"is_school" %} -
      -
      {% get_verbose_field_name "observations" "observation" "needs_approval" %}
      {{ observation.needs_approval|yesno:_("ja,nee") }}
      -
      - {% endif %} - {% if observation.needs_approval %} -
      -
      {% get_verbose_field_name "observations" "observation" "approval_institution" %}
      {{ observation.approval_institution }}
      -
      - {% endif %} -
      -
      {% get_verbose_field_name "observations" "observation" "registrations" %}
      {{ observation.registrations.all|unordered_list }}
      -
      - {% if observation.registrations.all|needs_details %} -
      -
      {% get_verbose_field_name "observations" "observation" "registrations_details" %}
      {{ observation.registrations_details }}
      -
      - {% endif %} -
      \ No newline at end of file diff --git a/proposals/templates/proposals/proposal_confirm_delete.html b/proposals/templates/proposals/proposal_confirm_delete.html index a5b86a9cb..43b9246ae 100644 --- a/proposals/templates/proposals/proposal_confirm_delete.html +++ b/proposals/templates/proposals/proposal_confirm_delete.html @@ -15,11 +15,12 @@

      {% trans "Aanvraag verwijderen" %}

      Weet je zeker dat je de aanvraag {{ title }} wilt verwijderen? {% endblocktrans %}

      -
      {% csrf_token %} - - {% trans "Annuleren" %} + + {% csrf_token %} + + {% trans "Annuleren" %}
      -
      x +
      + x {% endblock %} diff --git a/proposals/templates/proposals/proposal_confirmation.html b/proposals/templates/proposals/proposal_confirmation.html index 574c4a7da..7637fd475 100644 --- a/proposals/templates/proposals/proposal_confirmation.html +++ b/proposals/templates/proposals/proposal_confirmation.html @@ -24,16 +24,19 @@

      {% trans "Bevestigingsbrief versturen" %}

      - {% blocktrans with title=review.proposal.title %} + {% blocktrans trimmed with title=review.proposal.title %} Geef hieronder aan wanneer de bevestigingsbrief voor de aanvraag {{ title }} is verstuurd. {% endblocktrans %}

      -
      {% csrf_token %} - {{ form.as_table }}
      - - {% trans "Terug naar de vorige pagina" %} + + {% csrf_token %} + + {{ form.as_table }} +
      + {% trans "Terug naar de vorige pagina" %} +
      diff --git a/proposals/templates/proposals/proposal_copy.html b/proposals/templates/proposals/proposal_copy.html index 5513bb8d9..f4c92e10d 100644 --- a/proposals/templates/proposals/proposal_copy.html +++ b/proposals/templates/proposals/proposal_copy.html @@ -14,12 +14,6 @@ - {{ block.super }} {% endblock %} -{% block html_head %} - {% if is_revision or is_amendment %} - - {% endif %} -{% endblock %} - {% block content %}
      @@ -49,7 +43,7 @@

      {% blocktrans trimmed %} Let op! Er kan maar één revisie tegelijk bestaan. Mocht je jouw aanvraag hier niet zien - als optie om te reviseren, bekijk dan of je aanvraag niet al tussen je concept aanvragen + als optie om te reviseren, bekijk dan of je aanvraag niet al tussen je concept aanvragen staat. {% endblocktrans %}

      @@ -63,16 +57,14 @@

      {% blocktrans trimmed %} Let op! Er kan maar één amendement tegelijk bestaan. Mocht je jouw aanvraag hier niet zien - als optie om te reviseren, bekijk dan of je aanvraag niet al tussen je concept aanvragen + als optie om te reviseren, bekijk dan of je aanvraag niet al tussen je concept aanvragen staat. {% endblocktrans %}

      {% else %} {% url 'proposals:copy_revision' as revision_url %} {% url 'proposals:copy_amendment' as amendment_url %} -

      - {% trans "Je kan hier een aanvraag kopiëren. Alle velden kunnen na het kopiëren aangepast worden." %} -

      +

      {% trans "Je kan hier een aanvraag kopiëren. Alle velden kunnen na het kopiëren aangepast worden." %}

      {% blocktrans trimmed %} Deze pagina is alleen bedoeld voor het geval je een geheel nieuwe aanvraag gaat doen op basis van @@ -92,17 +84,16 @@

      {% endblocktrans %}

      {% endif %} -
      {% csrf_token %} - {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      -

      - {% endblock %} diff --git a/proposals/templates/proposals/proposal_data_management.html b/proposals/templates/proposals/proposal_data_management.html index 65de386ca..0dde106bd 100644 --- a/proposals/templates/proposals/proposal_data_management.html +++ b/proposals/templates/proposals/proposal_data_management.html @@ -13,91 +13,95 @@ {% with nav_items=proposal.available_urls active=5 %} {% include 'base/navigation.html' %} {% endwith %} -

      - {% trans "Datamanagement en Privacy" %} -

      +

      {% trans "Datamanagement en Privacy" %}

      {% blocktrans trimmed %} - De Universiteit Utrecht streeft naar integriteit, duurzaamheid, en transparantie in de omgang met onderzoeksdata, waaronder persoonsgegevens. Sinds de introductie van de AVG zijn er duidelijke regels die onderzoekers moeten volgen met betrekking tot deze data. + De Universiteit Utrecht streeft naar integriteit, duurzaamheid, en transparantie in de omgang met onderzoeksdata, waaronder persoonsgegevens. Sinds de introductie van de AVG zijn er duidelijke regels die onderzoekers moeten volgen met betrekking tot deze data. {% endblocktrans %}

      {% trans "Data Management Plan" %}

        -
      • - {% blocktrans trimmed %} - Een data management plan is sinds 2020 verplicht bij de faculteit geesteswetenschappen, zowel als bij de instanties -NWO en ERC als zij subsidie voor een onderzoek bieden. - {% endblocktrans %} -
      • -
      • - {% blocktrans trimmed %} - De faculteit biedt uitgebreide informatie op het gebied van data management, waaronder ook hoe deze te schrijven.
        Je kunt bij de faculteit ook je DMP laten nakijken door Research Data Management Support of de facultaire datamanager. - {% endblocktrans %} -
      • -
      • - {% blocktrans trimmed %} - Op de website DMP-online vind je na het inloggen met je Solis-ID templates voor een DMP. Dit is waar je de templates die NWO en ERC vereisen kunt terugvinden, aangeboden door de UU. - {% endblocktrans %} -
      • -
      -

      {% trans "Nuttige workshops:" %}

      -

      - {% blocktrans trimmed %} - Als je dit nog niet gedaan hebt, wordt er sterk aangeraden om de volgende workshop te volgen: - {% endblocktrans %} -

      -
        {% blocktrans trimmed %}
      • - de workshop Quick -start to Research Data Management + {% blocktrans trimmed %} + Een data management plan is sinds 2020 verplicht bij de faculteit geesteswetenschappen, zowel als bij de instanties + NWO en ERC als zij subsidie voor een onderzoek bieden. + {% endblocktrans %} +
      • +
      • + {% blocktrans trimmed %} + De faculteit biedt uitgebreide informatie op het gebied van data management, waaronder ook hoe deze te schrijven. +
        + Je kunt bij de faculteit ook je DMP laten nakijken door Research Data Management Support of de facultaire datamanager. + {% endblocktrans %} +
      • +
      • + {% blocktrans trimmed %} + Op de website DMP-online vind je na het inloggen met je Solis-ID templates voor een DMP. Dit is waar je de templates die NWO en ERC vereisen kunt terugvinden, aangeboden door de UU. + {% endblocktrans %}
      • - - {% endblocktrans %}
      +

      {% trans "Nuttige workshops:" %}

      {% blocktrans trimmed %} - Voor advies op het gebied van data management planning kun je contact opnemen met de datamanager GW, Frans de Liagre Böhl via datamanagement.gw@uu.nl. + Als je dit nog niet gedaan hebt, wordt er sterk aangeraden om de volgende workshop te volgen: {% endblocktrans %}

      -

      {% trans "Privacy: AVG en GDPR" %}

      -

      +

      +

      + {% blocktrans trimmed %} + Voor advies op het gebied van data management planning kun je contact opnemen met de datamanager GW, Frans de Liagre Böhl via datamanagement.gw@uu.nl. + {% endblocktrans %} +

      +

      {% trans "Privacy: AVG en GDPR" %}

      +

      + {% blocktrans trimmed %} Wanneer je persoonsgebonden data verzamelt, zorg je er voor dat je je houdt aan de Algemene Verordening Gegevensbescherming, of AVG. Deze wet is de Nederlandse implementatie van het Europese GDPR. - {% endblocktrans %} -

      -
        + {% endblocktrans %} +

        +
        • {% blocktrans trimmed %} - De autoriteit persoonsgegevens heeft uitgebreide informatie in het Nederlands over hoe de AVG dataverzameling beïnvloedt. + De autoriteit persoonsgegevens heeft uitgebreide informatie in het Nederlands over hoe de AVG dataverzameling beïnvloedt. {% endblocktrans %}
        • -
        -

        {% trans "Nuttige workshops:" %}

        -

        - {% blocktrans trimmed %} +

      +

      {% trans "Nuttige workshops:" %}

      +

      + {% blocktrans trimmed %} Als je dit nog niet gedaan hebt, wordt er sterk aangeraden om de volgende workshop te volgen: - {% endblocktrans %} -

      -
        {% blocktrans trimmed %} + {% endblocktrans %} +

        + -

        {% blocktrans trimmed %} - Voor advies op het gebied van privacy en de AVG kun je contact opnemen met de privacy officer van GW via privacy.gw@uu.nl. - {% endblocktrans %} -

        - - -
        {% csrf_token %} - + personal data in research + + {% endblocktrans %} + +

        + {% blocktrans trimmed %} + Voor advies op het gebied van privacy en de AVG kun je contact opnemen met de privacy officer van GW via privacy.gw@uu.nl. + {% endblocktrans %} +

        + + {% csrf_token %} +
        {{ form.as_table }} -
        - {% include "base/form_buttons.html" %} -
        -
      -
      + + {% include "base/form_buttons.html" %} + +

    +
    {% endblock %} diff --git a/proposals/templates/proposals/proposal_diff.html b/proposals/templates/proposals/proposal_diff.html index 3b4f22f93..739fb6d7b 100644 --- a/proposals/templates/proposals/proposal_diff.html +++ b/proposals/templates/proposals/proposal_diff.html @@ -16,7 +16,7 @@ + + {% endblock %} {% block content %} -
    -
    - {% if not create %} - {% with nav_items=proposal.available_urls active=1 %} - {% include 'base/navigation.html' %} - {% endwith %} - {% endif %} - {% if is_practice %} -
    - {% trans "Je bewerkt op het moment een oefenaanvraag. Deze kan niet ter beoordeling door de FETC-GW worden ingediend." %} +
    +
    + {% if not create %} + {% with nav_items=proposal.available_urls active=1 %} + {% include 'base/navigation.html' %} + {% endwith %} + {% endif %} + {% if is_practice %} +
    + {% trans "Je bewerkt op het moment een oefenaanvraag. Deze kan niet ter beoordeling door de FETC-GW worden ingediend." %} +
    + {% endif %} +

    {% trans "Algemene informatie over de aanvraag" %}

    + {% if not create and is_supervisor %} + {% blocktrans trimmed %} + Je past nu een aanvraag aan van een student/PhD kandidaat onder jouw supervisie. Let er op dat je het + formulier + invult alsof jij die student/PhD kandidaat bent. + {% endblocktrans %} +
    +
    + {% endif %} +
    + {% csrf_token %} + + {{ form.as_table }} +
    + {% include "base/form_buttons.html" %} +
    - {% endif %} -

    {% trans "Algemene informatie over de aanvraag" %}

    - {% if not create and is_supervisor %} - {% blocktrans trimmed %} - Je past nu een aanvraag aan van een student/PhD kandidaat onder jouw supervisie. Let er op dat je het - formulier - invult alsof jij die student/PhD kandidaat bent. - {% endblocktrans %} -
    -
    - {% endif %} -
    {% csrf_token %} - {{ form.as_table }}
    - {% include "base/form_buttons.html" %} -
    -
    - - - - - + {% endblock %} diff --git a/proposals/templates/proposals/proposal_form_pre_approved.html b/proposals/templates/proposals/proposal_form_pre_approved.html index 9acfb000d..396a86f6b 100644 --- a/proposals/templates/proposals/proposal_form_pre_approved.html +++ b/proposals/templates/proposals/proposal_form_pre_approved.html @@ -8,8 +8,10 @@ {% endblock %} {% block html_head %} - - + + {% endblock %} {% block content %}

    {% trans "Algemene informatie over de aanvraag" %}

    - {% if not create and is_supervisor %} + {% if not create and is_supervisor %} {% blocktrans trimmed %} Je past nu een aanvraag aan van een student/PhD kandidaat onder je supervisie. Let er op dat je het formulier invult alsof jij die student/PhD kandidaat bent. {% endblocktrans %} -
    -
    +
    +
    {% endif %}
    {% csrf_token %} diff --git a/proposals/templates/proposals/proposal_list.html b/proposals/templates/proposals/proposal_list.html index 2c540360c..0b97279d1 100644 --- a/proposals/templates/proposals/proposal_list.html +++ b/proposals/templates/proposals/proposal_list.html @@ -1,24 +1,18 @@ {% extends "base/base.html" %} -{% load vue_tags %} +{% load vue_tags %} {% load static %} {% load i18n %} {% get_current_language as LANGUAGE_CODE %} - -{% block header_title %} - {{ title }} - {{ block.super }} -{% endblock %} +{% block header_title %}{{ title }} - {{ block.super }}{% endblock %} {% block html_head %} - {# This template loads in either the dev or prod Vue library, depending on settings.DEBUG #} {% include 'uil.vue/vueloader.html' %} {# Load in the base component FancyList #} {% load_vue_component 'FancyList' %} - {% include 'proposals/vue_templates/proposal_list.html' %} - {% endblock %} + {% block content %}
    @@ -37,64 +32,82 @@

    {{ title }}

    {% static "proposals/images/folder_delete.png" as img_hide %} {% static "proposals/images/folder_add.png" as img_add %} {% static 'reviews/images/scale.png' as img_decide %} -

    - {{ body }} -

    + {% static 'proposals/images/edit-undo.png' as img_revise %} +

    {{ body }}

    {% trans "Uitleg" %}

      {% if modifiable %}
    • {% blocktrans trimmed %} - Klik op om naar de volgende stap in + Klik op + + om naar de volgende stap in het proces te gaan. {% endblocktrans %}
    • {% blocktrans trimmed %} - Klik op om de verschillen met de + Klik op + + om de verschillen met de voorgaande versie te zien (alleen beschikbaar voor revisies/amendementen). {% endblocktrans %}
    • {% blocktrans trimmed %} - Klik op om je aanvraag te verwijderen. + Klik op + + om je aanvraag te verwijderen. {% endblocktrans %}
    • {% endif %} {% if submitted %}
    • {% blocktrans trimmed %} - Klik op om een ingediende aanvraag in te zien. + Klik op + + om een ingediende aanvraag in te zien. + {% endblocktrans %} +
    • +
    • + {% blocktrans trimmed %} + Klik op + + om een revisie aan te maken van je aanvraag. {% endblocktrans %}
    • {% endif %} {% if supervised %}
    • {% blocktrans trimmed %} - Klik op om je beslissing door te geven (als eindverantwoordelijke). + Klik op + + om je beslissing door te geven (als eindverantwoordelijke). {% endblocktrans %}
    • {% endif %} {% if is_secretary %}
    • {% blocktrans trimmed %} - Klik op om een ingediende aanvraag te verbergen + Klik op + + om een ingediende aanvraag te verbergen uit het archief. {% endblocktrans %}
    • {% blocktrans trimmed %} - Klik op om een ingediende aanvraag toe te voegen + Klik op + + om een ingediende aanvraag toe te voegen aan het archief. {% endblocktrans %}
    • {% endif %}
    -
    -
    {% endblock %} diff --git a/proposals/templates/proposals/proposal_pdf.html b/proposals/templates/proposals/proposal_pdf.html index 344a6624d..423850555 100644 --- a/proposals/templates/proposals/proposal_pdf.html +++ b/proposals/templates/proposals/proposal_pdf.html @@ -8,11 +8,9 @@ {% block extra_style %} {% endblock %} {% block page_header %} - {% endblock %} -{% block page_foot %} - Page of -{% endblock %} +{% block page_foot %}Page of {% endblock %} {% block content %} -
    -
    -

    - {% blocktrans with reference_number=proposal.reference_number trimmed %} - Referentienummer {{ reference_number }} - {% endblocktrans %} -

    -

    {% trans 'Huidige staat van de aanvraag' %}: {{proposal.get_status_display}} -

    - -

    {% trans 'Indiener' %}

    -
    -
    -
    {% trans 'Naam' %}
    {{ proposal.created_by.get_full_name }}
    -
    -
    -
    {% trans 'E-mail' %}
    {{ proposal.created_by.email }}
    -
    -
    -

    {% trans "Algemene informatie over de aanvraag" %}

    -
    -
    -
    {% get_verbose_field_name "proposals" "proposal" "relation" %}
    {{ proposal.relation }}
    -
    - {% if proposal.relation.needs_supervisor %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "supervisor" %}
    {{ proposal.supervisor.get_full_name }}
    -
    - {% endif %} - {% if proposal.relation.check_in_course %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "student_program" %}
    {{ proposal.student_program }}
    -
    -
    -
    {% get_verbose_field_name "proposals" "proposal" "student_context" %}
    {{ proposal.student_context }}
    -
    - {% if proposal.student_context.needs_details %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "student_context_details" %}
    {{ proposal.student_context_details }}
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "student_justification" %}
    {{ proposal.student_justification }}
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "other_applicants" %}
    {{ proposal.other_applicants|yesno:_("ja,nee") }}
    -
    - {% if proposal.other_applicants %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "applicants" %}
    -
      - {% for applicant in proposal.applicants.all %} -
    • - {{ applicant.get_full_name }} -
    • - {% endfor %} -
    -
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "other_stakeholders" %}
    {{ proposal.other_stakeholders|yesno:_("ja,nee") }}
    -
    - {% if proposal.other_stakeholders %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "stakeholders" %}
    {{ proposal.stakeholders }}
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "date_start" %}
    {{ proposal.date_start|default:_("onbekend") }}
    -
    -
    -
    {% get_verbose_field_name "proposals" "proposal" "title" %}
    {{ proposal.title }}
    -
    -
    -
    {% get_verbose_field_name "proposals" "proposal" "funding" %}
    {{ proposal.funding.all|unordered_list }}
    -
    - {% if proposal.funding.all|needs_details %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "funding_details" %}
    {{ proposal.funding_details }}
    -
    - {% endif %} - {% if proposal.funding.all|needs_details:"needs_name" %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "funding_name" %}
    {{ proposal.funding_name }}
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "self_assessment" %}
    {{ proposal.self_assessment }}
    -
    -
    -

    {% get_verbose_field_name "proposals" "proposal" "summary" %}

    -

    {{ proposal.summary|linebreaks }}

    - - {% with wmo=proposal.wmo %} -

    {% trans "Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" %}

    -
    -
    -
    {% get_verbose_field_name "proposals" "wmo" "metc" %}
    {{ wmo.get_metc_display }}
    -
    - {% if wmo.metc == 'Y' %} -
    -
    {% get_verbose_field_name "proposals" "wmo" "metc_details" %}
    {{ wmo.metc_details }}
    -
    -
    -
    {% get_verbose_field_name "proposals" "wmo" "metc_institution" %}
    {{ wmo.metc_institution }}
    -
    - {% else %} -
    -
    {% get_verbose_field_name "proposals" "wmo" "is_medical" %}
    {{ wmo.get_is_medical_display }}
    -
    - {% endif %} -
    - - {% if wmo.status != wmo.NO_WMO %} -

    {% trans "Aanmelding bij de METC" %}

    -
    -
    -
    {% get_verbose_field_name "proposals" "wmo" "metc_application" %}
    {{ wmo.metc_application|yesno:_("ja,nee") }}
    -
    -
    -
    {% get_verbose_field_name "proposals" "wmo" "metc_decision" %}
    {{ wmo.metc_decision|yesno:_("ja,nee") }}
    -
    - {% if wmo.metc_decision_pdf and not proposal.is_practice %} -
    -
    {% get_verbose_field_name "proposals" "wmo" "metc_decision_pdf" %}
    -
    - {% else %} -
    -
    {% get_verbose_field_name "proposals" "wmo" "metc_decision_pdf" %}
    -
    {% trans "Niet aangeleverd" %}
    -
    - {% endif %} -
    - {% endif %} - {% endwith %} - -

    {% trans "Eén of meerdere trajecten?" %}

    -
    -
    -
    {% get_verbose_field_name "proposals" "proposal" "studies_similar" %}
    {{ proposal.studies_similar|yesno:_("ja,nee") }}
    -
    - {% if not proposal.studies_similar %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "studies_number" %}
    {{ proposal.studies_number }}
    -
    - {% endif %} -
    - - {% if proposal.wmo.status == proposal.wmo.NO_WMO %} - {% for study in proposal.study_set.all %} -

    {% trans "De deelnemers" %}

    - {% include "studies/study_title.html" %} -
    -
    -
    {% get_verbose_field_name "studies" "study" "age_groups" %}
    {{ study.age_groups.all|unordered_list }}
    -
    - {% if study|has_adults %} -
    -
    {% get_verbose_field_name "studies" "study" "legally_incapable" %}
    {{ study.legally_incapable|yesno:_("ja,nee") }}
    -
    - {% if study.legally_incapable %} -
    -
    {% get_verbose_field_name "studies" "study" "legally_incapable_details" %}
    {{ study.legally_incapable_details }}
    -
    - {% endif %} - {% endif %} -
    -
    {% get_verbose_field_name "studies" "study" "has_special_details" %}
    {{ study.has_special_details|yesno:_("ja,nee") }}
    -
    - {% if study.has_special_details %} -
    -
    {% get_verbose_field_name "studies" "study" "special_details" %}
    {{ study.special_details.all|unordered_list }}
    -
    - {% if study.special_details.all|medical_traits %} -
    -
    {% get_verbose_field_name "studies" "study" "traits" %}
    {{ study.traits.all|unordered_list }}
    -
    - {% if study.traits.all|needs_details %} -
    -
    {% get_verbose_field_name "studies" "study" "traits_details" %}
    {{ study.traits_details }}
    -
    - {% endif %} - {% endif %} - {% endif %} - {% if study|necessity_required %} -
    -
    {% get_verbose_field_name "studies" "study" "necessity" %}
    {{ study.get_necessity_display }}
    -
    -
    -
    {% get_verbose_field_name "studies" "study" "necessity_reason" %}
    {{ study.necessity_reason }}
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "studies" "study" "recruitment" %}
    {{ study.recruitment.all|unordered_list }}
    -
    - {% if study.recruitment.all|needs_details %} -
    -
    {% get_verbose_field_name "studies" "study" "recruitment_details" %}
    {{ study.recruitment_details }}
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "studies" "study" "compensation" %}
    {{ study.compensation }}
    -
    - {% if study.compensation.needs_details %} -
    -
    {% get_verbose_field_name "studies" "study" "compensation_details" %}
    {{ study.compensation_details }}
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "studies" "study" "hierarchy" %}
    {{ study.hierarchy|yesno:_("ja,nee") }}
    -
    - {% if study.hierarchy %} -
    -
    {% get_verbose_field_name "studies" "study" "hierarchy_details" %}
    {{ study.hierarchy_details }}
    -
    - {% endif %} -
    - - {% if study.has_intervention %} - {% with intervention=study.intervention %} -

    {% trans "Het interventieonderzoek" %}

    - {% include "studies/study_title.html" %} - {% if intervention.version == 1 %} - {% include 'proposals/pdf/intervention_v1.html' %} - {% elif intervention.version == 2 %} - {% include 'proposals/pdf/intervention_v2.html' %} - {% endif %} - {% endwith %} - {% endif %} - - {% if study.has_observation %} - {% with observation=study.observation %} -

    {% trans "Het observatieonderzoek" %}

    - {% include "studies/study_title.html" %} - {% if observation.version == 1 %} - {% include 'proposals/pdf/observation_v1.html' %} - {% elif observation.version == 2 %} - {% include 'proposals/pdf/observation_v2.html' %} - {% endif %} - {% endwith %} - {% endif %} - - {% if study.has_sessions %} -

    {% trans "Het takenonderzoek en interviews" %}

    - {% include "studies/study_title.html" %} +
    +
    +

    + {% blocktrans with reference_number=proposal.reference_number trimmed %} + Referentienummer {{ reference_number }} + {% endblocktrans %} +

    +

    + {% trans 'Huidige staat van de aanvraag' %}: {{ proposal.get_status_display }} +

    +

    {% trans 'Indiener' %}

    -
    -
    {% get_verbose_field_name "studies" "study" "sessions_number" %}
    {{ study.sessions_number }}
    -
    +
    {% trans 'Naam' %}
    +
    {{ proposal.created_by.get_full_name }}
    +
    {% trans 'E-mail' %}
    +
    {{ proposal.created_by.email }}
    - - {% for session in study.session_set.all %} - {% include "tasks/session_title.html" %} -
    -
    -
    {% get_verbose_field_name "tasks" "session" "setting" %}
    {{ session.setting.all|unordered_list }}
    -
    - {% if session.setting.all|needs_details %} -
    -
    {% get_verbose_field_name "tasks" "session" "setting_details" %}
    {{ session.setting_details }}
    -
    - {% endif %} - {% if study.has_children and session.setting.all|needs_details:"needs_supervision" %} -
    -
    {% get_verbose_field_name "tasks" "session" "supervision" %}
    {{ session.supervision|yesno:_("ja,nee") }}
    -
    - {% if not session.supervision %} -
    -
    {% get_verbose_field_name "tasks" "session" "leader_has_coc" %}
    {{ session.leader_has_coc|yesno:_("ja,nee") }}
    -
    - {% endif %} - {% endif %} -
    -
    {% get_verbose_field_name "tasks" "session" "tasks_number" %}
    {{ session.tasks_number }}
    -
    -
    - {% for task in session.task_set.all %} - {% include "tasks/task_title.html" %} -
    -
    -
    {% get_verbose_field_name "tasks" "task" "name" %}
    {{ task.name }}
    -
    -
    -
    {% get_verbose_field_name "tasks" "task" "duration" %}
    {{ task.duration }}
    -
    -
    -
    {% get_verbose_field_name "tasks" "task" "registrations" %}
    {{ task.registrations.all|unordered_list }}
    -
    - {% if task.registrations.all|needs_details %} -
    -
    {% get_verbose_field_name "tasks" "task" "registrations_details" %}
    {{ task.registrations_details }}
    -
    - {% endif %} - {% if task.registrations.all|needs_details:"needs_kind" %} -
    -
    {% get_verbose_field_name "tasks" "task" "registration_kinds" %}
    {{ task.registration_kinds.all|unordered_list }}
    -
    - {% if task.registration_kinds.all|needs_details %} -
    -
    {% get_verbose_field_name "tasks" "task" "registration_kinds_details" %}
    {{ task.registration_kinds_details }}
    -
    - {% endif %} - {% endif %} -
    -
    {% get_verbose_field_name "tasks" "task" "feedback" %}
    {{ task.feedback|yesno:_("ja,nee") }}
    -
    - {% if task.feedback %} -
    -
    {% get_verbose_field_name "tasks" "task" "feedback_details" %}
    {{ task.feedback_details }}
    -
    - {% endif %} -
    -

    {% get_verbose_field_name "tasks" "task" "description" %}

    -

    {{ task.description|linebreaks }}

    - {% endfor %} - -

    {% trans "Overzicht van het takenonderzoek" %}

    -
    -
    -
    {% get_verbose_field_name "tasks" "session" "tasks_duration" session.net_duration %}
    {{ session.tasks_duration }}
    -
    -
    - + {% for section in sections %} + {% include section %} {% endfor %} - {% endif %} - -

    {% trans "Overzicht en eigen beoordeling van het gehele onderzoek" %}

    - {% include "studies/study_title.html" %} -
    - {% if study.has_sessions %} -
    -
    {% get_verbose_field_name "studies" "study" "deception" %}
    {{ study.get_deception_display }}
    -
    - {% if study.deception == 'Y' or study.deception == '?' %} -
    -
    {% get_verbose_field_name "studies" "study" "deception_details" %}
    {{ study.deception_details }}
    -
    - {% endif %} - {% endif %} -
    -
    {% get_verbose_field_name "studies" "study" "negativity" %}
    {{ study.get_negativity_display }}
    -
    - {% if study.negativity == 'Y' or study.negativity == '?' %} -
    -
    {% get_verbose_field_name "studies" "study" "negativity_details" %}
    {{ study.negativity_details }}
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "studies" "study" "stressful" %}
    {{ study.get_stressful_display }}
    -
    - {% if study.stressful == 'Y' or study.stressful == '?' %} -
    -
    {% get_verbose_field_name "studies" "study" "stressful_details" %}
    {{ study.stressful_details }}
    -
    - {% endif %} -
    -
    {% get_verbose_field_name "studies" "study" "risk" %}
    {{ study.get_risk_display }}
    -
    - {% if study.risk == 'Y' or study.risk == '?' %} -
    -
    {% get_verbose_field_name "studies" "study" "risk_details" %}
    {{ study.risk_details }}
    -
    - {% endif %} -
    - -

    {% trans "Informed consent formulieren" %}

    - {% include "studies/study_title.html" %} - {% get_study_documents study_documents study %} -
    -
    -
    {% get_verbose_field_name "proposals" "proposal" "translated_forms" %}
    {{ proposal.translated_forms|yesno:_("ja,nee") }}
    -
    - {% if proposal.translated_forms %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "translated_forms_languages" %}
    {{ proposal.translated_forms_languages }}
    -
    - {% endif %} - {% if not proposal.is_practice and study_documents.informed_consent %} -
    -
    {% get_verbose_field_name "studies" "documents" "informed_consent" %}
    -
    -
    -
    {% get_verbose_field_name "studies" "documents" "briefing" %}
    -
    - {% endif %} - {% if study.passive_consent is not None %} -
    -
    {% get_verbose_field_name "studies" "study" "passive_consent" %}
    {{ study.passive_consent|yesno:_("ja,nee") }}
    -
    - {% if study.passive_consent %} -
    -
    {% get_verbose_field_name "studies" "study" "passive_consent_details" %}
    {{ study.passive_consent_details }}
    -
    - {% endif %} - {% endif %} - {% if study_documents.director_consent_declaration %} -
    -
    {% get_verbose_field_name "studies" "documents" "director_consent_declaration" %}
    -
    - {% endif %} - {% if study_documents.director_consent_information %} -
    -
    {% get_verbose_field_name "studies" "documents" "director_consent_information" %}
    -
    - {% endif %} - {% if study_documents.parents_information %} -
    -
    {% get_verbose_field_name "studies" "documents" "parents_information" %}
    -
    - {% endif %} -
    - {% endfor %} - - {% if documents.extra %} - {% counter extra_form_counter create 1 %} - {% for extra_documents in documents.extra %} -

    {% trans 'Extra formulieren' %} {% counter extra_form_counter value %}

    - {% counter extra_form_counter increment 1 %} -
    - {% if extra_documents.informed_consent %} -
    -
    {% get_verbose_field_name "studies" "documents" "informed_consent" %}
    -
    - {% endif %} - {% if extra_documents.briefing %} -
    -
    {% get_verbose_field_name "studies" "documents" "briefing" %}
    -
    - {% endif %} -
    - {{ extra_form_counter.increment }} - {% endfor %} - {% endif %} - {% if proposal.dmp_file %} -

    {% trans "Data Management Plan" %}

    -
    -
    -
    - {% get_verbose_field_name "proposals" "proposal" "dmp_file" %} -
    - -
    -
    - {% endif %} -

    {% trans "Aanmelding versturen" %}

    -
    -
    -
    {% get_verbose_field_name "proposals" "proposal" "embargo" %}
    {{ proposal.embargo|yesno:_("ja,nee") }}
    -
    - {%if proposal.embargo %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "embargo_end_date" %}
    {{ proposal.date_start|default:_("onbekend") }}
    -
    - {% endif %}
    -

    {% get_verbose_field_name "proposals" "proposal" "comments" %}

    -

    - {{ proposal.comments }} -

    - {% endif %}
    -
    {% endblock %} diff --git a/proposals/templates/proposals/proposal_pdf_empty.html b/proposals/templates/proposals/proposal_pdf_empty.html deleted file mode 100644 index 688ee11d3..000000000 --- a/proposals/templates/proposals/proposal_pdf_empty.html +++ /dev/null @@ -1,394 +0,0 @@ -{% extends "easy_pdf/base.html" %} - -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - -{% block extra_style %} - -{% endblock %} - -{% block page_header %} - -{% endblock %} - -{% block page_foot %} -Page of -{% endblock %} - -{% block content %} -
    -
    -

    - {% blocktrans %} - Referentienummer referentienummer - {% endblocktrans %} -

    -

    {% trans "Algemene informatie over de aanvraag" %}

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {% get_verbose_field_name "proposals" "proposal" "relation" %}{% show_all "proposals" "relation" %}
    {% get_verbose_field_name "proposals" "proposal" "supervisor" %}
    {% get_verbose_field_name "proposals" "proposal" "student_program" %}{{ proposal.student_program }}
    {% get_verbose_field_name "proposals" "proposal" "other_applicants" %}{% show_yesno %}
    {% get_verbose_field_name "proposals" "proposal" "applicants" %}
    {% get_verbose_field_name "proposals" "proposal" "other_stakeholders" %}{% show_yesno %}
    {% get_verbose_field_name "proposals" "proposal" "stakeholders" %}
    {% get_verbose_field_name "proposals" "proposal" "date_start" %}
    {% get_verbose_field_name "proposals" "proposal" "title" %}
    {% get_verbose_field_name "proposals" "proposal" "summary" %}
    {% get_verbose_field_name "proposals" "proposal" "funding" %}{% show_all "proposals" "funding" %}
    {% get_verbose_field_name "proposals" "proposal" "funding_details" %}
    {% get_verbose_field_name "proposals" "proposal" "funding_name" %}
    - - -

    {% trans "Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" %}

    - - - - - - - - - - - - - -
    {% get_verbose_field_name "proposals" "wmo" "metc" %}{% show_yesnodoubt %}
    {% get_verbose_field_name "proposals" "wmo" "metc_details" %}
    {% get_verbose_field_name "proposals" "wmo" "metc_institution" %}
    {% get_verbose_field_name "proposals" "wmo" "is_medical" %}{% show_yesnodoubt %}
    - -

    {% trans "Aanmelding bij de METC" %}

    - - - - - - - - - - -
    {% get_verbose_field_name "proposals" "wmo" "metc_application" %}{% show_yesno %}
    {% get_verbose_field_name "proposals" "wmo" "metc_decision" %}{% show_yesno %}
    {% get_verbose_field_name "proposals" "wmo" "metc_decision_pdf" %}
    - - -

    {% trans "Eén of meerdere trajecten?" %}

    - - - - - - - -
    {% get_verbose_field_name "proposals" "proposal" "studies_similar" %}{% show_yesno %}
    {% get_verbose_field_name "proposals" "proposal" "studies_number" %}
    - - -

    {% trans "De deelnemers" %} n

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {% get_verbose_field_name "studies" "study" "age_groups" %}{% show_all "studies" "agegroup" %}
    {% get_verbose_field_name "studies" "study" "legally_incapable" %}{% show_yesno %}
    {% get_verbose_field_name "studies" "study" "legally_incapable_details" %}
    {% get_verbose_field_name "studies" "study" "has_traits" %}{% show_yesno %}
    {% get_verbose_field_name "studies" "study" "traits" %}{% show_all "studies" "trait" %}
    {% get_verbose_field_name "studies" "study" "traits_details" %}
    {% get_verbose_field_name "studies" "study" "necessity" %}{% show_yesnodoubt %}
    {% get_verbose_field_name "studies" "study" "necessity_reason" %}
    {% get_verbose_field_name "studies" "study" "recruitment" %}{% show_all "studies" "recruitment" %}
    {% get_verbose_field_name "studies" "study" "recruitment_details" %}
    {% get_verbose_field_name "studies" "study" "compensation" %}{% show_all "studies" "compensation" %}
    {% get_verbose_field_name "studies" "study" "compensation_details" %}
    - - -

    {% trans "Het interventieonderzoek" %}

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% if intervention.has_controls %} - - - - {% endif %} -
    {% get_verbose_field_name "interventions" "intervention" "setting" %}{% show_all "main" "setting" %}
    {% get_verbose_field_name "interventions" "intervention" "setting_details" %}
    {% get_verbose_field_name "interventions" "intervention" "supervision" %}{% show_yesno %}
    {% get_verbose_field_name "interventions" "intervention" "leader_has_coc" %}{% show_yesno %}
    {% get_verbose_field_name "interventions" "intervention" "period" %}
    {% get_verbose_field_name "interventions" "intervention" "amount_per_week" %}
    {% get_verbose_field_name "interventions" "intervention" "duration" %}
    {% get_verbose_field_name "interventions" "intervention" "measurement" %}
    {% get_verbose_field_name "interventions" "intervention" "experimenter" %}
    {% get_verbose_field_name "interventions" "intervention" "description" %}
    {% get_verbose_field_name "interventions" "intervention" "has_controls" %}{% show_yesno %}
    {% get_verbose_field_name "interventions" "intervention" "controls_description" %}
    - - -

    {% trans "Het observatieonderzoek" %}

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {% get_verbose_field_name "observations" "observation" "setting" %}{% show_all "main" "setting" %}
    {% get_verbose_field_name "observations" "observation" "setting_details" %}
    {% get_verbose_field_name "observations" "observation" "supervision" %}{% show_yesno %}
    {% get_verbose_field_name "observations" "observation" "leader_has_coc" %}{% show_yesno %}
    {% get_verbose_field_name "observations" "observation" "days" %}
    {% get_verbose_field_name "observations" "observation" "mean_hours" %}
    {% get_verbose_field_name "observations" "observation" "is_anonymous" %}{% show_yesno %}
    {% get_verbose_field_name "observations" "observation" "is_in_target_group" %}{% show_yesno %}
    {% get_verbose_field_name "observations" "observation" "is_nonpublic_space" %}{% show_yesno %}
    {% get_verbose_field_name "observations" "observation" "has_advanced_consent" %}{% show_yesno %}
    {% get_verbose_field_name "observations" "observation" "needs_approval" %}{% show_yesno %}
    {% get_verbose_field_name "observations" "observation" "approval_institution" %}
    {% get_verbose_field_name "observations" "observation" "approval_document" %}
    {% get_verbose_field_name "observations" "observation" "registrations" %}{% show_all "observations" "registration" %}
    {% get_verbose_field_name "observations" "observation" "registrations_details" %}
    - - -

    {% trans "Het takenonderzoek en interviews" %}

    - - - - -
    {% get_verbose_field_name "studies" "study" "sessions_number" %}
    - -

    {% trans "Sessie" %} n

    - - - - - - - - - - - - - - - - -
    {% get_verbose_field_name "tasks" "session" "setting" %}{% show_all "main" "setting" %}
    {% get_verbose_field_name "tasks" "session" "setting_details" %}
    {% get_verbose_field_name "tasks" "session" "supervision" %}{% show_yesno %}
    {% get_verbose_field_name "tasks" "session" "leader_has_coc" %}{% show_yesno %}
    {% get_verbose_field_name "tasks" "session" "tasks_number" %}
    -

    {% trans "Taak" %} n

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {% get_verbose_field_name "tasks" "task" "name" %}
    {% get_verbose_field_name "tasks" "task" "description" %}
    {% get_verbose_field_name "tasks" "task" "duration" %}
    {% get_verbose_field_name "tasks" "task" "registrations" %}{% show_all "tasks" "registration" %}
    {% get_verbose_field_name "tasks" "task" "registrations_details" %}
    {% get_verbose_field_name "tasks" "task" "registration_kinds" %}{% show_all "tasks" "registrationkind" %}
    {% get_verbose_field_name "tasks" "task" "registration_kinds_details" %}
    {% get_verbose_field_name "tasks" "task" "feedback" %}{% show_yesno %}
    {% get_verbose_field_name "tasks" "task" "feedback_details" %}
    - -

    {% trans "Overzicht van het takenonderzoek" %}

    - - - - -
    {% get_verbose_field_name "tasks" "session" "tasks_duration" 0 %}
    - - -

    {% trans "Overzicht en eigen beoordeling van het gehele onderzoek" %}

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    {% get_verbose_field_name "studies" "study" "deception" %}{% show_yesnodoubt %}
    {% get_verbose_field_name "studies" "study" "deception_details" %}
    {% get_verbose_field_name "studies" "study" "negativity" %}{% show_yesnodoubt %}
    {% get_verbose_field_name "studies" "study" "negativity_details" %}
    {% get_verbose_field_name "studies" "study" "stressful" %}{% show_yesnodoubt %}
    {% get_verbose_field_name "studies" "study" "stressful_details" %}
    {% get_verbose_field_name "studies" "study" "risk" %}{% show_yesnodoubt %}
    {% get_verbose_field_name "studies" "study" "risk_details" %}
    - - -

    {% trans "Informed consent formulieren voor het onderzoek" %}

    - - - - - - - - - - - - - -
    {% get_verbose_field_name "studies" "documents" "informed_consent" %}
    {% get_verbose_field_name "studies" "documents" "briefing" %}
    {% get_verbose_field_name "studies" "study" "passive_consent" %}{% show_yesno %}
    {% get_verbose_field_name "studies" "study" "passive_consent_details" %}
    - - -

    {% trans "Aanmelding versturen" %}

    -

    {% get_verbose_field_name "proposals" "proposal" "comments" %}

    - -
    -
    -{% endblock %} diff --git a/proposals/templates/proposals/proposal_pdf_pre_approved.html b/proposals/templates/proposals/proposal_pdf_pre_approved.html deleted file mode 100644 index 0b39ff35e..000000000 --- a/proposals/templates/proposals/proposal_pdf_pre_approved.html +++ /dev/null @@ -1,157 +0,0 @@ -{% extends "easy_pdf/base.html" %} - -{% load i18n %} -{% load proposal_filters %} -{% load get_field_name %} - -{% block extra_style %} - -{% endblock %} - -{% block page_header %} - -{% endblock %} - -{% block page_foot %} -Page of -{% endblock %} - -{% block content %} -
    -
    -

    - {% blocktrans with reference_number=proposal.reference_number %} - Referentienummer {{ reference_number }} - {% endblocktrans %} -

    -

    {% trans 'Indiener' %}

    - - - - - - - -
    {% trans 'Naam' %}{{ proposal.created_by.get_full_name }}
    {% trans 'E-mail' %}{{ proposal.created_by.email }}
    -

    {% trans "Algemene informatie over de aanvraag" %}

    - - - - - - - - - - {% if proposal.relation.needs_supervisor %} - - - - - {% endif %} - {% if proposal.relation.check_in_course %} - - - - {% endif %} - - - - - {% if proposal.other_applicants %} - - - - {% endif %} - - - - - {% if proposal.other_stakeholders %} - - - - - {% endif %} - - - - - - - - - - - - {% if proposal.funding.all|needs_details %} - - - - {% endif %} - {% if proposal.funding.all|needs_details:"needs_name" %} - - - - {% endif %} - - - - - - - -
    {% get_verbose_field_name "proposals" "proposal" "is_pre_approved" %}{{ proposal.is_pre_approved }}
    {% get_verbose_field_name "proposals" "proposal" "relation" %}{{ proposal.relation }}
    {% get_verbose_field_name "proposals" "proposal" "supervisor" %}{{ proposal.supervisor.get_full_name }}
    {% get_verbose_field_name "proposals" "proposal" "student_program" %}{{ proposal.student_program }}
    {% get_verbose_field_name "proposals" "proposal" "other_applicants" %}{{ proposal.other_applicants|yesno:_("ja,nee") }}
    {% get_verbose_field_name "proposals" "proposal" "applicants" %} -
      - {% for applicant in proposal.applicants.all %} -
    • - {{ applicant.get_full_name }} -
    • - {% endfor %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "other_stakeholders" %}{{ proposal.other_stakeholders|yesno:_("ja,nee") }}
    {% get_verbose_field_name "proposals" "proposal" "stakeholders" %}{{ proposal.stakeholders }}
    {% get_verbose_field_name "proposals" "proposal" "date_start" %}{{ proposal.date_start|default:_("onbekend") }}
    {% get_verbose_field_name "proposals" "proposal" "title" %}{{ proposal.title }}
    {% get_verbose_field_name "proposals" "proposal" "funding" %}{{ proposal.funding.all|unordered_list }}
    {% get_verbose_field_name "proposals" "proposal" "funding_details" %}{{ proposal.funding_details }}
    {% get_verbose_field_name "proposals" "proposal" "funding_name" %}{{ proposal.funding_name }}
    {% get_verbose_field_name "proposals" "proposal" "pre_approval_institute" %}{{ proposal.pre_approval_institute }}
    {% get_verbose_field_name "proposals" "proposal" "pre_approval_pdf" %}{% trans "Download" %}
    - -

    {% get_verbose_field_name "proposals" "proposal" "summary" %}

    -

    {{ proposal.summary|linebreaks }}

    - -

    {% trans "Aanmelding versturen" %}

    -

    {% get_verbose_field_name "proposals" "proposal" "comments" %}

    -

    - {{ proposal.comments }} -

    -
    -
    -{% endblock %} diff --git a/proposals/templates/proposals/proposal_pdf_pre_assessment.html b/proposals/templates/proposals/proposal_pdf_pre_assessment.html deleted file mode 100644 index dd293ea93..000000000 --- a/proposals/templates/proposals/proposal_pdf_pre_assessment.html +++ /dev/null @@ -1,137 +0,0 @@ -{% extends "easy_pdf/base.html" %} - -{% load i18n %} -{% load get_field_name %} - -{% block extra_style %} - -{% endblock %} - -{% block page_header %} - -{% endblock %} - -{% block page_foot %} -Page of -{% endblock %} - -{% block content %} -
    -
    -

    - {% blocktrans with reference_number=proposal.reference_number %} - Referentienummer {{ reference_number }} - {% endblocktrans %} -

    -

    {% trans "Algemene informatie over de aanvraag" %}

    - - - - - {% if proposal.relation.needs_supervisor %} - - - - {% endif %} - {% if proposal.relation.check_in_course %} - - - - {% endif %} - - - - {% if proposal.other_applicants %} - - - - {% endif %} - - - - {% if proposal.other_stakeholders %} - - - - {% endif %} - - - - - - - - - -
    {% get_verbose_field_name "proposals" "proposal" "relation" %}{{ proposal.relation }}
    {% get_verbose_field_name "proposals" "proposal" "supervisor" %}{{ proposal.supervisor.get_full_name }}
    {% get_verbose_field_name "proposals" "proposal" "student_program" %}{{ proposal.student_program }}
    {% get_verbose_field_name "proposals" "proposal" "other_applicants" %}{{ proposal.other_applicants|yesno:_("ja,nee") }}
    {% get_verbose_field_name "proposals" "proposal" "applicants" %} -
      - {% for applicant in proposal.applicants.all %} -
    • - {{ applicant.get_full_name }} -
    • - {% endfor %} -
    -
    {% get_verbose_field_name "proposals" "proposal" "other_stakeholders" %}{{ proposal.other_stakeholders|yesno:_("ja,nee") }}
    {% get_verbose_field_name "proposals" "proposal" "stakeholders" %}{{ proposal.stakeholders }}
    {% get_verbose_field_name "proposals" "proposal" "date_start" %}{{ proposal.date_start|default:_("onbekend") }}
    {% get_verbose_field_name "proposals" "proposal" "title" %}{{ proposal.title }}
    {% get_verbose_field_name "proposals" "proposal" "pre_assessment_pdf" %}{% trans "Download" %}
    - - {% with wmo=proposal.wmo %} -

    {% trans "Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" %}

    - - - - - {% if wmo.metc == 'Y' %} - - - - - - - {% else %} - - - - {% endif %} -
    {% get_verbose_field_name "proposals" "wmo" "metc" %}{{ wmo.get_metc_display }}
    {% get_verbose_field_name "proposals" "wmo" "metc_details" %}{{ wmo.metc_details }}
    {% get_verbose_field_name "proposals" "wmo" "metc_institution" %}{{ wmo.metc_institution }}
    {% get_verbose_field_name "proposals" "wmo" "is_medical" %}{{ wmo.get_is_medical_display }}
    - {% endwith %} - -

    {% trans "Aanvraag voor voortoetsing versturen" %}

    -

    {% get_verbose_field_name "proposals" "proposal" "comments" %}

    -

    - {{ proposal.comments }} -

    -
    -
    -{% endblock %} diff --git a/proposals/templates/proposals/proposal_private_archive.html b/proposals/templates/proposals/proposal_private_archive.html index 49a2fd430..d5e32d94b 100644 --- a/proposals/templates/proposals/proposal_private_archive.html +++ b/proposals/templates/proposals/proposal_private_archive.html @@ -1,24 +1,18 @@ {% extends "base/base.html" %} -{% load vue_tags %} +{% load vue_tags %} {% load static %} {% load i18n %} {% get_current_language as LANGUAGE_CODE %} - -{% block header_title %} - {{ title }} - {{ block.super }} -{% endblock %} +{% block header_title %}{{ title }} - {{ block.super }}{% endblock %} {% block html_head %} - {# This template loads in either the dev or prod Vue library, depending on settings.DEBUG #} {% include 'uil.vue/vueloader.html' %} {# Load in the base component FancyList #} {% load_vue_component 'FancyList' %} - {% include 'proposals/vue_templates/proposal_archive_list.html' %} - {% endblock %} + {% block content %}
    @@ -35,66 +30,76 @@

    {{ title }}

    {% static "proposals/images/delete.png" as img_delete %} {% static "main/images/page_white_acrobat.png" as img_pdf %} {% static "proposals/images/folder_delete.png" as img_hide %} - {% static "proposals/images/folder_add.png" as img_add%} + {% static "proposals/images/folder_add.png" as img_add %} {% static 'reviews/images/scale.png' as img_decide %} -

    - {{ body }} -

    +

    {{ body }}

    {% trans "Uitleg" %}

      {% if modifiable %}
    • {% blocktrans trimmed %} - Klik op om naar de volgende stap in + Klik op + + om naar de volgende stap in het proces te gaan. {% endblocktrans %}
    • {% blocktrans trimmed %} - Klik op om de verschillen met de + Klik op + + om de verschillen met de voorgaande versie te zien (alleen beschikbaar voor revisies/amendementen). {% endblocktrans %}
    • {% blocktrans trimmed %} - Klik op om je aanvraag te verwijderen. + Klik op + + om je aanvraag te verwijderen. {% endblocktrans %}
    • {% endif %} {% if submitted %}
    • {% blocktrans trimmed %} - Klik op om een ingediende aanvraag in te zien. + Klik op + + om een ingediende aanvraag in te zien. {% endblocktrans %}
    • {% endif %} {% if supervised %}
    • {% blocktrans trimmed %} - Klik op om je beslissing door te geven (als eindverantwoordelijke). + Klik op + + om je beslissing door te geven (als eindverantwoordelijke). {% endblocktrans %}
    • {% endif %} {% if is_secretary %}
    • {% blocktrans trimmed %} - Klik op om een ingediende aanvraag te verbergen + Klik op + + om een ingediende aanvraag te verbergen uit het archief. {% endblocktrans %}
    • {% blocktrans trimmed %} - Klik op om een ingediende aanvraag toe te voegen + Klik op + + om een ingediende aanvraag toe te voegen aan het archief. {% endblocktrans %}
    • {% endif %}
    -
    -
    {% endblock %} diff --git a/proposals/templates/proposals/proposal_public_archive.html b/proposals/templates/proposals/proposal_public_archive.html index 79e27b4eb..f9ce6ced1 100644 --- a/proposals/templates/proposals/proposal_public_archive.html +++ b/proposals/templates/proposals/proposal_public_archive.html @@ -2,8 +2,8 @@ {% load static %} {% load i18n %} -{% get_current_language as language_code %} +{% get_current_language as language_code %} {% block header_title %} {% trans 'Goedgekeurde aanvragen' %} - {{ block.super }} {% endblock %} @@ -26,21 +26,19 @@

    {% trans 'Goedgekeurde aanvragen' %}

    {{ proposal.reference_number }} {{ proposal.title }} - - {{ proposal.date_confirmed|date:"d M Y" }} - + {{ proposal.date_confirmed|date:"d M Y" }} {% if proposal.reviewing_committee.name == "AK" %} - {% trans 'AK' %} + {% trans 'AK' %} {% else %} - {% trans 'LK' %} + {% trans 'LK' %} {% endif %} {% endfor %} -
    +
    {% endblock %} diff --git a/proposals/templates/proposals/proposal_start.html b/proposals/templates/proposals/proposal_start.html index 332b7f4dd..13b2d9173 100644 --- a/proposals/templates/proposals/proposal_start.html +++ b/proposals/templates/proposals/proposal_start.html @@ -11,74 +11,69 @@

    {% trans "Een nieuwe aanvraag aanmelden" %}

    - -
      -
    • {% trans "Check voor het indienen:" %} +
        +
      • + {% trans "Check voor het indienen:" %}
          +
        • + {% blocktrans trimmed %} + De + UU-webpagina van de FETC-GW voor nieuws en de agenda. + {% endblocktrans %} +
        • +
        • + {% blocktrans trimmed %} + Het reglement van de FEtC-H. + {% endblocktrans %} +
        • +
      • {% blocktrans trimmed %} - De - - UU-webpagina van de FETC-GW voor nieuws en de agenda. + Gebruik de juiste (meest recente) voorbeelddocumenten voor de informed consent. {% endblocktrans %}
      • -
      • +

        {% blocktrans trimmed %} - Het reglement van de - Algemene Kamer (AK) - of dat van de - Linguïstiek Kamer (LK). + Studenten moeten hun begeleider vragen om deze formulieren; dezelfde voorbeeldteksten, maar op niet-officiële formulieren, zijn te vinden op deze pagina. {% endblocktrans %} -

      • -
      -
    • - {% blocktrans trimmed %} - Gebruik de juiste (meest recente) voorbeelddocumenten voor de informed consent. - {% endblocktrans %} -
    • -

      - {% blocktrans trimmed %} - Studenten moeten hun begeleider vragen om deze formulieren; dezelfde voorbeeldteksten, maar op niet-officiële formulieren, zijn te vinden op deze pagina. - {% endblocktrans %} -

      +

      -
    +

    - {% blocktrans %} + {% blocktrans trimmed %} Een voorstel is opgebouwd uit (van groot naar klein) (i) trajecten, (ii) sessies, (iii) taken. {% endblocktrans %}

      -

      -

    • {% trans "Traject" %}: +
    • + {% trans "Traject" %}: {% blocktrans trimmed %} - Als je met verschillende deelnemersgroepen werkt die een verschillend onderzoekstraject doorlopen waarvoor verschillende informed consent documenten nodig zijn.{% endblocktrans %} -

      {% blocktrans trimmed %} - Bijvoorbeeld: ouders van leerlingen 15 jaar en jonger, docenten, een controlegroep en een experimentele groep die verschillende taken krijgen. + Als je met verschillende deelnemersgroepen werkt die een verschillend onderzoekstraject doorlopen waarvoor verschillende informed consent documenten nodig zijn. + {% endblocktrans %} +

      + {% blocktrans trimmed %} + Bijvoorbeeld: ouders van leerlingen 15 jaar en jonger, docenten, een controlegroep en een experimentele groep die verschillende taken krijgen. {% endblocktrans %} -

      -

      -

      -

    • {% trans "Sessie" %}: - {% blocktrans trimmed %} - Alle taken/onderdelen die iemand op één dag uitvoert. - {% endblocktrans %} -
    • -

      -

      -

    • {% trans "Taak" %}: - {% blocktrans trimmed %} - Een taak of onderdeel van je onderzoek. -

      - Bijvoorbeeld: het invullen van een vragenlijst, een interview, of een taaltest. -

      - {% endblocktrans %} -
    • -

      +

      + +
    • + {% trans "Sessie" %}: + {% blocktrans trimmed %} + Alle taken/onderdelen die iemand op één dag uitvoert. + {% endblocktrans %} +
    • +
    • + {% trans "Taak" %}: + {% blocktrans trimmed %} + Een taak of onderdeel van je onderzoek. +

      + Bijvoorbeeld: het invullen van een vragenlijst, een interview, of een taaltest. +

      + {% endblocktrans %} +
    - - {% trans "Volgende stap >>" %} - + {% trans "Volgende stap >>" %}
    {% endblock %} diff --git a/proposals/templates/proposals/proposal_start_practice.html b/proposals/templates/proposals/proposal_start_practice.html index 091b688c0..53b59ccb7 100644 --- a/proposals/templates/proposals/proposal_start_practice.html +++ b/proposals/templates/proposals/proposal_start_practice.html @@ -10,79 +10,76 @@ {% block content %}
    -

    - {% trans "Een nieuwe aanvraag aanmelden (oefenportaal)" %} -

    - -
      -
    • {% trans "Check voor het indienen:" %} +

      {% trans "Een nieuwe aanvraag aanmelden (oefenportaal)" %}

      +
        +
      • + {% trans "Check voor het indienen:" %}
          +
        • + {% blocktrans trimmed %} + De + UU-webpagina van de FETC-GW voor nieuws en de agenda. + {% endblocktrans %} +
        • +
        • + {% blocktrans trimmed %} + Het reglement van de FEtC-H. + {% endblocktrans %} +
        • +
      • {% blocktrans trimmed %} - De - - UU-webpagina van de FETC-GW voor nieuws en de agenda. + Gebruik de juiste (meest recente) voorbeelddocumenten voor de informed consent. {% endblocktrans %}
      • -
      • +

        {% blocktrans trimmed %} - Het reglement van de - Algemene Kamer (AK) - of dat van de - Linguïstiek Kamer (LK). + Studenten moeten hun begeleider vragen om deze formulieren; dezelfde voorbeeldteksten, maar op niet-officiële formulieren, zijn te vinden op deze pagina. {% endblocktrans %} -

      • -
      -
    • - {% blocktrans trimmed %} - Gebruik de juiste (meest recente) voorbeelddocumenten voor de informed consent. - {% endblocktrans %} +

    • -

      - {% blocktrans trimmed %} - Studenten moeten hun begeleider vragen om deze formulieren; dezelfde voorbeeldteksten, maar op niet-officiële formulieren, zijn te vinden op deze pagina. - {% endblocktrans %} -

      - -
    +

    - {% blocktrans %} + {% blocktrans trimmed %} Een voorstel is opgebouwd uit (van groot naar klein) (i) trajecten, (ii) sessies, (iii) taken. {% endblocktrans %}

      -

      -

    • {% trans "Traject" %}: - {% blocktrans trimmed %} - Als je met verschillende deelnemersgroepen werkt die een verschillend onderzoekstraject doorlopen waarvoor verschillende informed consent documenten nodig zijn.{% endblocktrans %} -

      {% blocktrans trimmed %} - Bijvoorbeeld: ouders van leerlingen 15 jaar en jonger, docenten, een controlegroep en een experimentele groep die verschillende taken krijgen. +

    • + {% trans "Traject" %}: + {% blocktrans trimmed %} + Als je met verschillende deelnemersgroepen werkt die een verschillend onderzoekstraject doorlopen waarvoor verschillende informed consent documenten nodig zijn. {% endblocktrans %} -

      -

      -

    • {% trans "Sessie" %}: - {% blocktrans trimmed %} - Alle taken/onderdelen die iemand op één dag uitvoert. - {% endblocktrans %} -
    • -

      -

      -

    • {% trans "Taak" %}: - {% blocktrans trimmed %} - Een taak of onderdeel van je onderzoek. -

      - Bijvoorbeeld: het invullen van een vragenlijst, een interview, of een taaltest. -

      - {% endblocktrans %} -
    • -

      +

      + {% blocktrans trimmed %} + Bijvoorbeeld: ouders van leerlingen 15 jaar en jonger, docenten, een controlegroep en een experimentele groep die verschillende taken krijgen. + {% endblocktrans %} +

      + +
    • + {% trans "Sessie" %}: + {% blocktrans trimmed %} + Alle taken/onderdelen die iemand op één dag uitvoert. + {% endblocktrans %} +
    • +
    • + {% trans "Taak" %}: + {% blocktrans trimmed %} + Een taak of onderdeel van je onderzoek. +

      + Bijvoorbeeld: het invullen van een vragenlijst, een interview, of een taaltest. +

      + {% endblocktrans %} +

    {% trans "Houd er rekening mee dat een oefenaanvraag niet ingediend kan worden." %}

    - {% csrf_token %} - {{ form.as_table }}
    + + {% csrf_token %} + + {{ form.as_table }} +
    {% include "base/form_buttons.html" %}
    - {% endblock %} diff --git a/proposals/templates/proposals/proposal_start_pre_approved.html b/proposals/templates/proposals/proposal_start_pre_approved.html index f9b8c79cf..4417f9b9c 100644 --- a/proposals/templates/proposals/proposal_start_pre_approved.html +++ b/proposals/templates/proposals/proposal_start_pre_approved.html @@ -3,28 +3,23 @@ {% load static %} {% load i18n %} - - {% block header_title %} {% trans "Een nieuwe aanvraag aanmelden (die al goedgekeurd is door een andere ethische toetsingscomissie)" %} - {{ block.super }} {% endblock %} {% block content %} - {% trans "https://fetc-gw.wp.hum.uu.nl/reglement-fetc-gw/" as reg_url %}
    -

    - {% trans "Een nieuwe aanvraag aanmelden (die al goedgekeurd is door een andere ethische toetsingscomissie)" %} -

    +

    {% trans "Een nieuwe aanvraag aanmelden (die al goedgekeurd is door een andere ethische toetsingscomissie)" %}

    - {% blocktrans trimmed %} - Je wilt een nieuwe aanvraag ter toetsing bij de FETC-GW aanmelden, die al getoetst is - door een andere ethische (toetsings) commissie. - Het is daarvoor noodzakelijk dat je goed bekend bent met het FETC-GW - reglement. - Je kan jezelf en de commissieleden veel tijd besparen door je eerst - goed te informeren. + {% blocktrans trimmed %} + Je wilt een nieuwe aanvraag ter toetsing bij de FETC-GW aanmelden, die al getoetst is + door een andere ethische (toetsings) commissie. + Het is daarvoor noodzakelijk dat je goed bekend bent met het FETC-GW + reglement. + Je kan jezelf en de commissieleden veel tijd besparen door je eerst + goed te informeren. {% endblocktrans %}

    @@ -32,15 +27,14 @@

    Gebruik bij het invullen s.v.p. geen afkortingen waar de FETC-GW wellicht niet mee bekend is. Raadpleeg bij vragen eerst het - reglement + reglement en neem eventueel daarna contact op met de secretaris ({{ secretary_name }}, fetc-gw@uu.nl). {% endblocktrans %}

    - - {% trans "Volgende stap >>" %} - + {% trans "Volgende stap >>" %}

    {% endblock %} diff --git a/proposals/templates/proposals/proposal_start_pre_assessment.html b/proposals/templates/proposals/proposal_start_pre_assessment.html index ee85f6885..a0e29d324 100644 --- a/proposals/templates/proposals/proposal_start_pre_assessment.html +++ b/proposals/templates/proposals/proposal_start_pre_assessment.html @@ -11,25 +11,36 @@

    {% trans "Nieuwe FETC-aanvraag voor (al dan niet goedgekeurde) subsidieaanvragen" %}

    -

    - -

      -
    • {% blocktrans trimmed %}Soms is bij het indienen van een aanvraag bij een subsidieverstrekker een ethische verklaring nodig.{% endblocktrans %}
    • -
    • {% blocktrans trimmed %}Goedgekeurde NWO-aanvragen hebben ook een ethische verklaring nodig alvorens een startdatum vastgesteld kan worden.{% endblocktrans %}
    • -
    - -

    {% blocktrans trimmed %}In deze gevallen kunnen onderzoekers de FETC-GW verzoeken om de onderzoeksaanvraag te laten toetsen. Dit kan via deze route van de portal{% endblocktrans %}.

    - -

    {% blocktrans trimmed %}NB: De toetsing kan alleen op hoofdlijnen plaatsvinden en vervangt NIET de reguliere ethische toetsing van een onderzoek; elke mensgebonden studie die in het kader van de onderzoeksaanvraag zal worden uitgevoerd dient vóóraf goedgekeurd te zijn door de FETC-GW.{% endblocktrans %} -

    - -

    - - - {% trans "Volgende stap >>" %} - +
  • + {% blocktrans trimmed %} + Soms is bij het indienen van een aanvraag bij een subsidieverstrekker een ethische verklaring nodig. + {% endblocktrans %} +
  • +
  • + {% blocktrans trimmed %} + Goedgekeurde NWO-aanvragen hebben ook een ethische verklaring nodig alvorens een startdatum vastgesteld kan worden. + {% endblocktrans %} +
  • + +

    + {% blocktrans trimmed %} + In deze gevallen kunnen onderzoekers de FETC-GW verzoeken om de onderzoeksaanvraag te laten toetsen. Dit kan via deze route van de portal + {% endblocktrans %} + . +

    +

    + {% blocktrans trimmed %} + NB: De toetsing kan alleen op hoofdlijnen plaatsvinden en vervangt NIET de reguliere ethische toetsing van een onderzoek; elke mensgebonden studie die in het kader van de onderzoeksaanvraag zal worden uitgevoerd dient vóóraf goedgekeurd te zijn door de FETC-GW. + {% endblocktrans %} +

    +

    + +

    + {% trans "Volgende stap >>" %} +
    -
    -{% endblock %} + {% endblock %} diff --git a/proposals/templates/proposals/proposal_submit.html b/proposals/templates/proposals/proposal_submit.html index d88a42209..ba041907c 100644 --- a/proposals/templates/proposals/proposal_submit.html +++ b/proposals/templates/proposals/proposal_submit.html @@ -15,8 +15,10 @@ {% endblock %} {% block html_head %} - - + + {% endblock %} {% block content %} @@ -53,27 +55,25 @@

    {% if proposal.is_pre_assessment %} - {% blocktrans %} + {% blocktrans trimmed %} Je aanvraag voor voortoetsing is compleet. {% endblocktrans %} - {% blocktrans %} + {% blocktrans trimmed %} Als je er zeker van bent dat je aanvraag op adequate wijze is gespecifieerd kan je de aanmelding nu ter beoordeling naar de FETC-GW versturen. {% endblocktrans %} - {% elif proposal.relation.needs_supervisor %} - {% blocktrans %} + {% blocktrans trimmed %} Je concept-aanmelding is compleet. {% endblocktrans %} - {% blocktrans %} + {% blocktrans trimmed %} Je kan nu je concept-aanmelding ter beoordeling naar je supervisor versturen. {% endblocktrans %} - {% else %} - {% blocktrans %} + {% blocktrans trimmed %} Je aanmelding is compleet. {% endblocktrans %} - {% blocktrans %} + {% blocktrans trimmed %} Als je er zeker van bent dat je aanvraag op adequate wijze is gespecifieerd kan je de aanmelding nu ter beoordeling naar de FETC-GW versturen. {% endblocktrans %} @@ -92,8 +92,7 @@

    de concept-aanvraag wordt dan bewaard voor eventuele latere wijziging en indiening. {% endblocktrans %}

    - - {% if not proposal.is_pre_assessment %} + {% if not proposal.is_pre_assessment %} {% for study in proposal.study_set.all %} {% if study.has_missing_forms %}
    @@ -119,54 +118,50 @@

    {% endif %} {% endfor %} {% endif %} -
    - - {% if troublesome_pages %} -
    -
    - {% blocktrans trimmed %} - Er zijn nog errors gevonden op de volgende pagina's: - {% endblocktrans %} -
    - - {% blocktrans trimmed %} - Dit komt waarschijnlijk doordat je nog niet alle verplichte velden heeft ingevuld. Je kan je - aanmelding pas versturen wanneer deze fouten gecorrigeerd zijn. - {% endblocktrans %} -
    - {% endif %} - {% if start_date_warning %} -
    -
    {% trans "Controleer uw beoogde startdatum" %}
    -

    - {% blocktrans trimmed %} - Omdat de beoogde startdatum binnen twee weken van vandaag ligt, kan de FETC helaas geen officiële goedkeuring meer geven voor deze aanvraag. Controleer daarom bij een revisie altijd of de beoogde startdatum nog klopt. - {% endblocktrans %} - {% url "proposals:update" proposal.pk as first_page_url %} - {% blocktrans trimmed %} - De beoogde startdatum vindt u op - deze pagina. - {% endblocktrans %} -

    -
    - {% endif %} - - - {% csrf_token %} - {{ form.as_table }}
    + {% if troublesome_pages %} +
    +
    + {% blocktrans trimmed %} + Er zijn nog errors gevonden op de volgende pagina's: + {% endblocktrans %} +
    + + {% blocktrans trimmed %} + Dit komt waarschijnlijk doordat je nog niet alle verplichte velden heeft ingevuld. Je kan je + aanmelding pas versturen wanneer deze fouten gecorrigeerd zijn. + {% endblocktrans %} +
    + {% endif %} + {% if start_date_warning %} +
    +
    {% trans "Controleer uw beoogde startdatum" %}
    +

    + {% blocktrans trimmed %} + Omdat de beoogde startdatum binnen twee weken van vandaag ligt, kan de FETC helaas geen officiële goedkeuring meer geven voor deze aanvraag. Controleer daarom bij een revisie altijd of de beoogde startdatum nog klopt. + {% endblocktrans %} + {% url "proposals:update" proposal.pk as first_page_url %} + {% blocktrans trimmed %} + De beoogde startdatum vindt u op + deze pagina. + {% endblocktrans %} +

    +
    + {% endif %} + {% csrf_token %} + + {{ form.as_table }} +
    {% if is_practice %} -
    - {% trans "Je bewerkt op het moment een oefenaanvraag. Deze kan niet ter beoordeling door de FETC-GW worden ingediend." %} -
    +
    + {% trans "Je bewerkt op het moment een oefenaanvraag. Deze kan niet ter beoordeling door de FETC-GW worden ingediend." %} +
    {% endif %} {% if troublesome_pages or is_practice %} {% include "base/form_buttons.html" with no_forward=1 %} diff --git a/proposals/templates/proposals/proposal_submitted.html b/proposals/templates/proposals/proposal_submitted.html index 7c3a14678..32df1340b 100644 --- a/proposals/templates/proposals/proposal_submitted.html +++ b/proposals/templates/proposals/proposal_submitted.html @@ -35,7 +35,6 @@

    {% trans "Je aanmelding is verstuurd." %} {% endif %} {% trans "Je ontvangt een e-mail ter bevestiging." %} - {% url 'proposals:my_submitted' as submitted_url %} {% blocktrans trimmed %} Klik hier om je ingediende aanvragen in te zien. diff --git a/proposals/templates/proposals/proposal_update_attachments.html b/proposals/templates/proposals/proposal_update_attachments.html index 941594ebb..b59faee2d 100644 --- a/proposals/templates/proposals/proposal_update_attachments.html +++ b/proposals/templates/proposals/proposal_update_attachments.html @@ -10,21 +10,25 @@ {% block content %}
    -

    - {% trans "Formulieren aanpassen" %} -

    +

    {% trans "Formulieren aanpassen" %}

    {% blocktrans trimmed with title=proposal.title ref_number=proposal.reference_number %} - Op deze pagina kan je de formulieren aanpassen behorende bij de aanvraag {{ title }} - (referentienummer {{ ref_number }}). + Op deze pagina kan je de formulieren aanpassen behorende bij de aanvraag {{ title }} + (referentienummer {{ ref_number }}). {% endblocktrans %}

    - {% csrf_token %} - {{ form.as_table }}
    + + {% csrf_token %} + + {{ form.as_table }} +
    - - {% trans "Terug naar de vorige pagina" %} + + {% trans "Terug naar de vorige pagina" %}
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/proposals/templates/proposals/proposal_update_date_start.html b/proposals/templates/proposals/proposal_update_date_start.html new file mode 100644 index 000000000..143512cf0 --- /dev/null +++ b/proposals/templates/proposals/proposal_update_date_start.html @@ -0,0 +1,37 @@ +{% extends "base/base.html" %} + +{% load static %} +{% load i18n %} + +{% block header_title %} + {% trans "Formulieren aanpassen" %} - {{ block.super }} +{% endblock %} + +{% block content %} +
    +
    +

    {% trans "Startdatum aanpassen" %}

    +

    + {% blocktrans trimmed with title=proposal.title ref_number=proposal.reference_number %} + Op deze pagina kan de startdatum worden aangepast van de aanvraag {{ title }} + (referentienummer {{ ref_number }}). Let op! Als de review al is afgerond, + wordt de nieuwe startdatum niet automatisch weergegeven in de PDF. Mocht je de PDF + opnieuw willen genereren, neem hierover dan contact op met + {% endblocktrans %} + portalsupport.gw@uu.nl. +

    +
    + {% csrf_token %} + + {{ form.as_table }} +
    + + + {% trans "Terug naar de vorige pagina" %} +
    +
    +
    +{% endblock %} diff --git a/proposals/templates/proposals/study_consent.html b/proposals/templates/proposals/study_consent.html index b716a5f2f..7c8a54329 100644 --- a/proposals/templates/proposals/study_consent.html +++ b/proposals/templates/proposals/study_consent.html @@ -5,11 +5,11 @@ {% load uil_filters %} {% block header_title %} - {% trans "Informed consent formulieren" %} - {{ block.super }} + {% trans "Informed consent formulieren" %} - {{ block.super }} {% endblock %} {% block html_head %} - + {% endblock %} {% block content %} -
    -
    - {% with nav_items=proposal.available_urls active=4 %} - {% include 'base/navigation.html' %} - {% endwith %} - -

    - {% trans "Informed consent formulieren uploaden" %} -

    -

    - {% blocktrans trimmed %} - Hier kan je de Informed consent formulieren uploaden voor de opgegeven traject(en). Optioneel kan je indien nodig maximaal 10 - paar extra formulieren uploaden.
    Klik hiervoor op 'Voeg extra formulieren' onderaan de pagina. Deze velden - kan je weer weg halen door alle formulieren te wissen. - {% endblocktrans %} -

    - -

    - {% blocktrans trimmed %} - Gebruik de juiste (meest recente) voorbeelddocumenten voor de informed consent. - {% endblocktrans %} - - {% blocktrans trimmed %} - Studenten moeten hun begeleider vragen om deze formulieren; dezelfde voorbeeldteksten, maar op niet-officiële formulieren, zijn te vinden op deze pagina. - {% endblocktrans %} -

    - -

    - {% blocktrans trimmed %} - Let op dat je documenten geen redactionele fouten en/of taalfouten bevatten: een aanvraag kan hierom direct voor revisie worden teruggestuurd. - {% endblocktrans %} - {% blocktrans trimmed %} - Bij ontvangst worden alle bestandsnamen gewijzigd, zet hier dus geen belangrijke informatie in. - {% endblocktrans %} -

    - {% if external_permission %} -
    -

    {% blocktrans trimmed %} - Omdat er in één of meer trajecten onderzoek wordt uitgevoerd op een externe locatie waar toestemming voor vereist is, vragen we daar om een tweede set Informed Consent formulieren voor het management van de instelling. Dat is bijvoorbeeld de schoolleiding of het departementshoofd van een zorginstelling. Voeg waar nodig ook een informatiebrief voor de ouders/verzorgers toe. - {% endblocktrans %}

    -
    - {% endif %} -
    {% csrf_token %} - {{ formset.management_form }} - - {# Reset the counter, as we're looping again #} - {% counter extra_form_counter create 1 %} - {% for form in formset %} - - {% if form.instance.study %} - {# If it's connected to a study, use the study title and a simple div #} -
    - {% with study=form.instance.study %} - {% include 'studies/study_title.html' %} - {% endwith %} - {% else %} - {# If not, we have to do some fancy stuff for the extra forms #} - {% if form.instance.informed_consent or form.instance.briefing or form.instance.parents_information or form.instance.director_consent_information or form.instance.director_consent_declaration %} - {# We can't check this in Python, so we determine here if the object is empty or used #} - {% set used = 1 %} - {% else %} - {% set used = 0 %} - {# We only add the add link if the form is empty, as this simplifies the JS #} - - {% endif %} - -
    -

    {% trans 'Extra formulieren' %} {% counter extra_form_counter value %}

    - {% counter extra_form_counter increment 1 %} - - {% endif %} - - - {{ form.as_table }} -
    -
    - {% endfor %} -
    - {% include "base/form_buttons.html" %} - +
    +
    + {% with nav_items=proposal.available_urls active=4 %} + {% include 'base/navigation.html' %} + {% endwith %} +

    {% trans "Informed consent formulieren uploaden" %}

    +

    + {% blocktrans trimmed %} + Hier kan je de Informed consent formulieren uploaden voor de opgegeven traject(en). Optioneel kan je indien nodig maximaal 10 + paar extra formulieren uploaden. +
    + Klik hiervoor op 'Voeg extra formulieren' onderaan de pagina. Deze velden + kan je weer weg halen door alle formulieren te wissen. + {% endblocktrans %} +

    +

    + {% blocktrans trimmed %} + Gebruik de juiste (meest recente) voorbeelddocumenten voor de informed consent. + + {% endblocktrans %} + {% blocktrans trimmed %} + Studenten moeten hun begeleider vragen om deze formulieren; dezelfde voorbeeldteksten, maar op niet-officiële formulieren, zijn te vinden op deze pagina. + {% endblocktrans %} +

    +

    + {% blocktrans trimmed %} + Let op dat je documenten geen redactionele fouten en/of taalfouten bevatten: een aanvraag kan hierom direct voor revisie worden teruggestuurd. + {% endblocktrans %} + {% blocktrans trimmed %} + Bij ontvangst worden alle bestandsnamen gewijzigd, zet hier dus geen belangrijke informatie in. + {% endblocktrans %} +

    + {% if external_permission %} +
    +

    + {% blocktrans trimmed %} + Omdat er in één of meer trajecten onderzoek wordt uitgevoerd op een externe locatie waar toestemming voor vereist is, vragen we daar om een tweede set Informed Consent formulieren voor het management van de instelling. Dat is bijvoorbeeld de schoolleiding of het departementshoofd van een zorginstelling. Voeg waar nodig ook een informatiebrief voor de ouders/verzorgers toe. + {% endblocktrans %} +

    + {% endif %} +
    + {% csrf_token %} + {{ formset.management_form }} + {# Reset the counter, as we're looping again #} + {% counter extra_form_counter create 1 %} + {% for form in formset %} + {% if form.instance.study %} + {# If it's connected to a study, use the study title and a simple div #} +
    + {% with study=form.instance.study %} + {% include 'studies/study_title.html' %} + {% endwith %} + {% else %} + {# If not, we have to do some fancy stuff for the extra forms #} + {% if form.instance.informed_consent or form.instance.briefing or form.instance.parents_information or form.instance.director_consent_information or form.instance.director_consent_declaration %} + {# We can't check this in Python, so we determine here if the object is empty or used #} + {% set used = 1 %} + {% else %} + {% set used = 0 %} + {# We only add the add link if the form is empty, as this simplifies the JS #} + + {% endif %} +
    +

    {% trans 'Extra formulieren' %} {% counter extra_form_counter value %}

    + {% counter extra_form_counter increment 1 %} + {% endif %} + + {{ form.as_table }} +
    +
    + {% endfor %} +
    + {% include "base/form_buttons.html" %} + +
    - {% endblock %} diff --git a/proposals/templates/proposals/study_start.html b/proposals/templates/proposals/study_start.html index 66e5f1e0e..eebce8d03 100644 --- a/proposals/templates/proposals/study_start.html +++ b/proposals/templates/proposals/study_start.html @@ -8,7 +8,7 @@ {% endblock %} {% block html_head %} - + {% endblock %} {% block content %} @@ -60,42 +60,42 @@ {% with nav_items=proposal.available_urls active=3 %} {% include 'base/navigation.html' %} {% endwith %} -

    - {% trans "Eén of meerdere trajecten?" %} -

    +

    {% trans "Eén of meerdere trajecten?" %}

    - {% blocktrans %} + {% blocktrans trimmed %} Een voorstel is opgebouwd uit (van groot naar klein) (i) trajecten, (ii) sessies, (iii) taken. {% endblocktrans %}

      -

      -

    • {% trans "Traject" %}: +
    • + {% trans "Traject" %}: {% blocktrans trimmed %} - Als je met verschillende deelnemersgroepen werkt die een verschillend onderzoekstraject doorlopen waarvoor verschillende informed consent documenten nodig zijn.{% endblocktrans %} -

      {% blocktrans trimmed %} - Bijvoorbeeld: ouders van leerlingen 15 jaar en jonger, docenten, een controlegroep en een experimentele groep die verschillende taken krijgen. + Als je met verschillende deelnemersgroepen werkt die een verschillend onderzoekstraject doorlopen waarvoor verschillende informed consent documenten nodig zijn. + {% endblocktrans %} +

      + {% blocktrans trimmed %} + Bijvoorbeeld: ouders van leerlingen 15 jaar en jonger, docenten, een controlegroep en een experimentele groep die verschillende taken krijgen. {% endblocktrans %} -

      -

      -

    • {% trans "Sessie" %}: - {% blocktrans trimmed %} - Alle taken/onderdelen die iemand op één dag uitvoert. - {% endblocktrans %} -
    • -

      -

      -

    • {% trans "Taak" %}: - {% blocktrans trimmed %} - Een taak of onderdeel van je onderzoek. -

      - Bijvoorbeeld: het invullen van een vragenlijst, een interview, of een taaltest. -

      - {% endblocktrans %} -
    • -

      +

      + +
    • + {% trans "Sessie" %}: + {% blocktrans trimmed %} + Alle taken/onderdelen die iemand op één dag uitvoert. + {% endblocktrans %} +
    • +
    • + {% trans "Taak" %}: + {% blocktrans trimmed %} + Een taak of onderdeel van je onderzoek. +

      + Bijvoorbeeld: het invullen van een vragenlijst, een interview, of een taaltest. +

      + {% endblocktrans %} +
    -
    {% csrf_token %} + + {% csrf_token %} {{ form.as_table }}
    diff --git a/proposals/templates/proposals/table_with_header.html b/proposals/templates/proposals/table_with_header.html new file mode 100644 index 000000000..eb21d24f6 --- /dev/null +++ b/proposals/templates/proposals/table_with_header.html @@ -0,0 +1,14 @@ +{% load i18n %} + +{% if page_break %} +

    {% trans section_title %}

    +{% elif section_title %} +

    {% trans section_title %}

    +{% endif %} +{% if sub_title %}

    {{ sub_title }}

    {% endif %} +
    + {% for row in rows %} +
    {{ row.verbose_name }}
    +
    {{ row.value }}
    + {% endfor %} +
    diff --git a/proposals/templates/proposals/table_with_header_diff.html b/proposals/templates/proposals/table_with_header_diff.html new file mode 100644 index 000000000..a035042c8 --- /dev/null +++ b/proposals/templates/proposals/table_with_header_diff.html @@ -0,0 +1,48 @@ +{% load diff_tags %} +{% load i18n %} + +{% if section_title %} +

    {% trans section_title %}

    +{% endif %} +{% if sub_title %}

    {{ sub_title }}

    {% endif %} + + + + + + + {% if warning %} + {% for row in rows|slice:":1" %} + + + {# If the first object is missing, place a warning on the first TD #} + {% if missing_object == 'old' %} + + + {# Otherwise, we're missing the second one, thus we place the warning on the second #} + {% elif missing_object == 'new' %} + + + {% endif %} + + {% endfor %} + {% for row in rows|slice:"1:" %} + + + + + {% endfor %} + {% else %} + {% for row in rows %} + + + + + + {% endfor %} + {% endif %} +
    {% trans "Originele aanvraag" %}{% trans "Revisie/amendement" %}
    {{ row.verbose_name }} +
    {{ warning }}
    +
    {{ row.value }}{{ row.value }} +
    {{ warning }}
    +
    {{ row.verbose_name }}{{ row.value }}
    {{ row.verbose_name }}{{ row.old_value }}{{ row.new_value }}
    diff --git a/proposals/templates/proposals/translated_consent_forms.html b/proposals/templates/proposals/translated_consent_forms.html index 0db346fe4..9372d2237 100644 --- a/proposals/templates/proposals/translated_consent_forms.html +++ b/proposals/templates/proposals/translated_consent_forms.html @@ -12,7 +12,7 @@ $(function () { depends_on_value('translated_forms', 'True', 'translated_forms_languages'); }); - + {% endblock %} {% block content %} @@ -20,24 +20,23 @@
    {% with nav_items=proposal.available_urls active=pagenr %} {% include 'base/navigation.html' %} - {% endwith %} -

    - {% trans "Vertaling informed consent formulieren" %} -

    - + {% endwith %} +

    {% trans "Vertaling informed consent formulieren" %}

    {% blocktrans trimmed %} - Documenten moet in het Nederlands of in het Engels worden ingediend. - Echter, om je deelnemers op een adequate manier te informeren kan het noodzakelijk zijn om de documenten in hun moedertaal te vertalen. - Als dat het geval is, dan hoeven deze niet direct te worden ingediend. Het is wel noodzakelijk te vermelden dat deze vertaald zullen gaan worden. - Bij goedkeuring moeten de documenten in andere talen wel worden aangeleverd, omdat de portal ook dient als officieel archief van goedgekeurde aanvragen. - Dit kan eventueel na goedkeuring, maar kan ook bij een minimale revisie. + Documenten moet in het Nederlands of in het Engels worden ingediend. + Echter, om je deelnemers op een adequate manier te informeren kan het noodzakelijk zijn om de documenten in hun moedertaal te vertalen. + Als dat het geval is, dan hoeven deze niet direct te worden ingediend. Het is wel noodzakelijk te vermelden dat deze vertaald zullen gaan worden. + Bij goedkeuring moeten de documenten in andere talen wel worden aangeleverd, omdat de portal ook dient als officieel archief van goedgekeurde aanvragen. + Dit kan eventueel na goedkeuring, maar kan ook bij een minimale revisie. {% endblocktrans %}

    - - {% csrf_token %} - {{ form.as_table }}
    - {% include "base/form_buttons.html" %} + + {% csrf_token %} + + {{ form.as_table }} +
    + {% include "base/form_buttons.html" %}
    diff --git a/proposals/templates/proposals/vue_templates/proposal_archive_list.html b/proposals/templates/proposals/vue_templates/proposal_archive_list.html index d5e8473ef..a2bb72f80 100644 --- a/proposals/templates/proposals/vue_templates/proposal_archive_list.html +++ b/proposals/templates/proposals/vue_templates/proposal_archive_list.html @@ -112,7 +112,7 @@

    - {% trans "Eindverantwoordelijke onderzoeker" %}: + {% trans "Promotor/Begeleider" %}: diff --git a/proposals/templates/proposals/vue_templates/proposal_list.html b/proposals/templates/proposals/vue_templates/proposal_list.html index bd774a319..2431c0d84 100644 --- a/proposals/templates/proposals/vue_templates/proposal_list.html +++ b/proposals/templates/proposals/vue_templates/proposal_list.html @@ -7,6 +7,8 @@ {% static "main/images/page_white_acrobat.png" as img_pdf %} {% static "proposals/images/folder_delete.png" as img_hide %} {% static 'reviews/images/scale.png' as img_decide %} +{% static 'proposals/images/edit-undo.png' as img_revise %} + - + + {% endblock %} {% block content %} @@ -22,13 +24,17 @@ {% with nav_items=wmo.proposal.available_urls active=2 %} {% include 'base/navigation.html' %} {% endwith %} -

    - {% trans "WMO-check" %} -

    -
    {% csrf_token %} - {{ form.as_table }}
    +

    {% trans "WMO-check" %}

    + + {% csrf_token %} + + {{ form.as_table }} +
    - +
    diff --git a/proposals/templates/proposals/wmo_form.html b/proposals/templates/proposals/wmo_form.html index 3a9996d1e..334393725 100644 --- a/proposals/templates/proposals/wmo_form.html +++ b/proposals/templates/proposals/wmo_form.html @@ -8,7 +8,9 @@ {% endblock %} {% block html_head %} - + {% endblock %} - {% block content %}
    {% with nav_items=proposal.available_urls active=2 %} {% include 'base/navigation.html' %} {% endwith %} -

    - {% trans "Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" %} -

    - -
    {% csrf_token %} - {{ form.as_table }}
    +

    {% trans "Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" %}

    + + {% csrf_token %} + + {{ form.as_table }} +
    {% with proposal=wmo.proposal %} {% include "base/form_buttons.html" %} diff --git a/proposals/templatetags/diff_tags.py b/proposals/templatetags/diff_tags.py index 30ea8da32..ffb0d62a9 100644 --- a/proposals/templatetags/diff_tags.py +++ b/proposals/templatetags/diff_tags.py @@ -4,14 +4,16 @@ register = template.Library() -@register.filter(name='zip_equalize_lists') +@register.filter(name="zip_equalize_lists") def zip_equalize_lists(a, b): """ A zip implementation which will not stop when reaching the end of the smallest list, but will append None's to the smaller list to fill the gap """ - a = list(a) - b = list(b) + + a = [] if a is None else list(a) + b = [] if b is None else list(b) + a_len = len(a) b_len = len(b) diff = abs(a_len - b_len) @@ -25,100 +27,3 @@ def zip_equalize_lists(a, b): b.append(None) return zip(a, b) - - -class ZippedSessionsNode(template.Node): - """ - This node handles adding a zipped list of all sessions for 2 given studies - If one study has more sessions than the other, None's will be added to - the other - """ - - def __init__(self, var_name, study, p_study): - self.var_name = var_name - self.study = template.Variable(study) - self.p_study = template.Variable(p_study) - - def render(self, context): - study = self.study.resolve(context) - p_study = self.p_study.resolve(context) - - sessions = [] - p_sessions = [] - - if study: - sessions = study.session_set.all() - - if p_study: - p_sessions = p_study.session_set.all() - - context[self.var_name] = zip_equalize_lists(sessions, p_sessions) - return u"" - - -@register.tag -def get_zipped_sessions_lists(parser, token): - """ - Adds a variable to the context with a zipped list of all sessions for - the provided studies. If one study has more sessions than the other, - None's will be added to the other - - Usage: - {% get_zipped_sessions_lists VARIABLE_NAME STUDY_OBJECT_1 STUDY_OBJECT_2 %} - params: - VARIABLE_NAME: the name of the variable to store the object in - STUDY_OBJECT_1: the variable which contains the first study object - STUDY_OBJECT_2: the variable which contains the second study object - """ - parts = token.split_contents() - - return ZippedSessionsNode(parts[1], parts[2], parts[3]) - - -class ZippedTasksNode(template.Node): - """ - This node handles adding a zipped list of all tasks for 2 given sessions - If one session has more tasks than the other, None's will be added to - the other - """ - - def __init__(self, var_name, session, p_session): - self.var_name = var_name - self.session = template.Variable(session) - self.p_session = template.Variable(p_session) - - def render(self, context): - session = self.session.resolve(context) - p_session = self.p_session.resolve(context) - - tasks = [] - p_tasks = [] - - if session: - tasks = session.task_set.all() - - if p_session: - p_tasks = p_session.task_set.all() - - context[self.var_name] = zip_equalize_lists(tasks, p_tasks) - return u"" - - -@register.tag -def get_zipped_tasks_lists(parser, token): - """ - Adds a variable to the context with a zipped list of all tasks for - the provided sessions. If one session has more tasks than the other, - None's will be added to the other - - Usage: - {% get_zipped_sessions_lists VARIABLE_NAME SESSION_OBJECT_1 - SESSION_OBJECT_2 %} - params: - VARIABLE_NAME: the name of the variable to store the object in - SESSION_OBJECT_1: the variable which contains the first session object - SESSION_OBJECT_2: the variable which contains the second session object - """ - parts = token.split_contents() - - return ZippedTasksNode(parts[1], parts[2], parts[3]) \ No newline at end of file diff --git a/proposals/templatetags/proposal_filters.py b/proposals/templatetags/proposal_filters.py index a323e32e5..d67684795 100644 --- a/proposals/templatetags/proposal_filters.py +++ b/proposals/templatetags/proposal_filters.py @@ -7,15 +7,17 @@ register = template.Library() + @register.filter -def needs_details(selected_values, field='needs_details'): +def needs_details(selected_values, field="needs_details"): for sv in selected_values: if getattr(sv, field): return True return False + @register.filter -def medical_traits(selected_values, field='medical_traits'): +def medical_traits(selected_values, field="medical_traits"): for sv in selected_values: if getattr(sv, field): return True @@ -24,24 +26,24 @@ def medical_traits(selected_values, field='medical_traits'): @register.filter def has_adults(study): - age_groups = study.age_groups.values_list('id', flat=True) + age_groups = study.age_groups.values_list("id", flat=True) return check_has_adults(age_groups) @register.filter def necessity_required(study): - age_groups = study.age_groups.values_list('id', flat=True) + age_groups = study.age_groups.values_list("id", flat=True) return check_necessity_required(study.proposal, age_groups, study.legally_incapable) @register.simple_tag def show_yesno(doubt=False): - result = '
      ' - result += '
    • {}
    • '.format('ja') - result += '
    • {}
    • '.format('nee') + result = "
        " + result += "
      • {}
      • ".format("ja") + result += "
      • {}
      • ".format("nee") if doubt: - result += '
      • {}
      • '.format('twijfel') - result += '
      ' + result += "
    • {}
    • ".format("twijfel") + result += "
    " return mark_safe(result) @@ -71,7 +73,7 @@ def render(self, context): ).objects.get(study=study) except (ObjectDoesNotExist, MultipleObjectsReturned): context[self.var_name] = None - return u"" + return "" @register.tag @@ -101,9 +103,13 @@ def __init__(self, var_name, study): def render(self, context): proposal = self.var_value.resolve(context) - context[self.var_name] = apps.get_model("studies", "Documents").objects.filter(proposal=proposal, study=None).all() + context[self.var_name] = ( + apps.get_model("studies", "Documents") + .objects.filter(proposal=proposal, study=None) + .all() + ) - return u"" + return "" @register.tag @@ -120,4 +126,3 @@ def get_extra_documents(parser, token): parts = token.split_contents() return ExtraDocumentsNode(parts[1], parts[2]) - diff --git a/proposals/tests/__init__.py b/proposals/tests/__init__.py new file mode 100644 index 000000000..6bb3af1f2 --- /dev/null +++ b/proposals/tests/__init__.py @@ -0,0 +1,2 @@ +from .misc_tests import * +from .proposal_submission_tests import * diff --git a/proposals/tests.py b/proposals/tests/misc_tests.py similarity index 52% rename from proposals/tests.py rename to proposals/tests/misc_tests.py index 2e4192ca8..0d8c57677 100644 --- a/proposals/tests.py +++ b/proposals/tests/misc_tests.py @@ -5,76 +5,104 @@ from django.core.files.uploadedfile import SimpleUploadedFile from django.conf import settings -from main.models import Setting, YES, NO +from main.models import Setting, YesNoDoubt from interventions.models import Intervention from observations.models import Observation from tasks.models import Session, Task, Registration from studies.models import Study, Recruitment -from .api.views import MyProposalsApiView -from .copy import copy_proposal -from .models import Proposal, Relation, Wmo, Institution -from .utils import generate_ref_number, check_local_facilities, generate_revision_ref_number - - -class BaseProposalTestCase(TestCase): - fixtures = ['relations', 'compensations', 'recruitments', 'settings', - 'registrations', 'groups', 'institutions'] +from proposals.api.views import MyProposalsApiView +from proposals.copy import copy_proposal +from proposals.models import Proposal, Relation, Wmo, Institution +from proposals.utils import ( + generate_ref_number, + check_local_facilities, + generate_revision_ref_number, +) + + +class MiscProposalTestCase(TestCase): + fixtures = [ + "relations", + "compensations", + "recruitments", + "settings", + "00_registrations", + "groups", + "institutions", + ] def setUp(self): - self.user = User.objects.create_user(username='test0101', email='test@test.com', password='secret') + self.user = User.objects.create_user( + username="test0101", email="test@test.com", password="secret" + ) self.secretary = User.objects.create_user( - username='secretarytest010101', - email='test@test.nl', - password='more_secret') - Group.objects.get(name=settings.GROUP_PRIMARY_SECRETARY).user_set.add(self.secretary) + username="secretarytest010101", email="test@test.nl", password="more_secret" + ) + Group.objects.get(name=settings.GROUP_PRIMARY_SECRETARY).user_set.add( + self.secretary + ) self.chamber = Group.objects.get(name=settings.GROUP_LINGUISTICS_CHAMBER) self.institution = Institution.objects.get(pk=1) self.chamber.user_set.add(self.secretary) self.relation = Relation.objects.get(pk=4) - self.p1 = Proposal.objects.create(title='p1', reference_number=generate_ref_number(), - date_start=datetime.now(), - created_by=self.user, - relation=self.relation, - reviewing_committee=self.chamber, - institution=self.institution) + self.p1 = Proposal.objects.create( + title="p1", + reference_number=generate_ref_number(), + date_start=datetime.now(), + created_by=self.user, + relation=self.relation, + reviewing_committee=self.chamber, + institution=self.institution, + ) self.p1.applicants.add(self.user) self.p1.save() -class ProposalTestCase(BaseProposalTestCase): +class ProposalTestCase(MiscProposalTestCase): def test_reference_number(self): current_year = str(datetime.now().year) # Add a proposal for the same user, check new reference number ref_number = generate_ref_number() - p2 = Proposal.objects.create(title='p2', reference_number=ref_number, - date_start=datetime.now(), - created_by=self.user, - relation=self.relation, - reviewing_committee=self.chamber, - institution=self.institution) - self.assertEqual(ref_number, current_year[2:] + '-002-01') + p2 = Proposal.objects.create( + title="p2", + reference_number=ref_number, + date_start=datetime.now(), + created_by=self.user, + relation=self.relation, + reviewing_committee=self.chamber, + institution=self.institution, + ) + self.assertEqual(ref_number, current_year[2:] + "-002-01") # Delete a proposal, check new reference number p2.delete() ref_number2 = generate_ref_number() - Proposal.objects.create(title='p2', reference_number=ref_number2, - date_start=datetime.now(), - created_by=self.user, - relation=self.relation, - reviewing_committee=self.chamber, - institution=self.institution) - self.assertEqual(ref_number2, current_year[2:] + '-002-01') + Proposal.objects.create( + title="p2", + reference_number=ref_number2, + date_start=datetime.now(), + created_by=self.user, + relation=self.relation, + reviewing_committee=self.chamber, + institution=self.institution, + ) + self.assertEqual(ref_number2, current_year[2:] + "-002-01") # Add a proposal for another user - user2 = User.objects.create_user(username='test0102', email='test@test.com', password='secret') - p3 = Proposal.objects.create(title='p3', reference_number=generate_ref_number(), - date_start=datetime.now(), - created_by=user2, - relation=self.relation, - reviewing_committee=self.chamber, - institution=self.institution) - self.assertEqual(p3.reference_number, current_year[2:] + '-003-01') + user2 = User.objects.create_user( + username="test0102", email="test@test.com", password="secret" + ) + p3 = Proposal.objects.create( + title="p3", + reference_number=generate_ref_number(), + date_start=datetime.now(), + created_by=user2, + relation=self.relation, + reviewing_committee=self.chamber, + institution=self.institution, + ) + self.assertEqual(p3.reference_number, current_year[2:] + "-003-01") def test_revision_reference_number(self): current_year = str(datetime.now().year) @@ -82,26 +110,32 @@ def test_revision_reference_number(self): # Add a revision proposal for p1, check new reference number # Should be 01-02 (first proposal, second version) ref_number = generate_revision_ref_number(self.p1) - p2 = Proposal.objects.create(title='p2', reference_number=ref_number, - date_start=datetime.now(), - created_by=self.user, - relation=self.relation, - reviewing_committee=self.chamber, - is_revision=True, - parent=self.p1, - institution=self.institution) - self.assertEqual(ref_number, current_year[2:] + '-001-02') + p2 = Proposal.objects.create( + title="p2", + reference_number=ref_number, + date_start=datetime.now(), + created_by=self.user, + relation=self.relation, + reviewing_committee=self.chamber, + is_revision=True, + parent=self.p1, + institution=self.institution, + ) + self.assertEqual(ref_number, current_year[2:] + "-001-02") # Add a proposal for the same user, check new reference number # Should be 02-01 (second proposal, first version) ref_number = generate_ref_number() - p3 = Proposal.objects.create(title='p3', reference_number=ref_number, - date_start=datetime.now(), - created_by=self.user, - relation=self.relation, - reviewing_committee=self.chamber, - institution=self.institution) - self.assertEqual(ref_number, current_year[2:] + '-002-01') + p3 = Proposal.objects.create( + title="p3", + reference_number=ref_number, + date_start=datetime.now(), + created_by=self.user, + relation=self.relation, + reviewing_committee=self.chamber, + institution=self.institution, + ) + self.assertEqual(ref_number, current_year[2:] + "-002-01") # Add new proposal using an old 3-part ref.number and make a revision # number using the proposal. @@ -109,45 +143,49 @@ def test_revision_reference_number(self): # (The year in the ref.num. and the creation_date won't line up, # but in this case it doesn't matter as generate_revision_ref_number # only looks at the ref.num. of the parent). - p4 = Proposal.objects.create(title='p4', - reference_number='97-001-01', - date_start=datetime.now(), - created_by=self.user, - relation=self.relation, - reviewing_committee=self.chamber, - institution=self.institution) + p4 = Proposal.objects.create( + title="p4", + reference_number="97-001-01", + date_start=datetime.now(), + created_by=self.user, + relation=self.relation, + reviewing_committee=self.chamber, + institution=self.institution, + ) ref_number = generate_revision_ref_number(p4) - p2 = Proposal.objects.create(title='p5', reference_number=ref_number, - date_start=datetime.now(), - created_by=self.user, - relation=self.relation, - reviewing_committee=self.chamber, - is_revision=True, - parent=p4, - institution=self.institution) - self.assertEqual(ref_number, '97-001-02') + p2 = Proposal.objects.create( + title="p5", + reference_number=ref_number, + date_start=datetime.now(), + created_by=self.user, + relation=self.relation, + reviewing_committee=self.chamber, + is_revision=True, + parent=p4, + institution=self.institution, + ) + self.assertEqual(ref_number, "97-001-02") # Generate a new revision ref.number using the original proposal # This tests whether the right version number is created even if the # parent isn't the latest version # Should be 01-03-1997 (First proposal in 1997, third version) ref_number = generate_revision_ref_number(p4) - self.assertEqual(ref_number, '97-001-03') - + self.assertEqual(ref_number, "97-001-03") def test_status(self): proposal = self.p1 - self.assertEqual(proposal.status, Proposal.DRAFT) + self.assertEqual(proposal.status, Proposal.Statuses.DRAFT) - wmo = Wmo.objects.create(proposal=proposal, metc=YES) - self.assertEqual(proposal.wmo.status, Wmo.WAITING) - wmo.metc = NO + wmo = Wmo.objects.create(proposal=proposal, metc=YesNoDoubt.YES) + self.assertEqual(proposal.wmo.status, Wmo.WMOStatuses.WAITING) + wmo.metc = YesNoDoubt.NO wmo.save() - self.assertEqual(proposal.wmo.status, Wmo.NO_WMO) - #self.assertEqual(proposal.continue_url(), '/studies/create/1/') + self.assertEqual(proposal.wmo.status, Wmo.WMOStatuses.NO_WMO) + # self.assertEqual(proposal.continue_url(), '/studies/create/1/') s = Study.objects.create(proposal=proposal, order=1) - #self.assertEqual(proposal.continue_url(), '/studies/design/1/') + # self.assertEqual(proposal.continue_url(), '/studies/design/1/') s.sessions_number = 2 s.save() @@ -157,8 +195,8 @@ def test_status(self): s1.tasks_number = 2 s1.save() - s1_t1 = Task.objects.create(session=s1, order=1, name='t1') - Task.objects.create(session=s1, order=2, name='t2') + s1_t1 = Task.objects.create(session=s1, order=1, name="t1") + Task.objects.create(session=s1, order=2, name="t2") s1.tasks_duration = 45 s1.save() @@ -181,7 +219,10 @@ def test_check_local_facilities(self): facs = check_local_facilities(self.p1) self.assertEqual(len(facs), 1) - self.assertSetEqual(facs[Recruitment._meta.verbose_name], set([r.description for r in recruitments])) + self.assertSetEqual( + facs[Recruitment._meta.verbose_name], + set([r.description for r in recruitments]), + ) # If we remove local Recruitment, we should again return no facilities s.recruitment.set(Recruitment.objects.filter(is_local=False)) @@ -200,7 +241,9 @@ def test_check_local_facilities(self): facs = check_local_facilities(self.p1) self.assertEqual(len(facs), 1) - self.assertSetEqual(facs[Setting._meta.verbose_name], set([st.description for st in settings])) + self.assertSetEqual( + facs[Setting._meta.verbose_name], set([st.description for st in settings]) + ) # If we add a Sessions part, we should return facilities when we add local Registrations s.has_sessions = True @@ -211,7 +254,7 @@ def test_check_local_facilities(self): s1.tasks_number = 2 s1.save() - s1_t1 = Task.objects.create(session=s1, order=1, name='t1') + s1_t1 = Task.objects.create(session=s1, order=1, name="t1") registrations = Registration.objects.filter(is_local=True) s1_t1.registrations.set(registrations) @@ -219,43 +262,51 @@ def test_check_local_facilities(self): facs = check_local_facilities(self.p1) self.assertEqual(len(facs), 2) - self.assertSetEqual(facs[Registration._meta.verbose_name], set([r.description for r in registrations])) + self.assertSetEqual( + facs[Registration._meta.verbose_name], + set([r.description for r in registrations]), + ) -class ProposalsViewTestCase(BaseProposalTestCase): +class ProposalsViewTestCase(MiscProposalTestCase): def setUp(self): super(ProposalsViewTestCase, self).setUp() self.factory = RequestFactory() def test_supervisor(self): - request = self.factory.get('/proposals/api/my_archive') + request = self.factory.get("/proposals/api/my_archive") request.user = self.user response = MyProposalsApiView.as_view()(request) self.assertEqual(response.status_code, 200) - self.assertEqual(response.data['items'][0]['pk'], self.p1.pk) + self.assertEqual(response.data["items"][0]["pk"], self.p1.pk) # Add a Proposal for another User - user2 = User.objects.create_user(username='test0102', email='test@test.com', password='secret') - p2 = Proposal.objects.create(title='p3', reference_number=generate_ref_number(), - date_start=datetime.now(), - created_by=user2, - relation=self.relation, - reviewing_committee=self.chamber, - institution=self.institution) + user2 = User.objects.create_user( + username="test0102", email="test@test.com", password="secret" + ) + p2 = Proposal.objects.create( + title="p3", + reference_number=generate_ref_number(), + date_start=datetime.now(), + created_by=user2, + relation=self.relation, + reviewing_committee=self.chamber, + institution=self.institution, + ) p2.applicants.add(user2) p2.save() # Sanity test: response should still be the same response = MyProposalsApiView.as_view()(request) self.assertEqual(response.status_code, 200) - self.assertEqual(response.data['items'][0]['pk'], self.p1.pk) + self.assertEqual(response.data["items"][0]["pk"], self.p1.pk) # Second user should only see his Proposal request.user = user2 response = MyProposalsApiView.as_view()(request) self.assertEqual(response.status_code, 200) - self.assertEqual(response.data['items'][0]['pk'], p2.pk) + self.assertEqual(response.data["items"][0]["pk"], p2.pk) # If we set self.user to be the supervisor, he should see both Proposals p2.supervisor = self.user @@ -265,46 +316,42 @@ def test_supervisor(self): response = MyProposalsApiView.as_view()(request) self.assertEqual(response.status_code, 200) self.assertSequenceEqual( - [ - response.data['items'][0]['pk'], - response.data['items'][1]['pk'] - ], - [self.p1.pk, p2.pk] + [response.data["items"][0]["pk"], response.data["items"][1]["pk"]], + [self.p1.pk, p2.pk], ) -class WmoTestCase(BaseProposalTestCase): +class WmoTestCase(MiscProposalTestCase): def setUp(self): super(WmoTestCase, self).setUp() - self.wmo = Wmo.objects.create(proposal=self.p1, metc=NO) + self.wmo = Wmo.objects.create(proposal=self.p1, metc=YesNoDoubt.NO) def test_status(self): - self.assertEqual(self.wmo.status, Wmo.NO_WMO) + self.assertEqual(self.wmo.status, Wmo.WMOStatuses.NO_WMO) - self.wmo.metc = YES + self.wmo.metc = YesNoDoubt.YES self.wmo.save() - self.assertEqual(self.wmo.status, Wmo.WAITING) + self.assertEqual(self.wmo.status, Wmo.WMOStatuses.WAITING) self.wmo.metc_decision = True self.wmo.save() - self.assertEqual(self.wmo.status, Wmo.WAITING) + self.assertEqual(self.wmo.status, Wmo.WMOStatuses.WAITING) - self.wmo.metc_decision_pdf = SimpleUploadedFile('test.pdf', b'contents') + self.wmo.metc_decision_pdf = SimpleUploadedFile("test.pdf", b"contents") self.wmo.save() - self.assertEqual(self.wmo.status, Wmo.JUDGED) - + self.assertEqual(self.wmo.status, Wmo.WMOStatuses.JUDGED) -class CopyTestCase(BaseProposalTestCase): +class CopyTestCase(MiscProposalTestCase): def setUp(self): super().setUp() self.wmo_1 = Wmo.objects.create( proposal=self.p1, - metc=Wmo.JUDGED, + metc=Wmo.WMOStatuses.JUDGED, ) self.study_1 = Study.objects.create( @@ -336,32 +383,20 @@ def setUp(self): def test_parent_present_for_rev(self): """Test if parent is set when making a revision/amendment copy""" - p2 = copy_proposal( - self.p1, - True, - self.user - ) + p2 = copy_proposal(self.p1, True, self.user) self.assertIsNotNone(p2.parent) self.assertEqual(p2.parent.pk, self.p1.pk) def test_parent_missing_for_copy(self): """Test if parent is missing if making a regular copy""" - p2 = copy_proposal( - self.p1, - False, - self.user - ) + p2 = copy_proposal(self.p1, False, self.user) self.assertIsNone(p2.parent) def test_related_copying(self): """Test if related objects are copied during copying""" - p2 = copy_proposal( - self.p1, - False, - self.user - ) + p2 = copy_proposal(self.p1, False, self.user) self.assertEqual(p2.study_set.count(), 1) diff --git a/proposals/tests/proposal_submission_tests.py b/proposals/tests/proposal_submission_tests.py new file mode 100644 index 000000000..40a215baa --- /dev/null +++ b/proposals/tests/proposal_submission_tests.py @@ -0,0 +1,237 @@ +import logging + +from django.contrib.auth.models import User, Group, AnonymousUser +from django.conf import settings +from django.test import TestCase + +from main.tests import BaseViewTestCase +from proposals.models import Proposal, Relation +from reviews.models import Review + +from proposals.views.proposal_views import ( + ProposalSubmit, + ProposalSubmitPreApproved, + ProposalSubmitPreAssessment, +) + + +class BaseProposalTestCase(TestCase): + fixtures = [ + "groups", + "settings", + "registrations", + "fundings", + "institutions", + "relations", + "studentcontexts", + "agegroups", + "compensations", + "recruitments", + "specialdetails", + "traits", + "00_registrations", + "01_registrationkinds", + "testing/test_users", + "testing/test_proposals", + ] + + def setUp(self): + self.setup_users() + self.setup_proposal() + + # Disable logging warnings and all levels below + # Our (pdf) code logs warnings that are not relevant to the tests + # ERROR and CRITICAL are still logged + logging.disable(logging.WARN) + + def setup_users(self): + self.secretary = User.objects.create_user( + "secretary", + "test@test.com", + "secret", + first_name="The", + last_name="Secretary", + ) + self.c1 = User.objects.create_user("c1", "test@test.com", "secret") + self.c2 = User.objects.create_user("c2", "test@test.com", "secret") + self.user = User.objects.create_user( + "user", "test@test.com", "secret", first_name="John", last_name="Doe" + ) + self.supervisor = User.objects.create_user( + "supervisor", "test@test.com", "secret", first_name="Jane", last_name="Roe" + ) + + self.secretary.groups.add( + Group.objects.get(name=settings.GROUP_PRIMARY_SECRETARY) + ) + self.secretary.groups.add(Group.objects.get(name=settings.GROUP_SECRETARY)) + + self.c1.groups.add(Group.objects.get(name=settings.GROUP_LINGUISTICS_CHAMBER)) + self.c2.groups.add(Group.objects.get(name=settings.GROUP_LINGUISTICS_CHAMBER)) + + def setup_proposal(self): + """ + Load our test proposals from a fixture, then add our user as + an applicant to each of them. + + Please note, this currently uses a mish-mash of both fixtures + and programmatically created users and objects. + """ + self.proposal = Proposal.objects.get(pk=1) + self.proposal.applicants.add(self.user) + self.proposal.save() + self.pre_assessment = Proposal.objects.get(pk=2) + self.pre_assessment.applicants.add(self.user) + self.pre_assessment.save() + self.pre_approval = Proposal.objects.get(pk=3) + self.pre_approval.applicants.add(self.user) + self.pre_approval.save() + + def refresh(self): + """Refresh objects from DB. This is sometimes necessary if you access + attributes you previously read during the test and don't want to + receive a cached value.""" + self.proposal.refresh_from_db() + + +class ProposalSubmitTestCase( + BaseViewTestCase, + BaseProposalTestCase, +): + view_class = ProposalSubmit + + def get_view_path(self): + pk = self.proposal.pk + return f"/proposals/submit/{pk}/" + + def get_view_args(self): + return {"pk": self.proposal.pk} + + def get_post_data(self): + return { + "inform_local_staff": True, + "embargo": True, + "comments": "asdf", + "embargo_end_date": "2025-01-01", + } + + def test_access( + self, + ): + # NB: The proposal creator does not have access by default + # Be sure to add them to the applicants list as well. + self.assertEqual( + self.check_access( + self.proposal.created_by, + ), + True, + ) + self.assertEqual( + self.check_access( + AnonymousUser, + ), + False, + ) + + def test_submission_unsupervised(self): + """ + Tests the following: + - The current proposal is a draft + - An applicant can submit a proposal that has no errors + - Because there is no supervisor, a new review is created + in the assignment stage. + """ + # Sanity checks to start + self.assertEqual( + self.proposal.status, + self.proposal.Statuses.DRAFT, + ) + self.assertEqual( + self.proposal.latest_review(), + None, + ) + # POST and check status code + self.client.force_login(self.user) + page = self.post( + self.get_post_data(), + user=self.user, + ) + self.assertIn(page.status_code, [302, 200]) + self.refresh() + # Post-submission tests + self.assertNotEqual( + self.proposal.status, + self.proposal.Statuses.DRAFT, + ) + self.assertNotEqual( + self.proposal.latest_review(), + None, + ) + self.assertEqual( + self.proposal.latest_review().stage, + Review.Stages.ASSIGNMENT, + ) + + def test_proposal_supervised(self): + """ + Tests the following: + - The current proposal is a draft + - An applicant can submit a proposal that has no errors + - Because there is a supervisor, a new review is created + in the supervisor stage. + """ + # Select the PHD relation, which needs a supervisor + # but doesn't check for a study/course + self.proposal.relation = Relation.objects.get(pk=4) + self.proposal.supervisor = self.supervisor + self.proposal.save() + # Sanity checks to start + self.assertEqual( + self.proposal.status, + self.proposal.Statuses.DRAFT, + ) + self.assertEqual( + self.proposal.latest_review(), + None, + ) + # POST and check status code + self.client.force_login(self.user) + page = self.post( + self.get_post_data(), + user=self.user, + ) + self.assertIn(page.status_code, [302, 200]) + self.refresh() + # Post-submission tests + self.assertNotEqual( + self.proposal.status, + self.proposal.Statuses.DRAFT, + ) + self.assertNotEqual( + self.proposal.latest_review(), + None, + ) + self.assertEqual( + self.proposal.latest_review().stage, + Review.Stages.SUPERVISOR, + ) + + +class PreassessmentSubmitTestCase( + ProposalSubmitTestCase, +): + view_class = ProposalSubmitPreAssessment + + def setUp(self): + super().setUp() + self.proposal = self.pre_assessment + + +class PreapprovedSubmitTestCase( + ProposalSubmitTestCase, +): + view_class = ProposalSubmitPreApproved + + def setUp(self): + super().setUp() + self.proposal = self.pre_approval diff --git a/proposals/translation.py b/proposals/translation.py index 36fbdc94f..0c3f26eb6 100644 --- a/proposals/translation.py +++ b/proposals/translation.py @@ -5,18 +5,19 @@ @register(Funding) class FundingTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) @register(Institution) class FundingTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) @register(Relation) class RelationTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) + @register(StudentContext) class RelationTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) diff --git a/proposals/urls.py b/proposals/urls.py index d7dcd56e5..8d1ec593a 100644 --- a/proposals/urls.py +++ b/proposals/urls.py @@ -1,179 +1,296 @@ from django.urls import path, include -from .views.proposal_views import CompareDocumentsView, MyConceptsView, \ - MyPracticeView, \ - MySubmittedView, MyCompletedView, MySupervisedView, MyProposalsView, \ - ProposalCreate, ProposalUpdate, ProposalDelete, ProposalStart, \ - ProposalDataManagement, ProposalSubmit, ProposalSubmitted, \ - ProposalConfirmation, ProposalCopy, ProposalCopyRevision, \ - ProposalDifference, ProposalAsPdf, ProposalCreatePreAssessment, \ - ProposalUpdatePreAssessment, ProposalStartPreAssessment, \ - ProposalSubmitPreAssessment, ProposalSubmittedPreAssessment, \ - ProposalCreatePractice, ProposalUpdatePractice, ProposalStartPractice, \ - ChangeArchiveStatusView, ProposalsExportView, ProposalStartPreApproved, \ - ProposalCreatePreApproved, ProposalSubmittedPreApproved, \ - ProposalSubmitPreApproved, ProposalUpdatePreApproved, \ - ProposalUsersOnlyArchiveView, \ - ProposalCopyAmendment, ProposalsPublicArchiveView, \ - ProposalUpdateDataManagement, TranslatedConsentFormsView +from .views.proposal_views import ( + CompareDocumentsView, + MyConceptsView, + MyPracticeView, + MySubmittedView, + MyCompletedView, + MySupervisedView, + MyProposalsView, + ProposalCreate, + ProposalUpdate, + ProposalDelete, + ProposalStart, + ProposalDataManagement, + ProposalSubmit, + ProposalSubmitted, + ProposalConfirmation, + ProposalCopy, + ProposalCopyRevision, + ProposalDifference, + ProposalAsPdf, + ProposalCreatePreAssessment, + ProposalUpdatePreAssessment, + ProposalStartPreAssessment, + ProposalSubmitPreAssessment, + ProposalSubmittedPreAssessment, + ProposalCreatePractice, + ProposalUpdatePractice, + ProposalStartPractice, + ChangeArchiveStatusView, + ProposalsExportView, + ProposalStartPreApproved, + ProposalCreatePreApproved, + ProposalSubmittedPreApproved, + ProposalSubmitPreApproved, + ProposalUpdatePreApproved, + ProposalUsersOnlyArchiveView, + ProposalCopyAmendment, + ProposalsPublicArchiveView, + ProposalUpdateDataManagement, + TranslatedConsentFormsView, + ProposalUpdateDateStart, +) from .views.study_views import StudyStart, StudyConsent -from .views.wmo_views import WmoCreate, WmoUpdate, \ - WmoApplication, WmoCheck, check_wmo, \ - WmoCreatePreAssessment, WmoUpdatePreAssessment, WmoApplicationPreAssessment +from .views.wmo_views import ( + WmoCreate, + WmoUpdate, + WmoApplication, + WmoCheck, + check_wmo, + WmoCreatePreAssessment, + WmoUpdatePreAssessment, + WmoApplicationPreAssessment, +) -app_name = 'proposals' +app_name = "proposals" urlpatterns = [ - path('api/', include('proposals.api.urls', namespace='api')), + path("api/", include("proposals.api.urls", namespace="api")), # List views - path('archive/', include([ - path('public/', ProposalsPublicArchiveView.as_view(), - name='public_archive'), - path('export/', ProposalsExportView.as_view(), name='archive_export'), - path('export//', ProposalsExportView.as_view(), - name='archive_export'), - path('archive_status//', ChangeArchiveStatusView.as_view(), - name='archive_status'), - # WARNING! This one needs to be LAST in the list. (Django goes - # through the list and picks the first one that fits, and the regex - # will always fit for the other 2 URL's, effectively superseding them - # if it's above them). - path('/', ProposalUsersOnlyArchiveView.as_view(), - name='archive'), - ])), - - path('my_concepts/', MyConceptsView.as_view(), name='my_concepts'), - path('my_practice/', MyPracticeView.as_view(), name='my_practice'), - path('my_submitted/', MySubmittedView.as_view(), name='my_submitted'), - path('my_completed/', MyCompletedView.as_view(), name='my_completed'), - path('my_supervised/', MySupervisedView.as_view(), name='my_supervised'), - path('my_archive/', MyProposalsView.as_view(), name='my_archive'), - + path( + "archive/", + include( + [ + path( + "public/", + ProposalsPublicArchiveView.as_view(), + name="public_archive", + ), + path("export/", ProposalsExportView.as_view(), name="archive_export"), + path( + "export//", + ProposalsExportView.as_view(), + name="archive_export", + ), + path( + "archive_status//", + ChangeArchiveStatusView.as_view(), + name="archive_status", + ), + # WARNING! This one needs to be LAST in the list. (Django goes + # through the list and picks the first one that fits, and the regex + # will always fit for the other 2 URL's, effectively superseding them + # if it's above them). + path( + "/", + ProposalUsersOnlyArchiveView.as_view(), + name="archive", + ), + ] + ), + ), + path("my_concepts/", MyConceptsView.as_view(), name="my_concepts"), + path("my_practice/", MyPracticeView.as_view(), name="my_practice"), + path("my_submitted/", MySubmittedView.as_view(), name="my_submitted"), + path("my_completed/", MyCompletedView.as_view(), name="my_completed"), + path("my_supervised/", MySupervisedView.as_view(), name="my_supervised"), + path("my_archive/", MyProposalsView.as_view(), name="my_archive"), # Proposal - path('create/', include([ - path('', ProposalCreate.as_view(), name='create'), - path('pre/', ProposalCreatePreAssessment.as_view(), - name='create_pre'), - path('practice//', ProposalCreatePractice.as_view(), - name='create_practice'), - path('pre_approved/', ProposalCreatePreApproved.as_view(), - name='create_pre_approved'), - ])), - path('update//', include([ - path('', ProposalUpdate.as_view(), name='update'), - path('pre/', ProposalUpdatePreAssessment.as_view(), - name='update_pre'), - path('practice/', ProposalUpdatePractice.as_view(), - name='update_practice'), - path('pre_approved/', ProposalUpdatePreApproved.as_view(), - name='update_pre_approved'), - ])), - path('delete//', ProposalDelete.as_view(), name='delete'), - - path('start/', include([ - path('', ProposalStart.as_view(), name='start'), - path('pre/', ProposalStartPreAssessment.as_view(), name='start_pre'), - path('practice/', ProposalStartPractice.as_view(), - name='start_practice'), - path('pre_approved/', ProposalStartPreApproved.as_view(), - name='start_pre_approved'), - ])), - - path('data_management//', ProposalDataManagement.as_view(), - name='data_management'), - path('update_data_management//', ProposalUpdateDataManagement.as_view(), - name='update_data_management'), - - path('submit//', include([ - path('', ProposalSubmit.as_view(), name='submit'), - path('pre/', ProposalSubmitPreAssessment.as_view(), - name='submit_pre'), - path('pre_approved/', ProposalSubmitPreApproved.as_view(), - name='submit_pre_approved'), - ])), - - path('submitted//', include([ - path('', ProposalSubmitted.as_view(), name='submitted'), - path('pre/', ProposalSubmittedPreAssessment.as_view(), - name='submitted_pre'), - path('pre_approved/', ProposalSubmittedPreApproved.as_view(), - name='submitted_pre_approved') - ])), - - path('confirm//', ProposalConfirmation.as_view(), - name='confirmation'), - - path('study_start//', StudyStart.as_view(), - name='study_start'), - - path('consent//', StudyConsent.as_view(), name='consent'), - - path('translated//', TranslatedConsentFormsView.as_view(), name='translated'), - - path('copy/', include([ - path('', ProposalCopy.as_view(), name='copy'), - path('revision/', ProposalCopyRevision.as_view(), - name='copy_revision'), - path('amendment/', ProposalCopyAmendment.as_view(), - name='copy_amendment'), - ])), - path('diff//', ProposalDifference.as_view(), name='diff'), - - path('pdf//', ProposalAsPdf.as_view(), name='pdf'), - + path( + "create/", + include( + [ + path("", ProposalCreate.as_view(), name="create"), + path("pre/", ProposalCreatePreAssessment.as_view(), name="create_pre"), + path( + "practice//", + ProposalCreatePractice.as_view(), + name="create_practice", + ), + path( + "pre_approved/", + ProposalCreatePreApproved.as_view(), + name="create_pre_approved", + ), + ] + ), + ), + path( + "update//", + include( + [ + path("", ProposalUpdate.as_view(), name="update"), + path("pre/", ProposalUpdatePreAssessment.as_view(), name="update_pre"), + path( + "practice/", + ProposalUpdatePractice.as_view(), + name="update_practice", + ), + path( + "pre_approved/", + ProposalUpdatePreApproved.as_view(), + name="update_pre_approved", + ), + ] + ), + ), + path("delete//", ProposalDelete.as_view(), name="delete"), + path( + "start/", + include( + [ + path("", ProposalStart.as_view(), name="start"), + path("pre/", ProposalStartPreAssessment.as_view(), name="start_pre"), + path( + "practice/", ProposalStartPractice.as_view(), name="start_practice" + ), + path( + "pre_approved/", + ProposalStartPreApproved.as_view(), + name="start_pre_approved", + ), + ] + ), + ), + path( + "data_management//", + ProposalDataManagement.as_view(), + name="data_management", + ), + path( + "update_data_management//", + ProposalUpdateDataManagement.as_view(), + name="update_data_management", + ), + path( + "update_date_start//", + ProposalUpdateDateStart.as_view(), + name="update_date_start", + ), + path( + "submit//", + include( + [ + path("", ProposalSubmit.as_view(), name="submit"), + path("pre/", ProposalSubmitPreAssessment.as_view(), name="submit_pre"), + path( + "pre_approved/", + ProposalSubmitPreApproved.as_view(), + name="submit_pre_approved", + ), + ] + ), + ), + path( + "submitted//", + include( + [ + path("", ProposalSubmitted.as_view(), name="submitted"), + path( + "pre/", + ProposalSubmittedPreAssessment.as_view(), + name="submitted_pre", + ), + path( + "pre_approved/", + ProposalSubmittedPreApproved.as_view(), + name="submitted_pre_approved", + ), + ] + ), + ), + path("confirm//", ProposalConfirmation.as_view(), name="confirmation"), + path("study_start//", StudyStart.as_view(), name="study_start"), + path("consent//", StudyConsent.as_view(), name="consent"), + path( + "translated//", TranslatedConsentFormsView.as_view(), name="translated" + ), + path( + "copy/", + include( + [ + path("", ProposalCopy.as_view(), name="copy"), + path("revision/", ProposalCopyRevision.as_view(), name="copy_revision"), + path( + "amendment/", ProposalCopyAmendment.as_view(), name="copy_amendment" + ), + ] + ), + ), + path("diff//", ProposalDifference.as_view(), name="diff"), + path("pdf//", ProposalAsPdf.as_view(), name="pdf"), # WMO - path('wmo/create//', include([ - path('', WmoCreate.as_view(), name='wmo_create'), - path('pre/', WmoCreatePreAssessment.as_view(), name='wmo_create_pre'), - ])), - path('wmo/update//', include([ - path('', WmoUpdate.as_view(), name='wmo_update'), - path('pre/', WmoUpdatePreAssessment.as_view(), name='wmo_update_pre'), - ])), - path('wmo/application//', include([ - path('', WmoApplication.as_view(), name='wmo_application'), - path('pre/', WmoApplicationPreAssessment.as_view(), name='wmo_application_pre'), - ])), - path('wmo/check/', WmoCheck.as_view(), name='wmo_check'), - path('wmo/check_js/', check_wmo, name='check_wmo'), - path( - 'compare/', include([ - path( - 'consent////', - CompareDocumentsView.as_view(), - { - 'type': 'documents' - }, - name='compare_documents', - ), - path( - 'observation///approval_document/', - CompareDocumentsView.as_view(), - { - 'type': 'observation', - 'attribute': 'approval_document', - }, - name='compare_observation_approval', - ), - path( - 'wmo///decision/', - CompareDocumentsView.as_view(), - { - 'type': 'wmo', - 'attribute': 'metc_decision_pdf', - }, - name='compare_wmo_decision', - ), - path( - 'study////', - CompareDocumentsView.as_view(), - { - 'type': 'proposal' - }, - name='compare_proposal_docs', - ), - ]) + "wmo/create//", + include( + [ + path("", WmoCreate.as_view(), name="wmo_create"), + path("pre/", WmoCreatePreAssessment.as_view(), name="wmo_create_pre"), + ] + ), + ), + path( + "wmo/update//", + include( + [ + path("", WmoUpdate.as_view(), name="wmo_update"), + path("pre/", WmoUpdatePreAssessment.as_view(), name="wmo_update_pre"), + ] + ), + ), + path( + "wmo/application//", + include( + [ + path("", WmoApplication.as_view(), name="wmo_application"), + path( + "pre/", + WmoApplicationPreAssessment.as_view(), + name="wmo_application_pre", + ), + ] + ), + ), + path("wmo/check/", WmoCheck.as_view(), name="wmo_check"), + path("wmo/check_js/", check_wmo, name="check_wmo"), + path( + "compare/", + include( + [ + path( + "consent////", + CompareDocumentsView.as_view(), + {"type": "documents"}, + name="compare_documents", + ), + path( + "observation///approval_document/", + CompareDocumentsView.as_view(), + { + "type": "observation", + "attribute": "approval_document", + }, + name="compare_observation_approval", + ), + path( + "wmo///decision/", + CompareDocumentsView.as_view(), + { + "type": "wmo", + "attribute": "metc_decision_pdf", + }, + name="compare_wmo_decision", + ), + path( + "study////", + CompareDocumentsView.as_view(), + {"type": "proposal"}, + name="compare_proposal_docs", + ), + ] + ), ), ] diff --git a/proposals/utils/__init__.py b/proposals/utils/__init__.py index 4661c3735..be19d3292 100644 --- a/proposals/utils/__init__.py +++ b/proposals/utils/__init__.py @@ -1 +1,2 @@ -from .proposal_utils import * \ No newline at end of file +from .proposal_utils import * +from .pdf_diff_logic import * diff --git a/proposals/utils/pdf_diff_logic.py b/proposals/utils/pdf_diff_logic.py new file mode 100644 index 000000000..032ba5076 --- /dev/null +++ b/proposals/utils/pdf_diff_logic.py @@ -0,0 +1,1253 @@ +from datetime import date +from copy import copy + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.template.loader import get_template +from django.utils.html import format_html +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext as _ + +from proposals.templatetags.proposal_filters import ( + needs_details, + medical_traits, + necessity_required, + has_adults, +) +from proposals.templatetags.diff_tags import zip_equalize_lists + + +class BaseSection: + """This is the main class, from which sections are constructed. + It receives one object, such as a proposal or sub-objects of proposals. + The most important methods are render and make_rows. Make rows makes use of get_row_field, + which gets overwritten for specific sections, if logic is involved. + For certain sections, there can be a sub-title, such as for studies or other cases. + These are produced in the get_sub_title method and require a specific string, based on + the type of sub-title required. The options are: + - 'study' + - 'session' + - 'task' + -'task_overview' + These arguments are passed in overwritten __init__() methods, when applicable. + """ + + section_title = None + row_fields = None + + def __init__(self, obj): + self.obj = obj + self.sub_title = None + + def make_rows(self): + rows = [self.make_row_for_field(field) for field in self.get_row_fields()] + return rows + + def make_row_for_field(self, field): + if field in self.get_row_fields(): + return Row(self.obj, field) + else: + return None + + def get_row_fields(self): + return self.row_fields + + def render(self, context): + context = context.flatten() + template = get_template("proposals/table_with_header.html") + if self.sub_title is not None: + context.update( + { + "sub_title": self.sub_title, + } + ) + context.update( + { + "section_title": self.section_title, + "rows": self.make_rows(), + } + ) + return template.render(context) + + def get_sub_title(self, obj, sub_title_type): + return SubTitle(obj, sub_title_type).sub_title + + +class DiffSection: + """For the diff page, sections are constructed by comparing two section objects. + for instance: + GeneralSection(old_proposal), GeneralSection(new_proposal) + + It mostly uses the make_rows methods, but also some other class variables from these objects. + If a section is missing from a revision or an original proposal, this will be reperesented by + None, and a warning and some formatting info get passed to the template as well. + + Some parts of this were written with the idea of allowing more than two objects to be compared, + however, I did not end up pursuing this idea until the end.""" + + def __init__(self, old_section, new_section): + self.old_section = old_section + self.new_section = new_section + if self.old_section is None: + self.warning = _( + "Dit onderdeel is nieuw in de revisie en bestond niet in de originele aanvraag." + ) + self.missing_object = "old" + self.sub_title = self.new_section.sub_title + self.section_title = self.new_section.section_title + elif self.new_section is None: + self.warning = _( + "Dit onderdeel bestond in de originele aanvraag, maar niet meer in de revisie." + ) + self.missing_object = "new" + self.sub_title = self.old_section.sub_title + self.section_title = self.old_section.section_title + else: + self.warning = None + self.missing_object = None + self.sub_title = self.old_section.sub_title + self.section_title = self.old_section.section_title + self.rows = self.make_diff_rows() + + def make_diff_rows(self): + """This function generates rows for diff instances.""" + + if self.missing_object is not None: + # If there is a missing object, the template can just use the make_rows function + # of the object that is not missing. + if self.missing_object == "old": + rows = self.new_section.make_rows() + else: + rows = self.old_section.make_rows() + return rows + else: + all_fields = self.old_section.row_fields + + rows = [] + + old_rows = self.old_section.make_rows() + new_rows = self.new_section.make_rows() + + old_section_dict = {row.field: row for row in old_rows} + new_section_dict = {row.field: row for row in new_rows} + + for field in all_fields: + # If a field does not appear in either section, no row will be created. + if field in old_section_dict and field in new_section_dict: + rows.append( + { + "verbose_name": old_section_dict[field].verbose_name, + "old_value": old_section_dict[field].value, + "new_value": new_section_dict[field].value, + } + ) + elif field in old_section_dict and not field in new_section_dict: + rows.append( + { + "verbose_name": old_section_dict[field].verbose_name, + "old_value": old_section_dict[field].value, + "new_value": "", + } + ) + elif field in new_section_dict and not field in old_section_dict: + rows.append( + { + "verbose_name": new_section_dict[field].verbose_name, + "old_value": "", + "new_value": new_section_dict[field].value, + } + ) + + return rows + + def render(self, context): + context = context.flatten() + template = get_template("proposals/table_with_header_diff.html") + + if self.warning is not None: + context.update( + { + "warning": self.warning, + "missing_object": self.missing_object, + } + ) + if self.sub_title is not None: + context.update( + { + "sub_title": self.sub_title, + } + ) + context.update( + { + "section_title": self.section_title, + "rows": self.rows, + } + ) + return template.render(context) + + +class Row: + """This class creates rows for one objects, and gets initated + in the make_rows method of Section classes. The classmethods of Rowclass + are called in the templates of the render method of the PDF class, as well as in + the make_diff_rows() method of the DiffSection""" + + verbose_name_diff_field_dict = { + "get_metc_display": "metc", + "get_is_medical_display": "is_medical", + } + + def __init__(self, obj, field): + self.obj = obj + self.field = field + + def value(self): + return RowValue(self.obj, self.field).get_field_value() + + def verbose_name(self): + if self.field in self.verbose_name_diff_field_dict: + verbose_name_field = self.verbose_name_diff_field_dict[self.field] + verbose_name = self.get_verbose_name(verbose_name_field) + else: + verbose_name = self.get_verbose_name(self.field) + return verbose_name + + def get_verbose_name(self, field): + if field != "tasks_duration": + return mark_safe(self.obj._meta.get_field(field).verbose_name) + else: + return mark_safe( + self.obj._meta.get_field(field).verbose_name % self.obj.net_duration() + ) + + +class RowValue: + """The RowValue class manages the values of fields and correctly retrieves and/or formats + the right values per field. This class get initiated in the value method + of the Row class. It returns mostly strings, but sometimes some html as well.""" + + def __init__(self, obj, field): + self.obj = obj + self.field = field + + def get_field_value(self): + from ..models import Relation + from studies.models import Compensation + + value = getattr(self.obj, self.field) + + User = get_user_model() + + if value in ("Y", "N", "?"): + return self.yes_no_doubt(value) + elif isinstance(value, bool): + return _("ja") if value else _("nee") + elif isinstance(value, (str, int, date)): + return value + elif value is None: + return _("Onbekend") + elif isinstance(value, User): + return self.handle_user(value) + elif isinstance(value, Relation) or isinstance(value, Compensation): + return value.description + elif value.__class__.__name__ == "ManyRelatedManager": + if value.all().model == User: + return self.get_applicants_names(value) + else: + return self.get_object_list(value) + elif value.__class__.__name__ == "FieldFile": + return self.handle_field_file(value) + elif callable(value): + return value() + + def handle_user(self, user): + return user.get_full_name() + + def get_applicants_names(self, applicants): + applicant_names = [applicant.get_full_name() for applicant in applicants.all()] + return self.create_unordered_html_list(applicant_names) + + def get_object_list(self, object): + list_of_objects = [obj for obj in object.all()] + return self.create_unordered_html_list(list_of_objects) + + def create_unordered_html_list(self, lst): + html_output = mark_safe('

    ') + + for index, item in enumerate(lst): + html_output += format_html("- {}", item) + if index != len(lst) - 1: + html_output += mark_safe("
    ") + + html_output += mark_safe("

    ") + + return html_output + + def handle_field_file(self, field_file): + if field_file: + output = format_html( + "{}", + f"{settings.BASE_URL}{field_file.url}", + _("Download"), + ) + else: + output = _("Niet aangeleverd") + + return output + + def yes_no_doubt(self, value): + from main.models import YesNoDoubt + + return YesNoDoubt(value).label + + +class SubTitle: + """This class can return a sub title to the base section class, + according to the argument with which it is initiated. This argument gets passed + in overwritten __init__ methods of for instance, the StudySection class.""" + + def __init__(self, object, sub_title_type): + if sub_title_type == "study": + self.sub_title = self.get_study_title(object) + elif sub_title_type == "session": + self.sub_title = self.get_session_title(object) + elif sub_title_type == "task": + self.sub_title = self.get_task_title(object) + elif sub_title_type == "task_overview": + self.sub_title = _("Overzicht van het takenonderzoek") + else: + self.sub_title = None + + def get_study_title(self, study): + from studies.models import Study + + if not isinstance(study, Study): + study = study.study + if study.proposal.studies_number > 1: + if study.name: + study_title = format_html( + "{}{} {} ", + _("Traject "), + study.order, + study.name, + ) + else: + study_title = format_html( + "{}{}", + _("Traject"), + {study.order}, + ) + else: + study_title = None + return study_title + + def get_session_title(self, session): + if session is None: + return "" + else: + order = session.order + study_order = session.study.order + study_name = session.study.name + studies_number = session.study.proposal.studies_number + sessions_number = session.study.sessions_number + + if studies_number > 1 and sessions_number > 1: + session_title = format_html( + "{}{} {} {}{}", + _("Traject "), + study_order, + study_name, + _("sessie "), + order, + ) + elif studies_number > 1: + session_title = format_html( + "{}{} {} ", + _("Traject "), + study_order, + study_name, + ) + elif sessions_number >= 1: + session_title = format_html( + "{}{}", + _("Sessie "), + order, + ) + return session_title + + def get_task_title(self, task): + if task is None: + return "" + else: + order = task.order + session_order = task.session.order + study_order = task.session.study.order + study_name = task.session.study.name + studies_number = task.session.study.proposal.studies_number + if studies_number > 1: + task_title = format_html( + "{}{} {} , {}{}{}{}", + _("Traject "), + study_order, + study_name, + _("sessie "), + session_order, + _(", taak "), + order, + ) + else: + task_title = format_html( + "{}{}{}{}", + _("Sessie "), + session_order, + _(", taak "), + order, + ) + return task_title + + +class PageBreakMixin(BaseSection): + """A Mixin for adding page break formatting to a section.""" + + def render(self, context): + context.update( + { + "page_break": True, + } + ) + return super().render(context) + + +class GeneralSection(BaseSection): + """This class generates the data for the general section of a proposal and showcases + the general workflow for creating sections. All possible row fields are provided, and + removed according to the logic in the get_row_fields method. + This class receives a proposal object. + """ + + section_title = _("Algemene informatie over de aanvraag") + row_fields = [ + "is_pre_approved", + "relation", + "supervisor", + "student_program", + "student_context", + "student_context_details", + "student_justification", + "other_applicants", + "applicants", + "other_stakeholders", + "stakeholders", + "date_start", + "title", + "funding", + "funding_details", + "funding_name", + "pre_approval_institute", + "pre_approval_pdf", + "pre_assessment_pdf", + "self_assessment", + "summary", + ] + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if not obj.is_pre_approved: + rows.remove("is_pre_approved") + rows.remove("pre_approval_institute") + rows.remove("pre_approval_pdf") + + if obj.is_pre_assessment: + rows.remove("funding") + rows.remove("funding_name") + rows.remove("funding_details") + rows.remove("summary") + else: + rows.remove("pre_assessment_pdf") + if not needs_details(obj.funding.all()): + rows.remove("funding_details") + if not needs_details(obj.funding.all(), "needs_name"): + rows.remove("funding_name") + + if not obj.relation.needs_supervisor: + rows.remove("supervisor") + if not obj.relation.check_in_course: + rows.remove("student_program") + rows.remove("student_context") + if obj.student_context is not None: + if not obj.student_context.needs_details: + rows.remove("student_context_details") + else: + rows.remove("student_context_details") + rows.remove("student_justification") + if not obj.other_applicants: + rows.remove("applicants") + if not obj.other_stakeholders: + rows.remove("stakeholders") + + return rows + + +class WMOSection(PageBreakMixin, BaseSection): + """This class receives a proposal.wmo object.""" + + section_title = _( + "Ethische toetsing nodig door een Medische Ethische Toetsingscommissie (METC)?" + ) + row_fields = [ + "get_metc_display", + "metc_details", + "metc_institution", + "get_is_medical_display", + ] + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if not obj.metc == "Y": + rows.remove("metc_details") + rows.remove("metc_institution") + else: + rows.remove("get_is_medical_display") + + return rows + + +class METCSection(PageBreakMixin, BaseSection): + """This class receives a proposal.wmo object.""" + + section_title = _("Aanmelding bij de METC") + + row_fields = ["metc_application", "metc_decision", "metc_decision_pdf"] + + +class TrajectoriesSection(PageBreakMixin, BaseSection): + """This class receives a proposal object.""" + + section_title = _("Eén of meerdere trajecten?") + + row_fields = ["studies_similar", "studies_number"] + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if obj.studies_similar: + rows.remove("studies_number") + + return rows + + +class StudySection(PageBreakMixin, BaseSection): + """This class receives a proposal.study object + Note the overwritten __init__ method for adding a sub_title.""" + + section_title = _("De deelnemers") + row_fields = [ + "age_groups", + "legally_incapable", + "legally_incapable_details", + "has_special_details", + "special_details", + "traits", + "traits_details", + "necessity", + "necessity_reason", + "recruitment", + "recruitment_details", + "compensation", + "compensation_details", + "hierarchy", + "hierarchy_details", + ] + + def __init__(self, obj): + super().__init__(obj) + self.sub_title = self.get_sub_title(self.obj, "study") + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if not has_adults(obj): + rows.remove("legally_incapable") + rows.remove("legally_incapable_details") + elif not obj.legally_incapable: + rows.remove("legally_incapable_details") + if not obj.has_special_details: + rows.remove("special_details") + rows.remove("traits") + rows.remove("traits_details") + elif not medical_traits(obj.special_details.all()): + rows.remove("traits") + rows.remove("traits_details") + elif not needs_details(obj.traits.all()): + rows.remove("traits_details") + if not necessity_required(obj): + rows.remove("necessity") + rows.remove("necessity_reason") + if not needs_details(obj.recruitment.all()): + rows.remove("recruitment_details") + if not obj.compensation or not obj.compensation.needs_details: + rows.remove("compensation_details") + if not obj.hierarchy: + rows.remove("hierarchy_details") + + return rows + + +class InterventionSection(BaseSection): + """This class receives an intervention object""" + + section_title = _("Het interventieonderzoek") + row_fields = [ + "setting", + "setting_details", + "supervision", + "leader_has_coc", + "period", + "multiple_sessions", + "session_frequency", + "amount_per_week", + "duration", + "measurement", + "experimenter", + "description", + "has_controls", + "controls_description", + "extra_task", + ] + + def __init__(self, obj): + super().__init__(obj) + self.sub_title = self.get_sub_title(self.obj, "study") + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if obj.version == 1: + fields_to_remove = ["multiple_sessions", "session_frequency", "extra_task"] + for field in fields_to_remove: + rows.remove(field) + else: + rows.remove("amount_per_week") + if not obj.multiple_sessions: + rows.remove("session_frequency") + if obj.settings_contains_schools: + rows.remove("extra_task") + + if not needs_details(obj.setting.all()): + rows.remove("setting_details") + if not obj.study.has_children() or not needs_details( + obj.setting.all(), "needs_supervision" + ): + rows.remove("supervision") + rows.remove("leader_has_coc") + elif obj.supervision: + rows.remove("leader_has_coc") + if not obj.has_controls: + rows.remove("controls_description") + + return rows + + +class ObservationSection(BaseSection): + """This class receives an observation object""" + + section_title = _("Het observatieonderzoek") + row_fields = [ + "setting", + "setting_details", + "supervision", + "leader_has_coc", + "days", + "mean_hours", + "details_who", + "details_why", + "details_frequency", + "is_anonymous", + "is_anonymous_details", + "is_in_target_group", + "is_in_target_group_details", + "is_nonpublic_space", + "is_nonpublic_space_details", + "has_advanced_consent", + "has_advanced_consent_details", + "needs_approval", + "approval_institution", + "approval_document", + "registrations", + "registrations_details", + ] + + def __init__(self, obj): + super().__init__(obj) + self.sub_title = self.get_sub_title(self.obj, "study") + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if obj.version == 1: + to_remove_if_v1 = [ + "details_who", + "details_why", + "is_anonymous_details", + "is_in_target_group_details", + "is_nonpublic_space_details", + "has_advanced_consent_details", + ] + for field in to_remove_if_v1: + rows.remove(field) + + if not obj.is_nonpublic_space: + rows.remove("has_advanced_consent") + if not obj.needs_approval: + rows.remove("approval_institution") + rows.remove("approval_document") + elif obj.study.proposal.is_practice(): + rows.remove("approval_document") + else: + to_remove_if_v2 = ["days", "mean_hours", "approval_document"] + for field in to_remove_if_v2: + rows.remove(field) + + if not obj.is_anonymous: + rows.remove("is_anonymous_details") + if not obj.is_in_target_group: + rows.remove("is_in_target_group_details") + if not obj.is_nonpublic_space: + rows.remove("is_nonpublic_space_details") + rows.remove("has_advanced_consent") + rows.remove("has_advanced_consent_details") + elif obj.has_advanced_consent: + rows.remove("has_advanced_consent_details") + if not needs_details(obj.setting.all(), "is_school"): + rows.remove("needs_approval") + if not obj.needs_approval: + rows.remove("approval_institution") + + if not needs_details(obj.setting.all()): + rows.remove("setting_details") + if not obj.study.has_children() or not needs_details( + obj.setting.all(), "needs_supervision" + ): + rows.remove("supervision") + rows.remove("leader_has_coc") + elif obj.supervision: + rows.remove("leader_has_coc") + if not needs_details(obj.registrations.all()): + rows.remove("registrations_details") + + return rows + + +class SessionsOverviewSection(BaseSection): + """This class receives an study object""" + + section_title = _("Het takenonderzoek en interviews") + + row_fields = ["sessions_number"] + + +class SessionSection(BaseSection): + """This class receives a session object""" + + row_fields = [ + "setting", + "setting_details", + "supervision", + "leader_has_coc", + "tasks_number", + ] + + def __init__(self, obj): + super().__init__(obj) + self.sub_title = self.get_sub_title(self.obj, "session") + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if not needs_details(obj.setting.all()): + rows.remove("setting_details") + if not obj.study.has_children() or not needs_details( + obj.setting.all(), "needs_supervision" + ): + rows.remove("supervision") + rows.remove("leader_has_coc") + elif obj.supervision: + rows.remove("leader_has_coc") + + return rows + + +class TaskSection(BaseSection): + """This class receives a task object""" + + row_fields = [ + "name", + "duration", + "registrations", + "registrations_details", + "registration_kinds", + "registration_kinds_details", + "feedback", + "feedback_details", + "description", + ] + + def __init__(self, obj): + super().__init__(obj) + self.sub_title = self.get_sub_title(self.obj, "task") + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if not needs_details(obj.registrations.all()): + rows.remove("registrations_details") + if not needs_details( + obj.registrations.all(), "needs_kind" + ) or not needs_details(obj.registration_kinds.all()): + rows.remove("registration_kinds") + rows.remove("registration_kinds_details") + elif not needs_details(obj.registration_kinds.all()): + rows.remove("registration_kinds_details") + if not obj.feedback: + rows.remove("feedback_details") + + return rows + + +class TasksOverviewSection(BaseSection): + """Gets passed a session object""" + + row_fields = ["tasks_duration"] + + def __init__(self, obj): + super().__init__(obj) + self.sub_title = self.get_sub_title(self.obj, "task_overview") + + +class StudyOverviewSection(BaseSection): + """This class receives a Study object.""" + + section_title = _("Overzicht en eigen beoordeling van het gehele onderzoek") + row_fields = [ + "deception", + "deception_details", + "negativity", + "negativity_details", + "stressful", + "stressful_details", + "risk", + "risk_details", + ] + + def __init__(self, obj): + super().__init__(obj) + self.sub_title = self.get_sub_title(self.obj, "study") + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + rows_to_remove = [] + for x in range(0, 7, 2): + if getattr(obj, rows[x]) == "N": + rows_to_remove.append(rows[x + 1]) + rows = [row for row in rows if row not in rows_to_remove] + + if not obj.has_sessions and not obj.deception == "N": + rows.remove("deception") + rows.remove("deception_details") + elif not obj.has_sessions: + rows.remove("deception") + + return rows + + +class InformedConsentFormsSection(BaseSection): + """This class receives a Documents object""" + + section_title = _("Informed consent formulieren") + + row_fields = [ + "translated_forms", + "translated_forms_languages", + "informed_consent", + "briefing", + "passive_consent", + "passive_consent_details", + "director_consent_declaration", + "director_consent_information", + "parents_information", + ] + + def make_rows(self): + """A few fields here need to access different objects, therefore this complex + overriding of the make_rows function ... :(""" + + proposal_list = ["translated_forms", "translated_forms_languages"] + study_list = ["passive_consent", "passive_consent_details"] + + row_fields = self.get_row_fields() + + rows = [] + + for field in row_fields: + if field in proposal_list: + rows.append(Row(self.obj.proposal, field)) + elif field in study_list: + rows.append(Row(self.obj.study, field)) + else: + rows.append(Row(self.obj, field)) + + return rows + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if not obj.proposal.translated_forms: + rows.remove("translated_forms_languages") + if obj.proposal.is_practice() or not obj.informed_consent: + rows.remove("informed_consent") + rows.remove("briefing") + if obj.study.passive_consent is None: + rows.remove("passive_consent") + if not obj.study.passive_consent: + rows.remove("passive_consent_details") + if not obj.director_consent_declaration: + rows.remove("director_consent_declaration") + if not obj.director_consent_information: + rows.remove("director_consent_information") + if not obj.parents_information: + rows.remove("parents_information") + + return rows + + +class ExtraDocumentsSection(BaseSection): + """This class receives an Documents object. + Overrides the __init__ to create a formatted section title""" + + row_fields = [ + "informed_consent", + "briefing", + "director_consent_declaration", + "director_consent_information", + "parents_information", + ] + + def __init__(self, obj, num): + super().__init__(obj) + self.section_title = _("Extra formulieren ") + str(num + 1) + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if not obj.informed_consent: + rows.remove("informed_consent") + if not obj.briefing: + rows.remove("briefing") + if not obj.director_consent_declaration: + rows.remove("director_consent_declaration") + if not obj.director_consent_information: + rows.remove("director_consent_information") + if not obj.parents_information: + rows.remove("parents_information") + + return rows + + +class DMPFileSection(PageBreakMixin, BaseSection): + """This class receives a proposal object + Also unnecessary I suppose. But I though why not ...""" + + section_title = _("Data Management Plan") + + row_fields = ["dmp_file", "privacy_officer"] + + +class EmbargoSection(BaseSection): + """Gets passed a proposal object""" + + section_title = _("Aanmelding versturen") + + row_fields = ["embargo", "embargo_end_date"] + + def get_row_fields(self): + rows = copy(self.row_fields) + obj = self.obj + + if not obj.embargo: + rows.remove("embargo_end_date") + + return rows + + +class CommentsSection(BaseSection): + """Gets passed a proposal object.""" + + section_title = _("Ruimte voor eventuele opmerkingen") + + row_fields = ["comments"] + + +def get_extra_documents(obj): + """A function to retrieve all extra documents for a specific proposal.""" + from studies.models import Documents + + extra_documents = [] + + for document in Documents.objects.filter(proposal=obj, study__isnull=True): + extra_documents.append(document) + + return extra_documents + + +def create_context_pdf(context, model): + """A function to create the context for the PDF, which gets called in the ProposalAsPdf view.""" + + sections = [] + + sections.append(GeneralSection(model)) + + if hasattr(model, "wmo"): + sections.append(WMOSection(model.wmo)) + + if not model.is_pre_assessment: + if model.wmo.status != model.wmo.WMOStatuses.NO_WMO: + sections.append(METCSection(model.wmo)) + + sections.append(TrajectoriesSection(model)) + + if model.wmo.status == model.wmo.WMOStatuses.NO_WMO: + for study in model.study_set.all(): + sections.append(StudySection(study)) + if study.has_intervention: + sections.append(InterventionSection(study.intervention)) + if study.has_observation: + sections.append(ObservationSection(study.observation)) + if study.has_sessions: + sections.append(SessionsOverviewSection(study)) + for session in study.session_set.all(): + sections.append(SessionSection(session)) + for task in session.task_set.all(): + sections.append(TaskSection(task)) + sections.append(TasksOverviewSection(session)) + sections.append(StudyOverviewSection(study)) + sections.append(InformedConsentFormsSection(study.documents)) + + extra_documents = get_extra_documents(model) + + for num, document in enumerate(extra_documents): + sections.append(ExtraDocumentsSection(document, num)) + + if model.dmp_file: + sections.append(DMPFileSection(model)) + + sections.append(EmbargoSection(model)) + sections.append(CommentsSection(model)) + + context["sections"] = sections + + return context + + +def multi_sections(section_type, objects, num=None): + """A function that creates a list of sections of a specified type, from a list of + objects, where it is possible for an object, such as a study, to be missing.""" + + if num is None: + return [section_type(obj) if obj is not None else None for obj in objects] + else: + return [section_type(obj, num) if obj is not None else None for obj in objects] + + +def get_all_related(objects, related_name): + """Helper function for retrieving related objects""" + + return [ + getattr(obj, related_name, None) if obj is not None else None for obj in objects + ] + + +def get_all_related_set(objects, related_name): + """Helper function for retrieving a set of related objects.""" + + return [ + getattr(obj, related_name, None).all() if obj is not None else None + for obj in objects + ] + + +def create_context_diff(context, old_proposal, new_proposal): + """A function to create the context for the diff page.""" + + sections = [] + + sections.append( + DiffSection(GeneralSection(old_proposal), GeneralSection(new_proposal)) + ) + + if hasattr(new_proposal, "wmo"): + sections.append( + DiffSection(WMOSection(old_proposal.wmo), WMOSection(new_proposal.wmo)) + ) + + if not new_proposal.is_pre_assessment: + if ( + new_proposal.wmo.status != new_proposal.wmo.WMOStatuses.NO_WMO + or old_proposal.wmo.status != old_proposal.wmo.WMOStatuses.NO_WMO + ): + sections.append( + DiffSection( + METCSection(old_proposal.wmo), METCSection(new_proposal.wmo) + ) + ) + + sections.append( + DiffSection( + TrajectoriesSection(old_proposal), TrajectoriesSection(new_proposal) + ) + ) + + if ( + new_proposal.wmo.status == new_proposal.wmo.WMOStatuses.NO_WMO + or new_proposal.wmo.status == new_proposal.wmo.WMOStatuses.JUDGED + ): + for old_study, new_study in zip_equalize_lists( + old_proposal.study_set.all(), new_proposal.study_set.all() + ): + both_studies = [old_study, new_study] + + sections.append( + DiffSection(*multi_sections(StudySection, both_studies)) + ) + + if ( + old_study is not None + and old_study.has_intervention + or new_study is not None + and new_study.has_intervention + ): + interventions = get_all_related(both_studies, "intervention") + + sections.append( + DiffSection( + *multi_sections(InterventionSection, interventions) + ) + ) + + if ( + old_study is not None + and old_study.has_observation + or new_study is not None + and new_study.has_observation + ): + observations = get_all_related(both_studies, "observation") + + sections.append( + DiffSection( + *multi_sections(ObservationSection, observations) + ) + ) + + if ( + old_study is not None + and old_study.has_sessions + or new_study is not None + and new_study.has_sessions + ): + sections.append( + DiffSection( + *multi_sections(SessionsOverviewSection, both_studies) + ) + ) + + old_sessions_set, new_sessions_set = get_all_related_set( + both_studies, "session_set" + ) + + for both_sessions in zip_equalize_lists( + old_sessions_set, new_sessions_set + ): + sections.append( + DiffSection( + *multi_sections(SessionSection, both_sessions) + ) + ) + + old_tasks_set, new_tasks_set = get_all_related_set( + both_sessions, "task_set" + ) + + for both_tasks in zip_equalize_lists( + old_tasks_set, new_tasks_set + ): + sections.append( + DiffSection( + *multi_sections(TaskSection, both_tasks) + ) + ) + + sections.append( + DiffSection( + *multi_sections(TasksOverviewSection, both_sessions) + ) + ) + + sections.append( + DiffSection(*multi_sections(StudyOverviewSection, both_studies)) + ) + + both_documents = get_all_related(both_studies, "documents") + + sections.append( + DiffSection( + *multi_sections(InformedConsentFormsSection, both_documents) + ) + ) + + old_extra_docs = get_extra_documents(old_proposal) + new_extra_docs = get_extra_documents(new_proposal) + + if old_extra_docs or new_extra_docs: + for num, zipped_extra_docs in enumerate( + zip_equalize_lists(old_extra_docs, new_extra_docs) + ): + sections.append( + DiffSection( + *multi_sections( + ExtraDocumentsSection, zipped_extra_docs, num + ) + ) + ) + + if old_proposal.dmp_file or new_proposal.dmp_file: + sections.append( + DiffSection( + *multi_sections( + DMPFileSection, [old_proposal, new_proposal] + ) + ) + ) + + sections.append( + DiffSection(EmbargoSection(old_proposal), EmbargoSection(new_proposal)) + ) + sections.append( + DiffSection(CommentsSection(old_proposal), CommentsSection(new_proposal)) + ) + + context["sections"] = sections + + return context diff --git a/proposals/utils/proposal_utils.py b/proposals/utils/proposal_utils.py index 471a281d4..b0d1c08ed 100644 --- a/proposals/utils/proposal_utils.py +++ b/proposals/utils/proposal_utils.py @@ -12,7 +12,7 @@ from django.core.mail import send_mail from django.db.models import Q from django.urls import reverse -from django.template.loader import render_to_string, get_template +from django.template.loader import render_to_string from django.utils.translation import activate, get_language, ugettext as _ from django.utils.deconstruct import deconstructible @@ -20,11 +20,16 @@ from studies.utils import study_urls -__all__ = ['available_urls', 'generate_ref_number', - 'generate_revision_ref_number', 'generate_pdf', - 'check_local_facilities', 'notify_local_staff', - 'FilenameFactory', 'OverwriteStorage', - ] +__all__ = [ + "available_urls", + "generate_ref_number", + "generate_revision_ref_number", + "generate_pdf", + "check_local_facilities", + "notify_local_staff", + "FilenameFactory", + "OverwriteStorage", +] def available_urls(proposal): @@ -36,60 +41,63 @@ def available_urls(proposal): urls = list() if proposal.is_pre_assessment: - urls.append(AvailableURL(url=reverse('proposals:update_pre', args=(proposal.pk,)), - title=_('Algemene informatie over de aanvraag'))) + urls.append( + AvailableURL( + url=reverse("proposals:update_pre", args=(proposal.pk,)), + title=_("Algemene informatie over de aanvraag"), + ) + ) - wmo_url = AvailableURL(title=_('Ethische toetsing nodig door een METC?')) - if hasattr(proposal, 'wmo'): - wmo_url.url = reverse('proposals:wmo_update_pre', args=(proposal.wmo.pk,)) + wmo_url = AvailableURL(title=_("Ethische toetsing nodig door een METC?")) + if hasattr(proposal, "wmo"): + wmo_url.url = reverse("proposals:wmo_update_pre", args=(proposal.wmo.pk,)) else: - wmo_url.url = reverse('proposals:wmo_create_pre', args=(proposal.pk,)) + wmo_url.url = reverse("proposals:wmo_create_pre", args=(proposal.pk,)) urls.append(wmo_url) - submit_url = AvailableURL(title=_('Aanvraag voor voortoetsing klaar voor versturen')) - if hasattr(proposal, 'wmo'): - submit_url.url = reverse('proposals:submit_pre', args=(proposal.pk,)) + submit_url = AvailableURL( + title=_("Aanvraag voor voortoetsing klaar voor versturen") + ) + if hasattr(proposal, "wmo"): + submit_url.url = reverse("proposals:submit_pre", args=(proposal.pk,)) urls.append(submit_url) elif proposal.is_pre_approved: - urls.append(AvailableURL(url=reverse('proposals:update_pre_approved', args=(proposal.pk,)), - title=_('Algemene informatie over de aanvraag'))) + urls.append( + AvailableURL( + url=reverse("proposals:update_pre_approved", args=(proposal.pk,)), + title=_("Algemene informatie over de aanvraag"), + ) + ) submit_url = AvailableURL( - title=_('Aanvraag voor voortoetsing klaar voor versturen'), + title=_("Aanvraag voor voortoetsing klaar voor versturen"), margin=0, - url = reverse('proposals:submit_pre_approved', args=(proposal.pk,)) + url=reverse("proposals:submit_pre_approved", args=(proposal.pk,)), ) urls.append(submit_url) else: - update_url = 'proposals:update_practice' if proposal.is_practice() else 'proposals:update' + update_url = ( + "proposals:update_practice" + if proposal.is_practice() + else "proposals:update" + ) urls.append( AvailableURL( url=reverse(update_url, args=(proposal.pk,)), - title=_('Algemeen'), + title=_("Algemeen"), ) ) - wmo_url = AvailableURL( - title=_('METC') - ) - if hasattr(proposal, 'wmo'): - wmo_url.url = reverse( - 'proposals:wmo_update', - args=(proposal.wmo.pk,) - ) + wmo_url = AvailableURL(title=_("METC")) + if hasattr(proposal, "wmo"): + wmo_url.url = reverse("proposals:wmo_update", args=(proposal.wmo.pk,)) else: - wmo_url.url = reverse( - 'proposals:wmo_create', - args=(proposal.pk,) - ) + wmo_url.url = reverse("proposals:wmo_create", args=(proposal.pk,)) urls.append(wmo_url) - studies_url = AvailableURL(title=_('Trajecten')) - if hasattr(proposal, 'wmo'): - studies_url.url = reverse( - 'proposals:study_start', - args=(proposal.pk,) - ) + studies_url = AvailableURL(title=_("Trajecten")) + if hasattr(proposal, "wmo"): + studies_url.url = reverse("proposals:study_start", args=(proposal.pk,)) if proposal.study_set.count() > 0: _add_study_urls(studies_url, proposal) @@ -97,37 +105,28 @@ def available_urls(proposal): urls.append(studies_url) consent_docs_url = AvailableURL( - title=_('Uploaden'), - url=reverse( - 'proposals:consent', - args=(proposal.pk, ) - ) - ) + title=_("Uploaden"), url=reverse("proposals:consent", args=(proposal.pk,)) + ) translated_docs_url = AvailableURL( - title=_('Vertaling'), - url=reverse( - 'proposals:translated', - args=(proposal.pk, ) - ) - ) + title=_("Vertaling"), + url=reverse("proposals:translated", args=(proposal.pk,)), + ) consent_url = AvailableURL( - title=_('Formulieren'), - children=[ - translated_docs_url, - consent_docs_url - ] - ) + title=_("Formulieren"), children=[translated_docs_url, consent_docs_url] + ) - data_management_url = AvailableURL(title=_('Datamanagement')) - submit_url = AvailableURL(title=_('Versturen')) + data_management_url = AvailableURL(title=_("Datamanagement")) + submit_url = AvailableURL(title=_("Versturen")) if proposal.last_study() and proposal.last_study().is_completed(): - consent_url.url = reverse('proposals:translated', args=(proposal.pk, )) - data_management_url.url = reverse('proposals:data_management', args=(proposal.pk, )) - submit_url.url = reverse('proposals:submit', args=(proposal.pk,)) + consent_url.url = reverse("proposals:translated", args=(proposal.pk,)) + data_management_url.url = reverse( + "proposals:data_management", args=(proposal.pk,) + ) + submit_url.url = reverse("proposals:submit", args=(proposal.pk,)) if proposal.translated_forms is not None: - consent_url.url = reverse('proposals:consent', args=(proposal.pk,)) + consent_url.url = reverse("proposals:consent", args=(proposal.pk,)) urls.append(consent_url) urls.append(data_management_url) @@ -148,9 +147,7 @@ def _add_study_urls(main_element, proposal): # Otherwise, add them all with the parent node prev_study_completed = True for study in proposal.study_set.all(): - main_element.children.append( - study_urls(study, prev_study_completed) - ) + main_element.children.append(study_urls(study, prev_study_completed)) prev_study_completed = study.is_completed() @@ -169,7 +166,7 @@ def generate_ref_number(): proposal_number = _get_next_proposal_number(current_year) version_number = 1 - return '{}-{:03}-{:02}'.format( + return "{}-{:03}-{:02}".format( current_year_formatted, proposal_number, version_number, @@ -192,7 +189,7 @@ def generate_revision_ref_number(parent): will use the next available version number (this might not be the same as parent.vr + 1, as that one might already exist). """ - parent_parts = parent.reference_number.split('-') + parent_parts = parent.reference_number.split("-") # If we have 4 parts, the ref.number is in the user-nr-vr-year format if len(parent_parts) == 4: @@ -211,7 +208,7 @@ def _generate_revision_ref_number_oldformat(parent, version): """ from ..models import Proposal - parent_parts = parent.reference_number.split('-') + parent_parts = parent.reference_number.split("-") old_proposal_number = int(parent_parts[1]) proposal_number = -1 @@ -233,18 +230,18 @@ def _generate_revision_ref_number_oldformat(parent, version): # part and the same year. (This way we find both old and new style ref.nums) num_versions = Proposal.objects.filter( Q( - reference_number__istartswith="{}-{:02}".format(username, - old_proposal_number), - reference_number__endswith=str(year) - ) | Q(reference_number__istartswith="{}-{:03}".format(year, - proposal_number)) - + reference_number__istartswith="{}-{:02}".format( + username, old_proposal_number + ), + reference_number__endswith=str(year), + ) + | Q(reference_number__istartswith="{}-{:03}".format(year, proposal_number)) ).count() # The new revision is number of current versions + 1 version_number = num_versions + 1 - return '{}-{:03}-{:02}'.format( + return "{}-{:03}-{:02}".format( year[2:], proposal_number, version_number, @@ -257,7 +254,7 @@ def _generate_revision_ref_number_newformat(parent): """ from ..models import Proposal - parent_parts = parent.reference_number.split('-') + parent_parts = parent.reference_number.split("-") year = int(parent_parts[0]) proposal_number = int(parent_parts[1]) @@ -269,14 +266,14 @@ def _generate_revision_ref_number_newformat(parent): # Loop through all them, and note the newest version seen newest = None for parent_proposal in parent_proposals: - version = parent_proposal.reference_number.split('-')[2] + version = parent_proposal.reference_number.split("-")[2] version = int(version) if not newest or version > newest: newest = version version_number = newest + 1 - return '{}-{:03}-{:02}'.format( + return "{}-{:03}-{:02}".format( year, proposal_number, version_number, @@ -289,21 +286,27 @@ def _get_next_proposal_number(current_year) -> int: try: # We count all proposals for this year by selecting all proposals # with a reference number ending with the current year. - last_proposal = Proposal.objects.filter( - reference_number__startswith="{}-".format(str(current_year)[2:]) - ).order_by('-reference_number').first() + last_proposal = ( + Proposal.objects.filter( + reference_number__startswith="{}-".format(str(current_year)[2:]) + ) + .order_by("-reference_number") + .first() + ) if not last_proposal: return 1 - _, num, _ = last_proposal.reference_number.split('-', maxsplit=2) + _, num, _ = last_proposal.reference_number.split("-", maxsplit=2) return int(num) + 1 except Proposal.DoesNotExist: return 1 -def generate_pdf(proposal,): +def generate_pdf( + proposal, +): """ Returns a PDF of a proposal using the ProposalAsPdf view and the proposal's own recommended PDF template. @@ -341,12 +344,12 @@ def pdf_link_callback(uri, rel): if not isinstance(result, (list, tuple)): result = [result] result = list(os.path.realpath(path) for path in result) - path=result[0] + path = result[0] else: - sUrl = settings.STATIC_URL # Typically /static/ - sRoot = settings.STATIC_ROOT # Typically /home/userX/project_static/ - mUrl = settings.MEDIA_URL # Typically /media/ - mRoot = settings.MEDIA_ROOT # Typically /home/userX/project_static/media/ + sUrl = settings.STATIC_URL # Typically /static/ + sRoot = settings.STATIC_ROOT # Typically /home/userX/project_static/ + mUrl = settings.MEDIA_URL # Typically /media/ + mRoot = settings.MEDIA_ROOT # Typically /home/userX/project_static/media/ if uri.startswith(mUrl): path = os.path.join(mRoot, uri.replace(mUrl, "")) @@ -357,9 +360,7 @@ def pdf_link_callback(uri, rel): # make sure that file exists if not os.path.isfile(path): - raise Exception( - 'media URI must start with %s or %s' % (sUrl, mUrl) - ) + raise Exception("media URI must start with %s or %s" % (sUrl, mUrl)) return path @@ -408,23 +409,25 @@ def notify_local_staff(proposal): """ # Change language to Dutch for this e-mail, but save the current language to reset it later current_language = get_language() - activate('nl') + activate("nl") secretary = get_secretary() if proposal.is_revision: - subject = _('FETC-GW: gereviseerde aanvraag gebruikt labfaciliteiten') + subject = _("FETC-GW: gereviseerde aanvraag gebruikt labfaciliteiten") else: - subject = _('FETC-GW: nieuwe aanvraag gebruikt labfaciliteiten') + subject = _("FETC-GW: nieuwe aanvraag gebruikt labfaciliteiten") params = { - 'secretary': secretary.get_full_name(), - 'proposal': proposal, - 'applicants': [applicant.get_full_name() for applicant in proposal.applicants.all()], - 'facilities': sorted(check_local_facilities(proposal).items()), - 'is_revision': proposal.is_revision, + "secretary": secretary.get_full_name(), + "proposal": proposal, + "applicants": [ + applicant.get_full_name() for applicant in proposal.applicants.all() + ], + "facilities": sorted(check_local_facilities(proposal).items()), + "is_revision": proposal.is_revision, } - msg_plain = render_to_string('mail/local_staff_notify.txt', params) + msg_plain = render_to_string("mail/local_staff_notify.txt", params) send_mail(subject, msg_plain, settings.EMAIL_FROM, [settings.EMAIL_LOCAL_STAFF]) # Reset the current language @@ -433,11 +436,10 @@ def notify_local_staff(proposal): @deconstructible class FilenameFactory: - '''A callable class which can be passed to upload_to() in FileFields - and can be deconstructed for migrations''' + """A callable class which can be passed to upload_to() in FileFields + and can be deconstructed for migrations""" def __init__(self, document_type): - # document_type is a string describing the document kind, # such as "Informed_Consent" self.document_type = document_type @@ -461,7 +463,7 @@ def __call__(self, instance, original_fn): # In case of Documents objects proposal = instance.proposal try: - trajectory = 'T' + str(instance.study.order) + trajectory = "T" + str(instance.study.order) except AttributeError: # No associated study, so this is an extra Documents instance # We need to give it an index so they don't overwrite each other @@ -469,50 +471,51 @@ def __call__(self, instance, original_fn): # Again, to prevent circular imports from studies.models import Documents - qs = Documents.objects.filter( - proposal=proposal).filter( - study=None) + + qs = Documents.objects.filter(proposal=proposal).filter(study=None) for docs in qs: # The current Documents instance might not yet be saved and # therefore not exist in the QS. Hence the for loop instead of # the more traditional while if docs == instance: - break # i.e. this may never happen + break # i.e. this may never happen extra_index += 1 # Unknown - trajectory = 'Extra' + str(extra_index) + trajectory = "Extra" + str(extra_index) chamber = proposal.reviewing_committee.name lastname = proposal.created_by.last_name refnum = proposal.reference_number - extension = '.' + original_fn.split('.')[-1][-7:] # At most 7 chars seems reasonable + extension = ( + "." + original_fn.split(".")[-1][-7:] + ) # At most 7 chars seems reasonable - fn_parts = ['FETC', - chamber, - refnum, - lastname, - trajectory, - self.document_type, - ] + fn_parts = [ + "FETC", + chamber, + refnum, + lastname, + trajectory, + self.document_type, + ] def not_empty(item): if item == None: return False - if str(item) == '': + if str(item) == "": return False return True # Translations will trip up join(), so we convert them here fn_parts = [str(p) for p in filter(not_empty, fn_parts)] - return '-'.join(fn_parts) + extension + return "-".join(fn_parts) + extension class OverwriteStorage(FileSystemStorage): - def get_available_name(self, name, **kwargs): """Returns a filename that's free on the target storage system, and available for new content to be written to. diff --git a/proposals/utils/statistics_utils.py b/proposals/utils/statistics_utils.py index 2aeb6c230..e51085298 100644 --- a/proposals/utils/statistics_utils.py +++ b/proposals/utils/statistics_utils.py @@ -27,7 +27,7 @@ def get_qs_for_year(year: int) -> QuerySet: return Proposal.objects.filter( date_submitted__year=year, is_revision=False, - status__gte=Proposal.DECISION_MADE, + status__gte=Proposal.Statuses.DECISION_MADE, ) @@ -57,17 +57,14 @@ def get_review_qs_for_proposals(proposal_data: QuerySet) -> QuerySet: return Review.objects.filter( proposal__in=proposal_data, ).exclude( - stage=Review.SUPERVISOR, + stage=Review.Stages.SUPERVISOR, date_end=None, ) -def _get_review_qs_by_route(proposal_data: QuerySet, short_route: bool) -> \ - QuerySet: +def _get_review_qs_by_route(proposal_data: QuerySet, short_route: bool) -> QuerySet: """Returns all Reviews for the given proposals and taken route""" - return get_review_qs_for_proposals(proposal_data).filter( - short_route=short_route - ) + return get_review_qs_for_proposals(proposal_data).filter(short_route=short_route) def get_qs_for_short_route_reviews(proposal_data: QuerySet) -> QuerySet: @@ -162,9 +159,7 @@ def get_total_turnaround_time(review_data: QuerySet) -> Counter: :return: A Counter of (days, count) pairs :rtype: Counter """ - return Counter( - [(x.date_end - x.date_start).days for x in review_data] - ) + return Counter([(x.date_end - x.date_start).days for x in review_data]) def get_average_turnaround_time(review_data: QuerySet) -> float: @@ -177,9 +172,7 @@ def get_average_turnaround_time(review_data: QuerySet) -> float: using a float to represent partial days) :rtype: float """ - return statistics.mean( - [(x.date_end - x.date_start).days for x in review_data] - ) + return statistics.mean([(x.date_end - x.date_start).days for x in review_data]) # @@ -205,30 +198,33 @@ def get_registrations_for_proposal(proposal: Proposal) -> dict: for registration in study.observation.registrations.all(): if registration in ObsReg.objects.filter(needs_details=True): registrations[study.order].append( - 'obs: {}: {}'.format(registration.description, - study.observation.registrations_details)) + "obs: {}: {}".format( + registration.description, + study.observation.registrations_details, + ) + ) else: registrations[study.order].append( - 'obs: {}'.format(registration.description)) + "obs: {}".format(registration.description) + ) if study.has_sessions: for session in study.session_set.all(): for task in session.task_set.all(): for registration in task.registrations.all(): - if registration in TasReg.objects.filter( - needs_details=True): + if registration in TasReg.objects.filter(needs_details=True): registrations[study.order].append( - 's{}t{}: {}: {}'.format( + "s{}t{}: {}: {}".format( session.order, task.order, registration.description, - task.registrations_details) + task.registrations_details, + ) ) else: registrations[study.order].append( - 's{}t{}: {}'.format( - session.order, - task.order, - registration.description) + "s{}t{}: {}".format( + session.order, task.order, registration.description + ) ) return registrations @@ -246,10 +242,10 @@ def get_studytypes_for_proposal(proposal: Proposal) -> dict: for study in proposal.study_set.all(): if study.has_intervention: - study_types[study.order].append('intervention') + study_types[study.order].append("intervention") if study.has_observation: - study_types[study.order].append('observation') + study_types[study.order].append("observation") if study.has_sessions: - study_types[study.order].append('task') + study_types[study.order].append("task") return study_types diff --git a/proposals/utils/validate_proposal.py b/proposals/utils/validate_proposal.py index 7e6ee914f..4611a15ea 100644 --- a/proposals/utils/validate_proposal.py +++ b/proposals/utils/validate_proposal.py @@ -4,6 +4,7 @@ Used for the submit page, to check if a user has completed the proposal. """ + from collections import OrderedDict from braces.forms import UserKwargModelFormMixin @@ -12,7 +13,14 @@ from observations.forms import ObservationForm from studies.forms import StudyForm, StudyDesignForm, SessionStartForm from tasks.forms import TaskStartForm, TaskEndForm, TaskForm -from ..forms import ProposalForm, WmoForm, StudyStartForm, WmoApplicationForm, TranslatedConsentForms, ProposalDataManagementForm +from ..forms import ( + ProposalForm, + WmoForm, + StudyStartForm, + WmoApplicationForm, + TranslatedConsentForms, + ProposalDataManagementForm, +) from ..models import Proposal from django.utils.translation import ugettext_lazy as _ @@ -22,39 +30,39 @@ def _build_forms(proposal: Proposal) -> OrderedDict: forms = OrderedDict() - wmo_update_url = 'proposals:wmo_update' - wmo_application_url = 'proposals:wmo_application' + wmo_update_url = "proposals:wmo_update" + wmo_application_url = "proposals:wmo_application" # Get the correct URL for the if proposal.is_pre_assessment: - forms['start'] = ( + forms["start"] = ( ProposalForm, - reverse('proposals:update_pre', args=[proposal.pk]), - _('Algemene informatie over de aanvraag'), + reverse("proposals:update_pre", args=[proposal.pk]), + _("Algemene informatie over de aanvraag"), proposal, ) - wmo_create_url = 'proposals:wmo_create_pro' - wmo_update_url = 'proposals:wmo_update_pro' + wmo_create_url = "proposals:wmo_create_pro" + wmo_update_url = "proposals:wmo_update_pro" elif proposal.is_pre_approved: - forms['start'] = ( + forms["start"] = ( ProposalForm, - reverse('proposals:update_pre_approved', args=[proposal.pk]), - _('Algemene informatie over de aanvraag'), + reverse("proposals:update_pre_approved", args=[proposal.pk]), + _("Algemene informatie over de aanvraag"), proposal, ) elif proposal.is_practice(): - forms['start'] = ( + forms["start"] = ( ProposalForm, - reverse('proposals:update_practice', args=[proposal.pk]), - _('Algemene informatie over de aanvraag'), + reverse("proposals:update_practice", args=[proposal.pk]), + _("Algemene informatie over de aanvraag"), proposal, ) else: - forms['start'] = ( + forms["start"] = ( ProposalForm, - reverse('proposals:update', args=[proposal.pk]), - _('Algemene informatie over de aanvraag'), + reverse("proposals:update", args=[proposal.pk]), + _("Algemene informatie over de aanvraag"), proposal, ) @@ -62,18 +70,18 @@ def _build_forms(proposal: Proposal) -> OrderedDict: if proposal.is_pre_approved: return forms - if hasattr(proposal, 'wmo'): - forms['wmo_form'] = ( + if hasattr(proposal, "wmo"): + forms["wmo_form"] = ( WmoForm, reverse(wmo_update_url, args=[proposal.wmo.pk]), - _('Ethische toetsing nodig door een METC?'), + _("Ethische toetsing nodig door een METC?"), proposal.wmo, ) - if proposal.wmo.status != proposal.wmo.NO_WMO: - forms['wmo_application'] = ( + if proposal.wmo.status != proposal.wmo.WMOStatuses.NO_WMO: + forms["wmo_application"] = ( WmoApplicationForm, reverse(wmo_application_url, args=[proposal.pk]), - _('Ethische toetsing nodig door een METC?'), + _("Ethische toetsing nodig door een METC?"), proposal.wmo, ) @@ -81,42 +89,39 @@ def _build_forms(proposal: Proposal) -> OrderedDict: if proposal.is_pre_assessment: return forms - forms['study_start'] = ( + forms["study_start"] = ( StudyStartForm, - reverse('proposals:study_start', args=[proposal.pk]), - _(u'Eén of meerdere trajecten?'), + reverse("proposals:study_start", args=[proposal.pk]), + _("Eén of meerdere trajecten?"), proposal, ) for study in proposal.study_set.all(): - key_base = 'study_{}'.format(study.pk) + key_base = "study_{}".format(study.pk) - start_key = '{}_start'.format(key_base) + start_key = "{}_start".format(key_base) forms[start_key] = ( StudyForm, - reverse('studies:update', args=[study.pk]), - _('De deelnemers (traject {})').format(study.order), + reverse("studies:update", args=[study.pk]), + _("De deelnemers (traject {})").format(study.order), study, ) - design_key = '{}_design'.format(key_base) + design_key = "{}_design".format(key_base) forms[design_key] = ( StudyDesignForm, - reverse('studies:design', args=[study.pk]), - _('De onderzoekstype(n) (traject {})').format(study.order), + reverse("studies:design", args=[study.pk]), + _("De onderzoekstype(n) (traject {})").format(study.order), study, ) if study.has_intervention: - intervention_key = '{}_intervention'.format(key_base) - if hasattr(study, 'intervention'): + intervention_key = "{}_intervention".format(key_base) + if hasattr(study, "intervention"): forms[intervention_key] = ( InterventionForm, - reverse( - 'interventions:update', - args=[study.intervention.pk] - ), - _('Het interventieonderzoek (traject {})').format( + reverse("interventions:update", args=[study.intervention.pk]), + _("Het interventieonderzoek (traject {})").format( study.order, ), study.intervention, @@ -124,23 +129,20 @@ def _build_forms(proposal: Proposal) -> OrderedDict: else: forms[intervention_key] = ( InterventionForm, - reverse('interventions:create', args=[study.pk]), - _('Het interventieonderzoek (traject {})').format( + reverse("interventions:create", args=[study.pk]), + _("Het interventieonderzoek (traject {})").format( study.order, ), None, ) if study.has_observation: - observation_key = '{}_observation'.format(key_base) - if hasattr(study, 'observation'): + observation_key = "{}_observation".format(key_base) + if hasattr(study, "observation"): forms[observation_key] = ( ObservationForm, - reverse( - 'observations:update', - args=[study.observation.pk] - ), - _('Het observatieonderzoek (traject {})').format( + reverse("observations:update", args=[study.observation.pk]), + _("Het observatieonderzoek (traject {})").format( study.order, ), study.observation, @@ -148,34 +150,34 @@ def _build_forms(proposal: Proposal) -> OrderedDict: else: forms[observation_key] = ( ObservationForm, - reverse('observations:create', args=[study.pk]), - _('Het observatieonderzoek (traject {})').format( + reverse("observations:create", args=[study.pk]), + _("Het observatieonderzoek (traject {})").format( study.order, ), None, ) if study.has_sessions: - taskbased_key = '{}_task_start'.format(key_base) + taskbased_key = "{}_task_start".format(key_base) forms[taskbased_key] = ( SessionStartForm, - reverse('studies:session_start', args=[study.pk]), - _('Het takenonderzoek (traject {})').format( + reverse("studies:session_start", args=[study.pk]), + _("Het takenonderzoek (traject {})").format( study.order, ), study, ) for session in study.session_set.all(): - session_start_key = '{}_session_{}_start'.format( + session_start_key = "{}_session_{}_start".format( key_base, session.pk, ) forms[session_start_key] = ( TaskStartForm, - reverse('tasks:start', args=[session.pk]), - _('Het takenonderzoek: sessie {} (traject {})').format( + reverse("tasks:start", args=[session.pk]), + _("Het takenonderzoek: sessie {} (traject {})").format( session.order, study.order, ), @@ -183,7 +185,7 @@ def _build_forms(proposal: Proposal) -> OrderedDict: ) for task in session.task_set.all(): - task_key = '{}_session_{}_task_{}'.format( + task_key = "{}_session_{}_task_{}".format( key_base, session.pk, task.pk, @@ -191,8 +193,8 @@ def _build_forms(proposal: Proposal) -> OrderedDict: forms[task_key] = ( TaskForm, - reverse('tasks:update', args=[task.pk]), - _('Het takenonderzoek: sessie {} taak {} (traject {})').format( + reverse("tasks:update", args=[task.pk]), + _("Het takenonderzoek: sessie {} taak {} (traject {})").format( session.order, task.order, study.order, @@ -200,7 +202,7 @@ def _build_forms(proposal: Proposal) -> OrderedDict: task, ) - session_end_key = '{}_session_{}_end'.format( + session_end_key = "{}_session_{}_end".format( key_base, session.pk, session, @@ -208,26 +210,25 @@ def _build_forms(proposal: Proposal) -> OrderedDict: forms[session_end_key] = ( TaskEndForm, - reverse('tasks:end', args=[session.pk]), - _('Overzicht van takenonderzoek: sessie {} (traject {})') - .format( + reverse("tasks:end", args=[session.pk]), + _("Overzicht van takenonderzoek: sessie {} (traject {})").format( session.order, study.order, ), session, ) - forms['translated'] = ( + forms["translated"] = ( TranslatedConsentForms, - reverse('proposals:translated', args=[proposal.pk]), - _('Vertaling informed consent formulieren'), + reverse("proposals:translated", args=[proposal.pk]), + _("Vertaling informed consent formulieren"), proposal, ) - forms['data_management'] = ( + forms["data_management"] = ( ProposalDataManagementForm, - reverse('proposals:data_management', args=[proposal.pk]), - _('AVG en Data Management'), + reverse("proposals:data_management", args=[proposal.pk]), + _("AVG en Data Management"), proposal, ) @@ -243,37 +244,42 @@ def get_form_errors(proposal: Proposal) -> list: form_class, url, page_name, obj = form try: kwargs = { - 'instance': obj, + "instance": obj, } if issubclass(form_class, UserKwargModelFormMixin): # This is a bit ugly of course, as we should be getting the # authenticated used. But as only the owner will use this method, # it's the same thing. - kwargs['user'] = proposal.created_by + kwargs["user"] = proposal.created_by if issubclass(form_class, (StudyStartForm, StudyForm)): - kwargs['proposal'] = proposal + kwargs["proposal"] = proposal - if issubclass(form_class, (InterventionForm, ObservationForm, TaskStartForm)): - kwargs['study'] = obj.study + if issubclass( + form_class, (InterventionForm, ObservationForm, TaskStartForm) + ): + kwargs["study"] = obj.study instance = form_class(**kwargs) for field, error in instance.errors.items(): - if field in instance.fields: - troublesome_pages.append({ - 'url': url, - 'page_name': page_name, - }) + troublesome_pages.append( + { + "url": url, + "page_name": page_name, + } + ) break # prevent duplicates for this field except: # If for some reason validation completely fails, we can assume # _something_ is not right and the page contains an error. - troublesome_pages.append({ - 'url': url, - 'page_name': page_name, - }) + troublesome_pages.append( + { + "url": url, + "page_name": page_name, + } + ) return troublesome_pages diff --git a/proposals/validators.py b/proposals/validators.py index c70cd8f65..cb3e1f1ed 100644 --- a/proposals/validators.py +++ b/proposals/validators.py @@ -2,17 +2,13 @@ from django.utils.translation import gettext as _ - class UniqueTitleValidator: - - proposal = None - def __init__(self, proposal = None): + def __init__(self, proposal=None): self.proposal = proposal def __call__(self, value): - # Importing here to prevent circular import from .models import Proposal @@ -22,14 +18,6 @@ def __call__(self, value): qs = qs.exclude(pk=self.proposal.pk) if qs.exists(): - raise forms.ValidationError(_('Er bestaat al een aanvraag met deze ' - 'titel.'), code='unique') - - -def AVGUnderstoodValidator(value): - - if value != True: - raise forms.ValidationError( - _('Je dient kennis genomen te hebben van de AVG om jouw aanvraag in ' - 'te dienen'), code='avg' + raise forms.ValidationError( + _("Er bestaat al een aanvraag met deze " "titel."), code="unique" ) diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index d8d3a4c60..141e94095 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -2,8 +2,7 @@ import datetime -from braces.views import GroupRequiredMixin, LoginRequiredMixin, \ - UserFormKwargsMixin +from braces.views import GroupRequiredMixin, LoginRequiredMixin, UserFormKwargsMixin from django.conf import settings from django.db.models import Q @@ -12,26 +11,46 @@ from django.utils.translation import ugettext_lazy as _ from django.views import generic from django.http import FileResponse -#from easy_pdf.views import PDFTemplateResponseMixin, PDFTemplateView + +# from easy_pdf.views import PDFTemplateResponseMixin, PDFTemplateView from typing import Tuple, Union from main.utils import get_document_contents, get_secretary, is_secretary -from main.views import AllowErrorsOnBackbuttonMixin, CreateView, DeleteView, \ - HumanitiesRequiredMixin, UpdateView, UserAllowedMixin +from main.views import ( + AllowErrorsOnBackbuttonMixin, + CreateView, + DeleteView, + HumanitiesOrPrivilegeRequiredMixin, + UpdateView, + UserAllowedMixin, +) from observations.models import Observation from proposals.utils.validate_proposal import get_form_errors +from proposals.utils.pdf_diff_logic import create_context_pdf, create_context_diff from reviews.mixins import CommitteeMixin, UsersOrGroupsAllowedMixin from reviews.utils.review_utils import start_review, start_review_pre_assessment from studies.models import Documents from ..copy import copy_proposal -from ..forms import ProposalConfirmationForm, ProposalCopyForm, \ - ProposalDataManagementForm, ProposalForm, ProposalStartPracticeForm, \ - ProposalSubmitForm, RevisionProposalCopyForm, AmendmentProposalCopyForm, \ - ProposalUpdateDataManagementForm, TranslatedConsentForms +from ..forms import ( + ProposalConfirmationForm, + ProposalCopyForm, + ProposalDataManagementForm, + ProposalForm, + ProposalStartPracticeForm, + ProposalSubmitForm, + RevisionProposalCopyForm, + AmendmentProposalCopyForm, + ProposalUpdateDataManagementForm, + ProposalUpdateDateStartForm, + TranslatedConsentForms, +) from ..models import Proposal, Wmo from ..utils import generate_pdf, generate_ref_number -from proposals.mixins import ProposalMixin, ProposalContextMixin, \ - PDFTemplateResponseMixin +from proposals.mixins import ( + ProposalMixin, + ProposalContextMixin, + PDFTemplateResponseMixin, +) from proposals.utils.proposal_utils import FilenameFactory @@ -39,120 +58,131 @@ # List views ############ + class BaseProposalsView(LoginRequiredMixin, generic.TemplateView): - title = _('Publiek archief') - body = _('Dit overzicht toont alle goedgekeurde aanvragen.') + title = _("Publiek archief") + body = _("Dit overzicht toont alle goedgekeurde aanvragen.") is_modifiable = False is_submitted = True contains_supervised = False - template_name = 'proposals/proposal_list.html' + template_name = "proposals/proposal_list.html" def get_context_data(self, **kwargs): context = super(BaseProposalsView, self).get_context_data(**kwargs) - context['title'] = self.title - context['body'] = self.body - context['modifiable'] = self.is_modifiable - context['submitted'] = self.is_submitted - context['supervised'] = self.contains_supervised - context['data_url'] = None + context["title"] = self.title + context["body"] = self.body + context["modifiable"] = self.is_modifiable + context["submitted"] = self.is_submitted + context["supervised"] = self.contains_supervised + context["data_url"] = None return context class MyProposalsView(BaseProposalsView): - title = _('Mijn aanvraag') - body = _('Dit overzicht toont al je aanvragen.') + title = _("Mijn aanvraag") + body = _("Dit overzicht toont al je aanvragen.") is_modifiable = True is_submitted = True contains_supervised = True def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['data_url'] = reverse('proposals:api:my_archive',) + context["data_url"] = reverse( + "proposals:api:my_archive", + ) return context class MyConceptsView(BaseProposalsView): - title = _('Mijn conceptaanvragen') - body = _('Dit overzicht toont al je nog niet ingediende aanvragen.') + title = _("Mijn conceptaanvragen") + body = _("Dit overzicht toont al je nog niet ingediende aanvragen.") is_modifiable = True is_submitted = False def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['data_url'] = reverse('proposals:api:my_concepts',) + context["data_url"] = reverse( + "proposals:api:my_concepts", + ) return context class MySubmittedView(BaseProposalsView): - title = _('Mijn ingediende aanvragen') - body = _('Dit overzicht toont al je ingediende aanvragen.') + title = _("Mijn ingediende aanvragen") + body = _("Dit overzicht toont al je ingediende aanvragen.") is_modifiable = False is_submitted = True def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['data_url'] = reverse('proposals:api:my_submitted',) + context["data_url"] = reverse( + "proposals:api:my_submitted", + ) return context class MyCompletedView(BaseProposalsView): - title = _('Mijn afgehandelde aanvragen') - body = _('Dit overzicht toont al je beoordeelde aanvragen.') + title = _("Mijn afgehandelde aanvragen") + body = _("Dit overzicht toont al je beoordeelde aanvragen.") is_modifiable = False is_submitted = True def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['data_url'] = reverse('proposals:api:my_completed',) + context["data_url"] = reverse( + "proposals:api:my_completed", + ) return context class MySupervisedView(BaseProposalsView): - title = _('Mijn aanvragen als eindverantwoordelijke') + title = _("Mijn aanvragen als eindverantwoordelijke") body = _( - 'Dit overzicht toont alle aanvragen waarvan je eindverantwoordelijke ' - 'bent.') + "Dit overzicht toont alle aanvragen waarvan je eindverantwoordelijke " "bent." + ) is_modifiable = True is_submitted = True contains_supervised = True def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['data_url'] = reverse('proposals:api:my_supervised',) + context["data_url"] = reverse( + "proposals:api:my_supervised", + ) return context + class MyPracticeView(BaseProposalsView): - title = _('Mijn oefenaanvragen') - body = _('Dit overzicht toont alle oefenaanvragen waar je als student, \ -onderzoeker of eindverantwoordelijke bij betrokken bent.') + title = _("Mijn oefenaanvragen") + body = _( + "Dit overzicht toont alle oefenaanvragen waar je als student, \ +onderzoeker of eindverantwoordelijke bij betrokken bent." + ) is_modifiable = True is_submitted = False def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['data_url'] = reverse('proposals:api:my_practice',) + context["data_url"] = reverse( + "proposals:api:my_practice", + ) return context class ProposalUsersOnlyArchiveView( - HumanitiesRequiredMixin, - CommitteeMixin, - BaseProposalsView + HumanitiesOrPrivilegeRequiredMixin, CommitteeMixin, BaseProposalsView ): - template_name = 'proposals/proposal_private_archive.html' + template_name = "proposals/proposal_private_archive.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['data_url'] = reverse('proposals:api:archive', args=[self.committee]) + context["data_url"] = reverse("proposals:api:archive", args=[self.committee]) return context @property def title(self): - return "{} - {}".format( - _('Archief'), - self.committee_display_name - ) + return "{} - {}".format(_("Archief"), self.committee_display_name) class ProposalsPublicArchiveView(generic.ListView): @@ -163,19 +193,20 @@ def get_queryset(self): """Returns all the Proposals that have been decided positively upon""" return Proposal.objects.public_archive() + class ProposalsExportView(GroupRequiredMixin, generic.ListView): - context_object_name = 'proposals' + context_object_name = "proposals" group_required = [ settings.GROUP_SECRETARY, settings.GROUP_GENERAL_CHAMBER, - settings.GROUP_LINGUISTICS_CHAMBER + settings.GROUP_LINGUISTICS_CHAMBER, ] - template_name_suffix = '_export_list' + template_name_suffix = "_export_list" def get_queryset(self): """Returns all the Proposals that have been decided positively upon, or a single one if specified in the URL""" - pk = self.kwargs.get('pk') + pk = self.kwargs.get("pk") if pk is not None: return Proposal.objects.filter(pk=pk) @@ -188,26 +219,27 @@ class ChangeArchiveStatusView(GroupRequiredMixin, generic.RedirectView): permanent = False def get_redirect_url(self, *args, **kwargs): - pk = kwargs.get('pk') + pk = kwargs.get("pk") proposal = Proposal.objects.get(pk=pk) proposal.in_archive = not proposal.in_archive proposal.save() committee = proposal.reviewing_committee.name - return reverse('proposals:archive', args=[committee]) + return reverse("proposals:archive", args=[committee]) + ########################## # CRUD actions on Proposal ########################## -class ProposalCreate(ProposalMixin, AllowErrorsOnBackbuttonMixin, CreateView): +class ProposalCreate(ProposalMixin, AllowErrorsOnBackbuttonMixin, CreateView): # Note: template_name is auto-generated to proposal_form.html def get_initial(self): """Sets initial applicant to current User""" initial = super(ProposalCreate, self).get_initial() - initial['applicants'] = [self.request.user] + initial["applicants"] = [self.request.user] return initial def form_valid(self, form): @@ -220,13 +252,14 @@ def form_valid(self, form): def get_context_data(self, **kwargs): """Adds 'create'/'no_back' to template context""" context = super(ProposalCreate, self).get_context_data(**kwargs) - context['create'] = True - context['no_back'] = True + context["create"] = True + context["no_back"] = True return context -class ProposalUpdate(ProposalMixin, ProposalContextMixin, AllowErrorsOnBackbuttonMixin, UpdateView): - +class ProposalUpdate( + ProposalMixin, ProposalContextMixin, AllowErrorsOnBackbuttonMixin, UpdateView +): def form_valid(self, form): """Sets created_by to current user and generates a reference number""" form.instance.reviewing_committee = form.instance.institution.reviewing_chamber @@ -235,23 +268,23 @@ def form_valid(self, form): def get_context_data(self, **kwargs): """Adds 'create'/'no_back' to template context""" context = super(ProposalUpdate, self).get_context_data(**kwargs) - context['create'] = False - context['no_back'] = True + context["create"] = False + context["no_back"] = True return context class ProposalDelete(DeleteView): model = Proposal - success_message = _('Aanvraag verwijderd') + success_message = _("Aanvraag verwijderd") def get_success_url(self): """After deletion, return to the concepts overview""" - return reverse('proposals:my_concepts') + return reverse("proposals:my_concepts") class CompareDocumentsView(UsersOrGroupsAllowedMixin, generic.TemplateView): - template_name = 'proposals/compare_documents.html' + template_name = "proposals/compare_documents.html" group_required = [ settings.GROUP_SECRETARY, settings.GROUP_GENERAL_CHAMBER, @@ -259,16 +292,15 @@ class CompareDocumentsView(UsersOrGroupsAllowedMixin, generic.TemplateView): ] def get_allowed_users(self): - - compare_type = self.kwargs.get('type') - new_pk = self.kwargs.get('new') - attribute = self.kwargs.get('attribute') + compare_type = self.kwargs.get("type") + new_pk = self.kwargs.get("new") + attribute = self.kwargs.get("attribute") model = { - 'documents': Documents, - 'wmo': Wmo, - 'observation': Observation, - 'proposal': Proposal, + "documents": Documents, + "wmo": Wmo, + "observation": Observation, + "proposal": Proposal, }.get(compare_type, None) if model == Proposal: @@ -282,36 +314,31 @@ def get_allowed_users(self): return allowed_users - def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) self.old_file, self.new_file = self._get_files() - context['old_name'] = self.old_file.name - context['old_file'] = self.old_file - context['old_text'] = get_document_contents(self.old_file) - context['new_name'] = self.new_file.name - context['new_file'] = self.new_file - context['new_text'] = get_document_contents(self.new_file) + context["old_name"] = self.old_file.name + context["old_file"] = self.old_file + context["old_text"] = get_document_contents(self.old_file) + context["new_name"] = self.new_file.name + context["new_file"] = self.new_file + context["new_text"] = get_document_contents(self.new_file) return context - - def _get_files(self) -> Tuple[ - Union[None, FieldFile], - Union[None, FieldFile] - ]: - compare_type = self.kwargs.get('type') - old_pk = self.kwargs.get('old') - new_pk = self.kwargs.get('new') - attribute = self.kwargs.get('attribute') + def _get_files(self) -> Tuple[Union[None, FieldFile], Union[None, FieldFile]]: + compare_type = self.kwargs.get("type") + old_pk = self.kwargs.get("old") + new_pk = self.kwargs.get("new") + attribute = self.kwargs.get("attribute") model = { - 'documents': Documents, - 'wmo': Wmo, - 'observation': Observation, - 'proposal': Proposal, + "documents": Documents, + "wmo": Wmo, + "observation": Observation, + "proposal": Proposal, }.get(compare_type, None) if model is None: @@ -327,48 +354,50 @@ def _get_files(self) -> Tuple[ # Other actions on Proposal ########################### class ProposalStart(generic.TemplateView): - template_name = 'proposals/proposal_start.html' + template_name = "proposals/proposal_start.html" def get_context_data(self, **kwargs): """Adds secretary and link to regulations to template context""" context = super(ProposalStart, self).get_context_data(**kwargs) - context['secretary'] = get_secretary() + context["secretary"] = get_secretary() return context - + + class TranslatedConsentFormsView(UpdateView): model = Proposal form_class = TranslatedConsentForms - template_name = 'proposals/translated_consent_forms.html' + template_name = "proposals/translated_consent_forms.html" def get_next_url(self): - '''Go to the consent form upload page''' - return reverse('proposals:consent', args=(self.object.pk,)) + """Go to the consent form upload page""" + return reverse("proposals:consent", args=(self.object.pk,)) def get_back_url(self): """Return to the overview of the last Study""" - return reverse('studies:design_end', args=(self.object.last_study().pk,)) + return reverse("studies:design_end", args=(self.object.last_study().pk,)) class ProposalDataManagement(UpdateView): model = Proposal form_class = ProposalDataManagementForm - template_name = 'proposals/proposal_data_management.html' + template_name = "proposals/proposal_data_management.html" def get_next_url(self): """Continue to the submission view""" - return reverse('proposals:submit', args=(self.object.pk,)) + return reverse("proposals:submit", args=(self.object.pk,)) def get_back_url(self): """Return to the consent form overview of the last Study""" - return reverse('proposals:consent', args=(self.object.pk,)) + return reverse("proposals:consent", args=(self.object.pk,)) class ProposalUpdateDataManagement(GroupRequiredMixin, generic.UpdateView): """ Allows the secretary to change the Data Management Plan on the Proposal level """ + model = Proposal - template_name = 'proposals/proposal_update_attachments.html' + template_name = "proposals/proposal_update_attachments.html" form_class = ProposalUpdateDataManagementForm group_required = settings.GROUP_SECRETARY @@ -384,33 +413,62 @@ def form_valid(self, form): def get_success_url(self): """Continue to the URL specified in the 'next' POST parameter""" - return reverse('reviews:detail', args=[self.object.latest_review().pk]) + return reverse("reviews:detail", args=[self.object.latest_review().pk]) + + +class ProposalUpdateDateStart(GroupRequiredMixin, generic.UpdateView): + """ + Allows the secretary to change the date_start on the Proposal level + """ + + model = Proposal + template_name = "proposals/proposal_update_date_start.html" + form_class = ProposalUpdateDateStartForm + group_required = settings.GROUP_SECRETARY + + def form_valid(self, form): + ret = super().form_valid(form) + # Always regenerate the PDF after updating the DMP + # This is necessary, as the canonical PDF protection might already + # have kicked in if the secretary changes the documents later than + # we initially expected. + self.object.generate_pdf(force_overwrite=True) + + return ret + + def get_success_url(self): + """Continue to the URL specified in the 'next' POST parameter""" + return reverse("reviews:detail", args=[self.object.latest_review().pk]) -class ProposalSubmit(ProposalContextMixin, AllowErrorsOnBackbuttonMixin, UpdateView, ): +class ProposalSubmit( + ProposalContextMixin, + AllowErrorsOnBackbuttonMixin, + UpdateView, +): model = Proposal form_class = ProposalSubmitForm - template_name = 'proposals/proposal_submit.html' - success_message = _('Wijzigingen opgeslagen') + template_name = "proposals/proposal_submit.html" + success_message = _("Wijzigingen opgeslagen") def get_form_kwargs(self): """Sets the Proposal as a form kwarg""" kwargs = super(ProposalSubmit, self).get_form_kwargs() - kwargs['proposal'] = self.get_object() + kwargs["proposal"] = self.get_object() # Required for examining POST data # to check for js-redirect-submit - kwargs['request'] = self.request + kwargs["request"] = self.request return kwargs def get_context_data(self, **kwargs): context = super(ProposalSubmit, self).get_context_data(**kwargs) - context['troublesome_pages'] = get_form_errors(self.get_object()) - context['pagenr'] = self._get_page_number() - context['is_supervisor_edit_phase'] = self.is_supervisor_edit_phase() - context['start_date_warning'] = self.check_start_date() + context["troublesome_pages"] = get_form_errors(self.get_object()) + context["pagenr"] = self._get_page_number() + context["is_supervisor_edit_phase"] = self.is_supervisor_edit_phase() + context["start_date_warning"] = self.check_start_date() return context @@ -427,40 +485,43 @@ def check_start_date(self): return start_date <= two_weeks_from_now def is_supervisor_edit_phase(self): - if self.object.status == self.object.SUBMITTED_TO_SUPERVISOR: + if self.object.status == self.object.Statuses.SUBMITTED_TO_SUPERVISOR: return True - return False def form_valid(self, form): """ - - Save the PDF on the Proposal - - Start the review process on submission (though not for practice Proposals) + Start a review for this proposal and return a response. """ - - success_url = super(ProposalSubmit, self).form_valid(form) - if 'save_back' not in self.request.POST and 'js-redirect-submit' not in self.request.POST: - proposal = self.get_object() - proposal.generate_pdf() - if not proposal.is_practice() and proposal.status == Proposal.DRAFT: - start_review(proposal) - return success_url + # We pick up the response from the base class first so that + # the fields on the Submit page get saved correctly. In the end, + # this is still an UpdateView + success_response = super().form_valid(form) + # We then defer all submission logic to the utility code. + # Checks for practice proposals and starting the right + # kind of review happen over there. + proposal = form.instance + if ( + "save_back" not in self.request.POST + and "js-redirect-submit" not in self.request.POST + ): + start_review(proposal) + return success_response def get_next_url(self): """After submission, go to the thank-you view. Unless a supervisor is editing the proposal during their review, in that case: go to their decide page""" - if self.is_supervisor_edit_phase() and \ - self.current_user_is_supervisor(): + if self.is_supervisor_edit_phase() and self.current_user_is_supervisor(): review = self.object.latest_review() decision = review.decision_set.get(reviewer=self.request.user) - return reverse('reviews:decide', args=(decision.pk,)) + return reverse("reviews:decide", args=(decision.pk,)) - return reverse('proposals:submitted', args=(self.object.pk,)) + return reverse("proposals:submitted", args=(self.object.pk,)) def get_back_url(self): """Return to the data management view""" - return reverse('proposals:data_management', args=(self.object.pk,)) + return reverse("proposals:data_management", args=(self.object.pk,)) def _get_page_number(self): if self.object.is_pre_assessment: @@ -474,26 +535,26 @@ def _get_page_number(self): class ProposalSubmitted(generic.DetailView): model = Proposal - template_name = 'proposals/proposal_submitted.html' + template_name = "proposals/proposal_submitted.html" class ProposalConfirmation(GroupRequiredMixin, generic.UpdateView): model = Proposal - template_name = 'proposals/proposal_confirmation.html' + template_name = "proposals/proposal_confirmation.html" form_class = ProposalConfirmationForm group_required = settings.GROUP_SECRETARY def get_success_url(self): """On confirmation, return to the Review archive""" committee = self.object.reviewing_committee.name - return reverse('reviews:my_archive', args=[committee]) + return reverse("reviews:my_archive", args=[committee]) class ProposalCopy(UserFormKwargsMixin, CreateView): model = Proposal form_class = ProposalCopyForm - success_message = _('Aanvraag gekopieerd') - template_name = 'proposals/proposal_copy.html' + success_message = _("Aanvraag gekopieerd") + template_name = "proposals/proposal_copy.html" def get_initial(self): """Sets initial value of is_revision to False. It's a hidden field, @@ -501,14 +562,14 @@ def get_initial(self): behaviour for this class' subclasses """ initial = super(ProposalCopy, self).get_initial() - initial['is_revision'] = False + initial["is_revision"] = False return initial def form_valid(self, form): """Create a copy of the selected Proposal""" form.instance = copy_proposal( - form.cleaned_data['parent'], - form.cleaned_data['is_revision'], + form.cleaned_data["parent"], + form.cleaned_data["is_revision"], self.request.user, ) return super(ProposalCopy, self).form_valid(form) @@ -516,8 +577,8 @@ def form_valid(self, form): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['is_revision'] = False - context['is_amendment'] = False + context["is_revision"] = False + context["is_amendment"] = False return context @@ -528,13 +589,13 @@ class ProposalCopyRevision(ProposalCopy): def get_initial(self): """Sets initial value of is_revision to True""" initial = super(ProposalCopyRevision, self).get_initial() - initial['is_revision'] = True + initial["is_revision"] = True return initial def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['is_revision'] = True + context["is_revision"] = True return context @@ -545,25 +606,26 @@ class ProposalCopyAmendment(ProposalCopy): def get_initial(self): """Sets initial value of is_revision to True""" initial = super(ProposalCopyAmendment, self).get_initial() - initial['is_revision'] = True + initial["is_revision"] = True return initial def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['is_amendment'] = True + context["is_amendment"] = True return context class ProposalAsPdf( - LoginRequiredMixin, - generic.DetailView, - PDFTemplateResponseMixin, + LoginRequiredMixin, + generic.DetailView, + PDFTemplateResponseMixin, ): model = Proposal # The PDF mixin generates a filename with this factory - filename_factory = FilenameFactory('Proposal') + filename_factory = FilenameFactory("Proposal") + template_name = "proposals/proposal_pdf.html" def get(self, request, *args, **kwargs): # First, check if we should use a pregenerated pdf, if we have one @@ -586,55 +648,47 @@ def get_object(self, *args, **kwargs): self.object = super().get_object(*args, **kwargs) return self.object - def get_template_names(self): - """Determine the correct PDf template for given proposal""" - proposal = self.get_object() - self.template_name = proposal.pdf_template_name - return [self.template_name] - def get_context_data(self, **kwargs): - """Adds 'BASE_URL' to template context""" - context = super(ProposalAsPdf, self).get_context_data(**kwargs) - context['BASE_URL'] = settings.BASE_URL - - documents = { - 'extra': [] - } - for document in Documents.objects.filter(proposal=self.object).all(): - if document.study: - documents[document.study.pk] = document - else: - documents['extra'].append(document) - context['documents'] = documents + context = super().get_context_data(**kwargs) + + context = create_context_pdf(context, self.object) + return context class ProposalDifference(LoginRequiredMixin, generic.DetailView): model = Proposal - template_name = 'proposals/proposal_diff.html' + template_name = "proposals/proposal_diff.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context = create_context_diff(context, self.object.parent, self.object) + + return context ######################## # Preliminary assessment ######################## class ProposalStartPreAssessment(ProposalStart): - template_name = 'proposals/proposal_start_pre_assessment.html' + template_name = "proposals/proposal_start_pre_assessment.html" class PreAssessmentMixin(ProposalMixin): def get_form_kwargs(self): """Sets is_pre_assessment as a form kwarg""" kwargs = super(PreAssessmentMixin, self).get_form_kwargs() - kwargs['is_pre_assessment'] = True + kwargs["is_pre_assessment"] = True return kwargs def get_next_url(self): """If the Proposal has a Wmo model attached, go to update, else, go to create""" proposal = self.object - if hasattr(proposal, 'wmo'): - return reverse('proposals:wmo_update_pre', args=(proposal.pk,)) + if hasattr(proposal, "wmo"): + return reverse("proposals:wmo_update_pre", args=(proposal.pk,)) else: - return reverse('proposals:wmo_create_pre', args=(proposal.pk,)) + return reverse("proposals:wmo_create_pre", args=(proposal.pk,)) class ProposalCreatePreAssessment(PreAssessmentMixin, ProposalCreate): @@ -649,55 +703,42 @@ class ProposalUpdatePreAssessment(PreAssessmentMixin, ProposalUpdate): class ProposalSubmitPreAssessment(ProposalSubmit): - def form_valid(self, form): - """ - Performs actions after saving the form - - Save the preassessment PDF on the Proposal - - End the preassessment phase - """ - # Note that the below method does NOT call the ProposalSubmit method, as that would generate the full PDF. - success_url = super(ProposalSubmitPreAssessment, self).form_valid(form) - if 'save_back' not in self.request.POST and 'js-redirect-submit' not in self.request.POST: - proposal = self.get_object() - proposal.generate_pdf() - start_review_pre_assessment(proposal) - return success_url - def get_next_url(self): """After submission, go to the thank-you view""" - return reverse('proposals:submitted_pre', args=(self.object.pk,)) + return reverse("proposals:submitted_pre", args=(self.object.pk,)) def get_back_url(self): """Return to the Wmo overview""" - return reverse('proposals:wmo_update_pre', args=(self.object.pk,)) + return reverse("proposals:wmo_update_pre", args=(self.object.pk,)) class ProposalSubmittedPreAssessment(ProposalSubmitted): - template_name = 'proposals/proposal_submitted.html' + template_name = "proposals/proposal_submitted.html" ############# # Pre-Aproved ############# + class ProposalStartPreApproved(ProposalStart): - template_name = 'proposals/proposal_start_pre_approved.html' + template_name = "proposals/proposal_start_pre_approved.html" class PreApprovedMixin(ProposalMixin): def get_form_kwargs(self): """Sets is_pre_approved as a form kwarg""" kwargs = super(PreApprovedMixin, self).get_form_kwargs() - kwargs['is_pre_approved'] = True + kwargs["is_pre_approved"] = True return kwargs def get_next_url(self): proposal = self.object - return reverse('proposals:submit_pre_approved', args=(proposal.pk,)) + return reverse("proposals:submit_pre_approved", args=(proposal.pk,)) class ProposalCreatePreApproved(PreApprovedMixin, ProposalCreate): - template_name = 'proposals/proposal_form_pre_approved.html' + template_name = "proposals/proposal_form_pre_approved.html" def form_valid(self, form): """Sets is_pre_approved to True""" @@ -710,71 +751,62 @@ class ProposalUpdatePreApproved(PreApprovedMixin, ProposalUpdate): class ProposalSubmitPreApproved(ProposalSubmit): - def form_valid(self, form): - """ - Performs actions after saving the form - - Save the pre_approved PDF on the Proposal - - End the draft phase and start the appropiate review phase (in super function) - """ - success_url = super(ProposalSubmitPreApproved, self).form_valid(form) - if 'save_back' not in self.request.POST: - proposal = self.get_object() - proposal.generate_pdf() - return success_url - def get_next_url(self): """After submission, go to the thank-you view""" - return reverse('proposals:submitted_pre_approved', - args=(self.object.pk,)) + return reverse("proposals:submitted_pre_approved", args=(self.object.pk,)) def get_back_url(self): """Return to the update page""" - return reverse('proposals:update_pre_approved', args=(self.object.pk,)) + return reverse("proposals:update_pre_approved", args=(self.object.pk,)) class ProposalSubmittedPreApproved(ProposalSubmitted): - template_name = 'proposals/proposal_submitted.html' + template_name = "proposals/proposal_submitted.html" ########## # Practice ########## class ProposalStartPractice(generic.FormView): - template_name = 'proposals/proposal_start_practice.html' + template_name = "proposals/proposal_start_practice.html" form_class = ProposalStartPracticeForm def get_context_data(self, **kwargs): """Adds 'secretary', 'is_practice' and 'no_back' to template context""" context = super(ProposalStartPractice, self).get_context_data(**kwargs) - context['secretary'] = get_secretary() - context['is_practice'] = True - context['no_back'] = True + context["secretary"] = get_secretary() + context["is_practice"] = True + context["no_back"] = True return context def get_success_url(self): """Go to the creation for a practice Proposal""" - return reverse('proposals:create_practice', - args=(self.request.POST['practice_reason'],)) + return reverse( + "proposals:create_practice", args=(self.request.POST["practice_reason"],) + ) class ProposalCreatePractice(ProposalCreate): def get_context_data(self, **kwargs): """Adds 'is_practice' to template context""" context = super(ProposalCreatePractice, self).get_context_data(**kwargs) - context['is_practice'] = True + context["is_practice"] = True return context def get_form_kwargs(self): """Sets in_course as a form kwarg""" kwargs = super(ProposalCreatePractice, self).get_form_kwargs() - kwargs['in_course'] = self.kwargs['reason'] == Proposal.COURSE + kwargs["in_course"] = self.kwargs["reason"] == Proposal.PracticeReasons.COURSE return kwargs def form_valid(self, form): """Sets in_course and is_exploration""" - form.instance.in_course = self.kwargs['reason'] == Proposal.COURSE - form.instance.is_exploration = self.kwargs[ - 'reason'] == Proposal.EXPLORATION + form.instance.in_course = ( + self.kwargs["reason"] == Proposal.PracticeReasons.COURSE + ) + form.instance.is_exploration = ( + self.kwargs["reason"] == Proposal.PracticeReasons.EXPLORATION + ) return super(ProposalCreatePractice, self).form_valid(form) @@ -782,5 +814,5 @@ class ProposalUpdatePractice(ProposalUpdate): def get_form_kwargs(self): """Sets in_course as a form kwarg""" kwargs = super(ProposalUpdatePractice, self).get_form_kwargs() - kwargs['in_course'] = self.object.in_course + kwargs["in_course"] = self.object.in_course return kwargs diff --git a/proposals/views/study_views.py b/proposals/views/study_views.py index df8eb017e..cb53258a0 100644 --- a/proposals/views/study_views.py +++ b/proposals/views/study_views.py @@ -14,12 +14,12 @@ class StudyStart(AllowErrorsOnBackbuttonMixin, UpdateView): model = Proposal form_class = StudyStartForm - template_name = 'proposals/study_start.html' + template_name = "proposals/study_start.html" def get_form_kwargs(self): """Sets the Proposal as a form kwarg""" kwargs = super(StudyStart, self).get_form_kwargs() - kwargs['proposal'] = self.object + kwargs["proposal"] = self.object return kwargs def form_valid(self, form): @@ -33,7 +33,7 @@ def form_valid(self, form): for n in range(proposal.studies_number): order = n + 1 s, _ = Study.objects.get_or_create(proposal=proposal, order=order) - s.name = self.request.POST.get('study_name_' + str(order)) + s.name = self.request.POST.get("study_name_" + str(order)) s.save() # Delete Studies @@ -47,30 +47,32 @@ def form_valid(self, form): def get_next_url(self): """Continue to the first Study""" proposal = self.object - return reverse('studies:update', args=(proposal.first_study().pk,)) + return reverse("studies:update", args=(proposal.first_study().pk,)) def get_back_url(self): """Return to the Wmo overview""" - return reverse('proposals:wmo_update', args=(self.object.wmo.pk,)) + return reverse("proposals:wmo_update", args=(self.object.wmo.pk,)) class StudyConsent(AllowErrorsOnBackbuttonMixin, FormSetUpdateView): """ Allows the applicant to add informed consent to their Studies """ - success_message = _('Consent opgeslagen') - template_name = 'proposals/study_consent.html' + + success_message = _("Consent opgeslagen") + template_name = "proposals/study_consent.html" form = StudyConsentForm extra = 10 - + def get(self, request, *args, **kwargs): """A bit of a hacky override to ensure only 2 extra document forms apart from the study document forms are presented""" - proposal = Proposal.objects.get(pk=self.kwargs.get('pk')) + proposal = Proposal.objects.get(pk=self.kwargs.get("pk")) - self.extra = (len(proposal.study_set.all()) + self.extra) - \ - len(self.get_queryset().all()) + self.extra = (len(proposal.study_set.all()) + self.extra) - len( + self.get_queryset().all() + ) return super(StudyConsent, self).get(request, *args, **kwargs) @@ -78,13 +80,13 @@ def get_context_data(self, *args, **kwargs): """Setting the progress on the context""" # (??) context = super().get_context_data(*args, **kwargs) # The following is used by the progress bar - proposal = Proposal.objects.get(pk=self.kwargs.get('pk')) - context['proposal'] = proposal + proposal = Proposal.objects.get(pk=self.kwargs.get("pk")) + context["proposal"] = proposal initial = [] for i in range(self.extra): - initial.append({'proposal': proposal.pk}) - context['formset'].initial_extra = initial + initial.append({"proposal": proposal.pk}) + context["formset"].initial_extra = initial # Tell the template if any studies need external forms studies = Study.objects.filter(proposal=proposal) @@ -94,7 +96,7 @@ def get_context_data(self, *args, **kwargs): return context def get_queryset(self): - proposal = Proposal.objects.get(pk=self.kwargs.get('pk')) + proposal = Proposal.objects.get(pk=self.kwargs.get("pk")) documents = Documents.objects.filter(proposal=proposal) if len(documents) == 0: @@ -105,16 +107,15 @@ def get_queryset(self): return documents - def get_next_url(self): """ If there is another Study in this Proposal, continue to that one. Otherwise, go to the data management view. """ - proposal = Proposal.objects.get(pk=self.kwargs.get('pk')) - return reverse('proposals:data_management', args=(proposal.pk,)) + proposal = Proposal.objects.get(pk=self.kwargs.get("pk")) + return reverse("proposals:data_management", args=(proposal.pk,)) def get_back_url(self): """Return to the Study design view""" - proposal = Proposal.objects.get(pk=self.kwargs.get('pk')) - return reverse('proposals:translated', args=(proposal.pk,)) + proposal = Proposal.objects.get(pk=self.kwargs.get("pk")) + return reverse("proposals:translated", args=(proposal.pk,)) diff --git a/proposals/views/wmo_views.py b/proposals/views/wmo_views.py index a3669f6eb..15a049437 100644 --- a/proposals/views/wmo_views.py +++ b/proposals/views/wmo_views.py @@ -6,7 +6,7 @@ from django.views.decorators.csrf import csrf_exempt from django.utils.translation import ugettext_lazy as _ -from main.models import YES, DOUBT +from main.models import YesNoDoubt from main.views import CreateView, UpdateView, AllowErrorsOnBackbuttonMixin from main.utils import get_secretary @@ -24,7 +24,7 @@ class WmoMixin(AllowErrorsOnBackbuttonMixin, object): def get_context_data(self, **kwargs): """Setting the Proposal on the context""" context = super(WmoMixin, self).get_context_data(**kwargs) - context['proposal'] = self.get_proposal() + context["proposal"] = self.get_proposal() return context def get_next_url(self): @@ -33,15 +33,19 @@ def get_next_url(self): else, start the Wmo application. """ wmo = self.object - if wmo.status == Wmo.NO_WMO: - return reverse('proposals:study_start', args=(wmo.proposal.pk,)) + if wmo.status == Wmo.WMOStatuses.NO_WMO: + return reverse("proposals:study_start", args=(wmo.proposal.pk,)) else: - return reverse('proposals:wmo_application', args=(wmo.pk,)) + return reverse("proposals:wmo_application", args=(wmo.pk,)) def get_back_url(self): """Return to the Proposal overview, or practice overview if we are in practice mode""" proposal = self.get_proposal() - url = 'proposals:update_practice' if proposal.is_practice() else 'proposals:update' + url = ( + "proposals:update_practice" + if proposal.is_practice() + else "proposals:update" + ) return reverse(url, args=(proposal.pk,)) def get_proposal(self): @@ -49,7 +53,7 @@ def get_proposal(self): class WmoCreate(WmoMixin, CreateView): - success_message = _('WMO-gegevens opgeslagen') + success_message = _("WMO-gegevens opgeslagen") def form_valid(self, form): """Saves the Proposal on the WMO instance""" @@ -58,11 +62,11 @@ def form_valid(self, form): def get_proposal(self): """Retrieves the Proposal from the pk kwarg""" - return Proposal.objects.get(pk=self.kwargs['pk']) + return Proposal.objects.get(pk=self.kwargs["pk"]) class WmoUpdate(WmoMixin, UpdateView): - success_message = _('WMO-gegevens bewerkt') + success_message = _("WMO-gegevens bewerkt") def get_proposal(self): """Retrieves the Proposal from the form object""" @@ -75,30 +79,30 @@ def get_proposal(self): class WmoApplication(UpdateView): model = Wmo form_class = WmoApplicationForm - template_name = 'proposals/wmo_application.html' + template_name = "proposals/wmo_application.html" def get_context_data(self, **kwargs): """Setting the Proposal on the context""" context = super(WmoApplication, self).get_context_data(**kwargs) - context['proposal'] = self.object.proposal + context["proposal"] = self.object.proposal return context def get_next_url(self): """Continue to the definition of a Study if we have completed the Wmo application""" wmo = self.object - if wmo.status == Wmo.WAITING: - return reverse('proposals:wmo_application', args=(wmo.pk,)) + if wmo.status == Wmo.WMOStatuses.WAITING: + return reverse("proposals:wmo_application", args=(wmo.pk,)) else: - return reverse('proposals:study_start', args=(wmo.proposal.pk,)) + return reverse("proposals:study_start", args=(wmo.proposal.pk,)) def get_back_url(self): """Return to the Wmo overview""" - return reverse('proposals:wmo_update', args=(self.object.pk,)) + return reverse("proposals:wmo_update", args=(self.object.pk,)) class WmoCheck(generic.FormView): form_class = WmoCheckForm - template_name = 'proposals/wmo_check.html' + template_name = "proposals/wmo_check.html" ######################## @@ -108,27 +112,28 @@ class PreAssessmentMixin(object): def get_next_url(self): """Different continue URL for pre-assessment Proposals""" wmo = self.object - if wmo.status == Wmo.NO_WMO: - return reverse('proposals:submit_pre', args=(self.object.proposal.pk,)) + if wmo.status == Wmo.WMOStatuses.NO_WMO: + return reverse("proposals:submit_pre", args=(self.object.proposal.pk,)) else: - return reverse('proposals:wmo_application_pre', args=(wmo.pk,)) + return reverse("proposals:wmo_application_pre", args=(wmo.pk,)) def get_back_url(self): """Different return URL for pre-assessment Proposals""" - return reverse('proposals:update_pre', args=(self.object.proposal.pk,)) + return reverse("proposals:update_pre", args=(self.object.proposal.pk,)) class WmoCreatePreAssessment(PreAssessmentMixin, WmoCreate): pass + class WmoUpdatePreAssessment(PreAssessmentMixin, WmoUpdate): pass -class WmoApplicationPreAssessment(PreAssessmentMixin, WmoApplication): +class WmoApplicationPreAssessment(PreAssessmentMixin, WmoApplication): def get_next_url(self): """Different continue URL for pre-assessment Proposals""" - return reverse('proposals:submit_pre', args=(self.object.proposal.pk,)) + return reverse("proposals:submit_pre", args=(self.object.proposal.pk,)) ################ @@ -139,27 +144,34 @@ def check_wmo(request): """ This call checks which WMO message should be generated. """ - is_metc = request.POST.get('metc') == YES - is_medical = request.POST.get('medical') == YES + is_metc = request.POST.get("metc") == YesNoDoubt.YES + is_medical = request.POST.get("medical") == YesNoDoubt.YES - doubt = request.POST.get('metc') == DOUBT or request.POST.get('medical') == DOUBT + doubt = ( + request.POST.get("metc") == YesNoDoubt.DOUBT + or request.POST.get("medical") == YesNoDoubt.DOUBT + ) # Default message: OK. - message = _('Je onderzoek hoeft niet te worden beoordeeld door de METC.') - message_class = 'info' + message = _("Je onderzoek hoeft niet te worden beoordeeld door de METC.") + message_class = "info" needs_metc = False # On doubt, contact secretary. if doubt: secretary = get_secretary() - message = _('Neem contact op met {secretary} om de twijfels weg te nemen.').format(link='mailto:'+ secretary.email , secretary=secretary.get_full_name()) - message_class = 'warning' + message = _( + 'Neem contact op met {secretary} om de twijfels weg te nemen.' + ).format(link="mailto:" + secretary.email, secretary=secretary.get_full_name()) + message_class = "warning" needs_metc = True # Otherwise, METC review is necessary for METC studies (obviously) and # studies that have medical research questions or define user behavior elif is_metc or is_medical: - message = _('Je onderzoek zal moeten worden beoordeeld door de METC.') - message_class = 'warning' + message = _("Je onderzoek zal moeten worden beoordeeld door de METC.") + message_class = "warning" needs_metc = True - return JsonResponse({'needs_metc': needs_metc, 'message': message, 'message_class': message_class}) + return JsonResponse( + {"needs_metc": needs_metc, "message": message, "message_class": message_class} + ) diff --git a/proposals/widgets.py b/proposals/widgets.py index 4660d4af4..3c755d8aa 100644 --- a/proposals/widgets.py +++ b/proposals/widgets.py @@ -6,7 +6,6 @@ except ImportError: # Define a dummy class if we can't import LDAPBackend for some reason class LDAPBackend(object): - def populate_user(self, uid): pass @@ -16,14 +15,14 @@ class SelectUser(forms.Select): Custom widget to allow a LDAP user to be entered through Select2. Used in combination with an ajax call to main:user_search """ + allow_multiple_selected = False ldap = LDAPBackend() def value_from_datadict(self, data, files, name): - value = data.get(name, None) - if value and value.startswith('ldap_'): + if value and value.startswith("ldap_"): # Strip the ldap_ from the string uid = value[5:] @@ -31,9 +30,12 @@ def value_from_datadict(self, data, files, name): user_object = self.ldap.populate_user(uid) # Add the user as a valid option - self.choices.append((user_object.pk, - u'{}: {}'.format(user_object.username, - user_object.get_full_name()))) + self.choices.append( + ( + user_object.pk, + "{}: {}".format(user_object.username, user_object.get_full_name()), + ) + ) # Redefine the chosen option to the pk of the new user object value = str(user_object.pk) @@ -46,6 +48,7 @@ class SelectMultipleUser(forms.Select): Custom widget to allow multiple LDAP users to be entered through Select2. Used in combination with an ajax call to main:user_search """ + allow_multiple_selected = True ldap = LDAPBackend() @@ -58,7 +61,7 @@ def value_from_datadict(self, data, files, name): for i, user in enumerate(values): # if the user id starts with ldap_, we need to add that user to our local cache - if user.startswith('ldap_'): + if user.startswith("ldap_"): # Strip the ldap_ from the string uid = user[5:] @@ -66,7 +69,14 @@ def value_from_datadict(self, data, files, name): user_object = self.ldap.populate_user(uid) # Add the user as a valid option - self.choices.append((user_object.pk, u'{}: {}'.format(user_object.username, user_object.get_full_name()))) + self.choices.append( + ( + user_object.pk, + "{}: {}".format( + user_object.username, user_object.get_full_name() + ), + ) + ) # Redefine the chosen option to the pk of the new user object values[i] = str(user_object.pk) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..2ca0d1293 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,7 @@ +[tool.djlint] +profile="django" +extend_exclude="docs,reviews/templates/reviews/vue_templates/,proposals/templates/proposals/vue_templates/" +max-blank-lines=3 +blank_line_after_tag="load,extends,endblock" +format_css=true +format_js=false # Disabled till we can solve our django-in-js situation diff --git a/requirements.in b/requirements.in index e3cd60377..72c5bbfd2 100644 --- a/requirements.in +++ b/requirements.in @@ -7,7 +7,7 @@ django-impersonate django-simple-menu django-debug-toolbar djangorestframework -djangosaml2<1.7 # 1.7 adds a logout bug... +djangosaml2 mysqlclient<2 xhtml2pdf sphinx @@ -21,7 +21,9 @@ pygments requests -e git+https://github.com/UiL-OTS-labs/django-shared-core.git@v2.0.10#egg=uil-django-core -e git+https://github.com/UiL-OTS-labs/python-docx2txt#egg=docx2txt -cdh-django-core[federated-auth] @ git+https://github.com/DH-IT-Portal-Development/django-shared-core.git@v3.1.0-alpha-4 +cdh-django-core[federated-auth] @ git+https://github.com/CentreForDigitalHumanities/django-shared-core.git@v3.1.0 python-magic pdftotext bpython +black +djlint \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index f7dcf4887..bceff8141 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ # via -r requirements.in -e git+https://github.com/UiL-OTS-labs/django-shared-core.git@v2.0.10#egg=uil-django-core # via -r requirements.in -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx arabic-reshaper==3.0.0 # via xhtml2pdf @@ -19,35 +19,46 @@ asn1crypto==1.5.1 # oscrypto # pyhanko # pyhanko-certvalidator -babel==2.12.1 +babel==2.14.0 # via sphinx +black==24.2.0 + # via -r requirements.in blessed==1.20.0 # via curtsies bpython==0.24 # via -r requirements.in -cdh-django-core @ git+https://github.com/DH-IT-Portal-Development/django-shared-core.git@v3.1.0-alpha-4 +cdh-django-core[federated-auth] @ git+https://github.com/CentreForDigitalHumanities/django-shared-core.git@v3.1.0 # via -r requirements.in -certifi==2023.7.22 +certifi==2024.2.2 # via requests cffi==1.16.0 # via cryptography -charset-normalizer==3.3.0 +chardet==5.2.0 + # via reportlab +charset-normalizer==3.3.2 # via requests click==8.1.7 - # via pyhanko + # via + # black + # djlint + # pyhanko closure==20191111 # via uil-django-core -cryptography==41.0.4 +colorama==0.4.6 + # via djlint +cryptography==42.0.5 # via # pyhanko # pyhanko-certvalidator # pyopenssl # pysaml2 +cssbeautifier==1.15.1 + # via djlint cssselect2==0.7.0 # via svglib curtsies==0.4.2 # via bpython -cwcwidth==0.1.8 +cwcwidth==0.1.9 # via # bpython # curtsies @@ -57,7 +68,7 @@ defusedxml==0.7.1 # pysaml2 deprecated==1.2.14 # via cdh-django-core -django==3.2.21 +django==3.2.25 # via # -r requirements.in # cdh-django-core @@ -72,19 +83,19 @@ django==3.2.21 # djangosaml2 # sphinxcontrib-django # uil-django-core -django-auth-ldap==4.5.0 +django-auth-ldap==4.6.0 # via -r requirements.in django-braces==1.15.0 # via -r requirements.in -django-debug-toolbar==4.2.0 +django-debug-toolbar==4.3.0 # via -r requirements.in django-extensions==3.2.3 # via -r requirements.in -django-impersonate==1.9.1 +django-impersonate==1.9.2 # via -r requirements.in django-modeltranslation==0.18.11 # via -r requirements.in -django-simple-menu==2.1.2.post1 +django-simple-menu==2.1.3 # via -r requirements.in django-user-agents==0.4.0 # via -r requirements.in @@ -96,52 +107,78 @@ djangosaml2==1.6.0 # via # -r requirements.in # cdh-django-core -docutils==0.18.1 +djlint==1.34.1 + # via -r requirements.in +docutils==0.20.1 # via # sphinx # sphinx-rtd-theme -elementpath==4.1.5 +editorconfig==0.12.4 + # via + # cssbeautifier + # jsbeautifier +elementpath==4.4.0 # via xmlschema -greenlet==2.0.2 +greenlet==3.0.3 # via bpython +html-tag-names==0.1.2 + # via djlint +html-void-elements==0.1.0 + # via djlint html5lib==1.1 # via # -r requirements.in # xhtml2pdf -idna==3.4 +idna==3.6 # via requests imagesize==1.4.1 # via sphinx -jinja2==3.1.2 +jinja2==3.1.3 # via sphinx +jsbeautifier==1.15.1 + # via + # cssbeautifier + # djlint +json5==0.9.22 + # via djlint lesscpy==0.15.1 # via uil-django-core -lxml==4.9.3 +lxml==5.1.0 # via svglib -markupsafe==2.1.3 +markupsafe==2.1.5 # via jinja2 +mypy-extensions==1.0.0 + # via black mysqlclient==1.4.6 # via -r requirements.in oscrypto==1.3.0 # via pyhanko-certvalidator -packaging==23.2 - # via sphinx -pbr==5.11.1 +packaging==24.0 + # via + # black + # sphinx +pathspec==0.12.1 + # via + # black + # djlint +pbr==6.0.0 # via sphinxcontrib-apidoc pdftotext==2.2.2 # via -r requirements.in -pillow==10.0.1 +pillow==10.2.0 # via # -r requirements.in # reportlab # xhtml2pdf +platformdirs==4.2.0 + # via black ply==3.11 # via lesscpy pprintpp==0.4.0 # via sphinxcontrib-django pscript==0.7.7 # via vbuild -pyasn1==0.5.0 +pyasn1==0.5.1 # via # pyasn1-modules # python-ldap @@ -149,38 +186,38 @@ pyasn1-modules==0.3.0 # via python-ldap pycparser==2.21 # via cffi -pygments==2.16.1 +pygments==2.17.2 # via # -r requirements.in # bpython # sphinx -pyhanko==0.20.1 +pyhanko==0.23.0 # via xhtml2pdf -pyhanko-certvalidator==0.24.1 +pyhanko-certvalidator==0.26.3 # via # pyhanko # xhtml2pdf pyjwt==2.8.0 # via uil-django-core -pyopenssl==23.2.0 +pyopenssl==24.1.0 # via pysaml2 -pypdf==3.16.2 +pypdf==4.1.0 # via xhtml2pdf pypng==0.20220715.0 # via qrcode -pysaml2==7.4.2 +pysaml2==7.5.0 # via djangosaml2 pyscss==1.4.0 # via uil-django-core python-bidi==0.4.2 # via xhtml2pdf -python-dateutil==2.8.2 +python-dateutil==2.9.0.post0 # via pysaml2 -python-ldap==3.4.3 +python-ldap==3.4.4 # via django-auth-ldap python-magic==0.4.27 # via -r requirements.in -pytz==2023.3.post1 +pytz==2024.1 # via # django # djangorestframework @@ -188,10 +225,14 @@ pytz==2023.3.post1 pyxdg==0.28 # via bpython pyyaml==6.0.1 - # via pyhanko + # via + # djlint + # pyhanko qrcode==7.4.2 # via pyhanko -reportlab==3.6.13 +regex==2023.12.25 + # via djlint +reportlab==4.0.9 # via # svglib # xhtml2pdf @@ -207,7 +248,9 @@ requests==2.31.0 six==1.16.0 # via # blessed + # cssbeautifier # html5lib + # jsbeautifier # pyscss # python-bidi # python-dateutil @@ -223,27 +266,25 @@ sphinx==7.2.6 # sphinxcontrib-django # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==2.0.0 # via -r requirements.in -sphinxcontrib-apidoc==0.4.0 +sphinxcontrib-apidoc==0.5.0 # via -r requirements.in -sphinxcontrib-applehelp==1.0.7 +sphinxcontrib-applehelp==1.0.8 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==1.0.6 # via sphinx sphinxcontrib-django==2.5 # via -r requirements.in -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.0.5 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==1.0.7 # via sphinx -sphinxcontrib-serializinghtml==1.1.9 +sphinxcontrib-serializinghtml==1.1.10 # via sphinx sqlparse==0.4.4 # via @@ -255,33 +296,40 @@ tinycss2==1.2.1 # via # cssselect2 # svglib -typing-extensions==4.8.0 +tomli==2.0.1 + # via + # black + # djlint +tqdm==4.66.2 + # via djlint +typing-extensions==4.10.0 # via # asgiref + # black # django-modeltranslation # qrcode -tzlocal==5.0.1 +tzlocal==5.2 # via pyhanko ua-parser==0.18.0 # via user-agents uritools==4.0.2 # via pyhanko-certvalidator -urllib3==2.0.5 +urllib3==2.2.1 # via requests user-agents==2.2.0 # via django-user-agents vbuild==0.8.2 # via uil-django-core -wcwidth==0.2.8 +wcwidth==0.2.13 # via blessed webencodings==0.5.1 # via # cssselect2 # html5lib # tinycss2 -wrapt==1.15.0 +wrapt==1.16.0 # via deprecated -xhtml2pdf==0.2.11 +xhtml2pdf==0.2.15 # via -r requirements.in -xmlschema==2.5.0 +xmlschema==2.5.1 # via pysaml2 diff --git a/reviews/admin.py b/reviews/admin.py index 4d11b0940..ca07ffd2c 100644 --- a/reviews/admin.py +++ b/reviews/admin.py @@ -5,8 +5,8 @@ class DecisionInline(admin.StackedInline): model = Decision - fields = ('reviewer', 'go') - readonly_fields = ('reviewer', 'go') + fields = ("reviewer", "go") + readonly_fields = ("reviewer", "go") can_delete = False show_change_link = True @@ -16,18 +16,19 @@ def has_add_permission(self, request, obj): @admin.register(Review) class ReviewAdmin(admin.ModelAdmin): - list_display = ('proposal', 'date_start', 'date_end', 'go') - list_filter = ('stage', 'continuation') - search_fields = ('proposal__title',) + list_display = ("proposal", "date_start", "date_end", "go") + list_filter = ("stage", "continuation") + search_fields = ("proposal__title",) inlines = (DecisionInline,) @admin.register(Decision) class DecisionAdmin(admin.ModelAdmin): - list_display = ('review', 'reviewer', 'go') - list_filter = ('go', ) + list_display = ("review", "reviewer", "go") + list_filter = ("go",) search_fields = ( - 'reviewer__first_name', - 'reviewer__last_name', - 'reviewer__username', - 'review__proposal__title') + "reviewer__first_name", + "reviewer__last_name", + "reviewer__username", + "review__proposal__title", + ) diff --git a/reviews/api/serializers.py b/reviews/api/serializers.py index 8dc371672..3a5e10ec8 100644 --- a/reviews/api/serializers.py +++ b/reviews/api/serializers.py @@ -8,9 +8,19 @@ class InlineReviewProposalSerializer(serializers.ModelSerializer): class Meta: model = Proposal - fields = ['pk', 'reference_number', 'title', 'is_revision', - 'date_confirmed', 'date_submitted', 'latest_review', - 'applicants', 'pdf', 'date_submitted_supervisor', 'in_archive'] + fields = [ + "pk", + "reference_number", + "title", + "is_revision", + "date_confirmed", + "date_submitted", + "latest_review", + "applicants", + "pdf", + "date_submitted_supervisor", + "in_archive", + ] read_only_fields = fields latest_review = serializers.SerializerMethodField() @@ -41,9 +51,20 @@ def get_pdf(self, proposal): class ReviewProposalSerializer(InlineReviewProposalSerializer): class Meta: model = Proposal - fields = ['pk', 'reference_number', 'title', 'is_revision', - 'date_confirmed', 'date_submitted', 'parent', 'latest_review', - 'applicants', 'pdf', 'date_submitted_supervisor', 'in_archive'] + fields = [ + "pk", + "reference_number", + "title", + "is_revision", + "date_confirmed", + "date_submitted", + "parent", + "latest_review", + "applicants", + "pdf", + "date_submitted_supervisor", + "in_archive", + ] read_only_fields = fields parent = serializers.SerializerMethodField() @@ -78,7 +99,7 @@ def get_pdf(self, proposal): class InlineDecisionSerializer(ModelDisplaySerializer): class Meta: model = Decision - fields = ['pk', 'go', 'date_decision', 'comments', 'reviewer'] + fields = ["pk", "go", "date_decision", "comments", "reviewer"] read_only_fields = fields reviewer = serializers.SerializerMethodField() @@ -90,12 +111,21 @@ def get_reviewer(self, decision): class InlineReviewSerializer(ModelDisplaySerializer): class Meta: model = Review - fields = ['pk', 'stage', 'route', 'go', 'continuation', 'date_start', - 'date_end', 'date_should_end', 'accountable_user', - 'current_reviewers'] + fields = [ + "pk", + "stage", + "route", + "go", + "continuation", + "date_start", + "date_end", + "date_should_end", + "accountable_user", + "current_reviewers", + ] read_only_fields = fields - route = serializers.CharField(source='get_route_display') + route = serializers.CharField(source="get_route_display") accountable_user = serializers.SerializerMethodField() current_reviewers = serializers.SerializerMethodField() @@ -109,19 +139,26 @@ def get_current_reviewers(self, review): class ReviewSerializer(InlineReviewSerializer): class Meta: model = Review - fields = ['pk', 'stage', 'route', 'go', 'continuation', 'date_start', - 'date_end', 'date_should_end', 'accountable_user', 'decision', - 'proposal'] + fields = [ + "pk", + "stage", + "route", + "go", + "continuation", + "date_start", + "date_end", + "date_should_end", + "accountable_user", + "decision", + "proposal", + ] read_only_fields = fields decision = serializers.SerializerMethodField() proposal = serializers.SerializerMethodField() def get_decision(self, review): - return InlineDecisionSerializer( - review.decision_set.all(), - many=True - ).data + return InlineDecisionSerializer(review.decision_set.all(), many=True).data def get_proposal(self, review): return ReviewProposalSerializer(review.proposal).data @@ -130,8 +167,15 @@ def get_proposal(self, review): class DecisionSerializer(InlineDecisionSerializer): class Meta: model = Decision - fields = ['pk', 'go', 'date_decision', 'comments', 'review', 'reviewer', - 'proposal'] + fields = [ + "pk", + "go", + "date_decision", + "comments", + "review", + "reviewer", + "proposal", + ] read_only_fields = fields review = serializers.SerializerMethodField() @@ -142,4 +186,3 @@ def get_review(self, decision): def get_proposal(self, decision): return ReviewProposalSerializer(decision.review.proposal).data - diff --git a/reviews/api/urls.py b/reviews/api/urls.py index 5bad56022..074cf5222 100644 --- a/reviews/api/urls.py +++ b/reviews/api/urls.py @@ -1,35 +1,37 @@ from django.urls import path -from .views import AllOpenReviewsApiView, MyDecisionsApiView, \ - MyOpenDecisionsApiView, OpenDecisionsApiView, \ - OpenSupervisorDecisionApiView, ToConcludeReviewApiView, AllReviewsApiView, \ - InRevisionApiView +from .views import ( + AllOpenReviewsApiView, + MyDecisionsApiView, + MyOpenDecisionsApiView, + OpenDecisionsApiView, + OpenSupervisorDecisionApiView, + ToConcludeReviewApiView, + AllReviewsApiView, + InRevisionApiView, +) -app_name = 'api' +app_name = "api" urlpatterns = [ - path('/decisions/', - MyDecisionsApiView.as_view(), - name='my_archive'), - path('/my_open/', - MyOpenDecisionsApiView.as_view(), - name='my_open'), - path('/open_decisions/', - OpenDecisionsApiView.as_view(), - name='open'), - path('/open_supervisors/', - OpenSupervisorDecisionApiView.as_view(), - name='open_supervisors'), - path('/in_revision/', - InRevisionApiView.as_view(), - name='in_revision'), - path('/open/', - AllOpenReviewsApiView.as_view(), - name='all_open'), - path('/to_conclude/', - ToConcludeReviewApiView.as_view(), - name='to_conclude'), - path('/archive/', - AllReviewsApiView.as_view(), - name='archive'), + path("/decisions/", MyDecisionsApiView.as_view(), name="my_archive"), + path("/my_open/", MyOpenDecisionsApiView.as_view(), name="my_open"), + path( + "/open_decisions/", OpenDecisionsApiView.as_view(), name="open" + ), + path( + "/open_supervisors/", + OpenSupervisorDecisionApiView.as_view(), + name="open_supervisors", + ), + path( + "/in_revision/", InRevisionApiView.as_view(), name="in_revision" + ), + path("/open/", AllOpenReviewsApiView.as_view(), name="all_open"), + path( + "/to_conclude/", + ToConcludeReviewApiView.as_view(), + name="to_conclude", + ), + path("/archive/", AllReviewsApiView.as_view(), name="archive"), ] diff --git a/reviews/api/views.py b/reviews/api/views.py index 9d8953025..420f9a212 100644 --- a/reviews/api/views.py +++ b/reviews/api/views.py @@ -17,69 +17,70 @@ class BaseDecisionApiView(GroupRequiredMixin, CommitteeMixin, FancyListApiView): - authentication_classes = (SessionAuthentication, ) + authentication_classes = (SessionAuthentication,) serializer_class = DecisionSerializer group_required = [ settings.GROUP_SECRETARY, + settings.GROUP_CHAIR, + settings.GROUP_PO, settings.GROUP_GENERAL_CHAMBER, settings.GROUP_LINGUISTICS_CHAMBER, ] filter_definitions = [ FancyListApiView.FilterDefinition( - 'review.get_stage_display', + "review.get_stage_display", _("Stadium"), ), FancyListApiView.FilterDefinition( - 'review.route', + "review.route", _("Route"), ), FancyListApiView.FilterDefinition( - 'proposal.is_revision', + "proposal.is_revision", _("Revisie"), ), ] sort_definitions = [ FancyListApiView.SortDefinition( - label=_('Referentienummer'), - field='proposal.reference_number', + label=_("Referentienummer"), + field="proposal.reference_number", ), FancyListApiView.SortDefinition( - label=_('Datum ingediend'), - field='proposal.date_submitted', + label=_("Datum ingediend"), + field="proposal.date_submitted", ), FancyListApiView.SortDefinition( - label=_('Start datum'), - field='review.date_start', + label=_("Start datum"), + field="review.date_start", ), ] - default_sort = ('proposal.date_submitted', 'desc') + default_sort = ("proposal.date_submitted", "desc") def get_context(self): context = super().get_context() - context['is_secretary'] = is_secretary(self.request.user) - context['review'] = { - 'ASSIGNMENT': Review.ASSIGNMENT, - 'COMMISSION': Review.COMMISSION, - 'CLOSING': Review.CLOSING, - 'CLOSED': Review.CLOSED, - 'GO': Review.GO, - 'GO_POST_HOC': Review.GO_POST_HOC, + context["is_secretary"] = is_secretary(self.request.user) + context["review"] = { + "ASSIGNMENT": Review.Stages.ASSIGNMENT, + "COMMISSION": Review.Stages.COMMISSION, + "CLOSING": Review.Stages.CLOSING, + "CLOSED": Review.Stages.CLOSED, + "GO": Review.Continuations.GO, + "GO_POST_HOC": Review.Continuations.GO_POST_HOC, } - context['current_user_pk'] = self.request.user.pk + context["current_user_pk"] = self.request.user.pk return context class MyDecisionsApiView(BaseDecisionApiView): - def get_default_sort(self) -> Tuple[str, str]: if is_secretary(self.request.user): - return 'review.date_start', "desc" + return "review.date_start", "desc" - return 'proposal.date_submitted', "desc" + return "proposal.date_submitted", "desc" def get_queryset(self): """Returns all open Decisions of the current User""" @@ -96,7 +97,7 @@ def get_queryset_for_committee(self): objects = Decision.objects.filter( reviewer=self.request.user, review__proposal__reviewing_committee=self.committee, - review__continuation__lt=Review.DISCONTINUED, + review__continuation__lt=Review.Continuations.DISCONTINUED, ) for obj in objects: @@ -119,7 +120,7 @@ def get_queryset_for_secretary(self): objects = Decision.objects.filter( reviewer__groups__name=settings.GROUP_SECRETARY, review__proposal__reviewing_committee=self.committee, - review__continuation__lt=Review.DISCONTINUED, + review__continuation__lt=Review.Continuations.DISCONTINUED, ) for obj in objects: @@ -127,8 +128,7 @@ def get_queryset_for_secretary(self): if proposal.pk not in dfse_cache: dfse_cache[proposal.pk] = Decision.objects.filter( - review__proposal=proposal, - reviewer=self.request.user + review__proposal=proposal, reviewer=self.request.user ).exists() # If there is a decision for this user, but this decision isn't @@ -148,12 +148,11 @@ def get_queryset_for_secretary(self): class MyOpenDecisionsApiView(BaseDecisionApiView): - def get_default_sort(self) -> Tuple[str, str]: if is_secretary(self.request.user): - return 'review.date_start', "desc" + return "review.date_start", "desc" - return 'proposal.date_submitted', "desc" + return "proposal.date_submitted", "desc" def get_queryset(self): """Returns all open Decisions of the current User""" @@ -163,16 +162,15 @@ def get_queryset(self): return self.get_queryset_for_committee() - def get_queryset_for_committee(self): """Returns all open Decisions of the current User""" decisions = OrderedDict() objects = Decision.objects.filter( reviewer=self.request.user, - go='', + go="", review__proposal__reviewing_committee=self.committee, - review__continuation__lt=Review.DISCONTINUED, + review__continuation__lt=Review.Continuations.DISCONTINUED, ) for obj in objects: @@ -194,9 +192,9 @@ def get_queryset_for_secretary(self): objects = Decision.objects.filter( reviewer__groups__name=settings.GROUP_SECRETARY, - go='', + go="", review__proposal__reviewing_committee=self.committee, - review__continuation__lt=Review.DISCONTINUED, + review__continuation__lt=Review.Continuations.DISCONTINUED, ) for obj in objects: @@ -204,8 +202,7 @@ def get_queryset_for_secretary(self): if proposal.pk not in dfse_cache: dfse_cache[proposal.pk] = Decision.objects.filter( - review__proposal=proposal, - reviewer=self.request.user + review__proposal=proposal, reviewer=self.request.user ).exists() # If there is a decision for this user, but this decision isn't @@ -227,6 +224,8 @@ def get_queryset_for_secretary(self): class OpenDecisionsApiView(BaseDecisionApiView): group_required = [ settings.GROUP_SECRETARY, + settings.GROUP_CHAIR, + settings.GROUP_PO, ] def get_queryset(self): @@ -236,18 +235,17 @@ def get_queryset(self): dfse_cache = {} objects = Decision.objects.filter( - go='', + go="", review__proposal__reviewing_committee=self.committee, - review__continuation__lt=Review.DISCONTINUED, - ).exclude(review__stage=Review.SUPERVISOR) + review__continuation__lt=Review.Continuations.DISCONTINUED, + ).exclude(review__stage=Review.Stages.SUPERVISOR) for obj in objects: proposal = obj.review.proposal if proposal.pk not in dfse_cache: dfse_cache[proposal.pk] = Decision.objects.filter( - review__proposal=proposal, - reviewer=self.request.user + review__proposal=proposal, reviewer=self.request.user ).exists() # If there is a decision for this user, but this decision *is* @@ -269,32 +267,33 @@ def get_queryset(self): class OpenSupervisorDecisionApiView(BaseDecisionApiView): group_required = [ settings.GROUP_SECRETARY, + settings.GROUP_CHAIR, + settings.GROUP_PO, ] sort_definitions = [ FancyListApiView.SortDefinition( - label=_('Referentienummer'), - field='proposal.reference_number', + label=_("Referentienummer"), + field="proposal.reference_number", ), FancyListApiView.SortDefinition( - label=_('Datum ingediend'), - field='proposal.date_submitted_supervisor', + label=_("Datum ingediend"), + field="proposal.date_submitted_supervisor", ), FancyListApiView.SortDefinition( - label=_('Start datum'), - field='review.date_start', + label=_("Start datum"), + field="review.date_start", ), ] - default_sort = ('proposal.date_submitted_supervisor', 'desc') + default_sort = ("proposal.date_submitted_supervisor", "desc") def get_queryset(self): - """Returns all proposals that still need to be reviewed by the secretary - """ + """Returns all proposals that still need to be reviewed by the secretary""" objects = Decision.objects.filter( - go='', - review__stage=Review.SUPERVISOR, - review__proposal__status=Proposal.SUBMITTED_TO_SUPERVISOR, - review__proposal__reviewing_committee=self.committee + go="", + review__stage=Review.Stages.SUPERVISOR, + review__proposal__status=Proposal.Statuses.SUBMITTED_TO_SUPERVISOR, + review__proposal__reviewing_committee=self.committee, ) decisions = OrderedDict() @@ -311,87 +310,97 @@ def get_queryset(self): class BaseReviewApiView(GroupRequiredMixin, CommitteeMixin, FancyListApiView): - authentication_classes = (SessionAuthentication, ) + authentication_classes = (SessionAuthentication,) serializer_class = ReviewSerializer filter_definitions = [ FancyListApiView.FilterDefinition( - 'get_stage_display', + "get_stage_display", _("Stadium"), ), FancyListApiView.FilterDefinition( - 'route', + "route", _("Route"), ), FancyListApiView.FilterDefinition( - 'proposal.is_revision', + "proposal.is_revision", _("Revisie"), ), FancyListApiView.FilterDefinition( - 'get_continuation_display', - _('Afhandeling'), + "get_continuation_display", + _("Afhandeling"), ), ] sort_definitions = [ FancyListApiView.SortDefinition( - label=_('Referentienummer'), - field='proposal.reference_number', + label=_("Referentienummer"), + field="proposal.reference_number", ), FancyListApiView.SortDefinition( - label=_('Datum ingediend'), - field='proposal.date_submitted', + label=_("Datum ingediend"), + field="proposal.date_submitted", ), FancyListApiView.SortDefinition( - label=_('Start datum'), - field='date_start', + label=_("Start datum"), + field="date_start", ), ] - default_sort = ('proposal.date_submitted', 'desc') + default_sort = ("proposal.date_submitted", "desc") def get_context(self): context = super().get_context() - context['is_secretary'] = is_secretary(self.request.user) - context['review'] = { - 'ASSIGNMENT': Review.ASSIGNMENT, - 'COMMISSION': Review.COMMISSION, - 'CLOSING': Review.CLOSING, - 'CLOSED': Review.CLOSED, - 'GO': Review.GO, - 'GO_POST_HOC': Review.GO_POST_HOC, + context["is_secretary"] = is_secretary(self.request.user) + context["review"] = { + "ASSIGNMENT": Review.Stages.ASSIGNMENT, + "COMMISSION": Review.Stages.COMMISSION, + "CLOSING": Review.Stages.CLOSING, + "CLOSED": Review.Stages.CLOSED, + "GO": Review.Continuations.GO, + "GO_POST_HOC": Review.Continuations.GO_POST_HOC, + "REVISION": Review.Continuations.REVISION, } - context['current_user_pk'] = self.request.user.pk + context["current_user_pk"] = self.request.user.pk return context class ToConcludeReviewApiView(BaseReviewApiView): - group_required = settings.GROUP_SECRETARY + group_required = [ + settings.GROUP_SECRETARY, + settings.GROUP_CHAIR, + settings.GROUP_PO, + ] def get_queryset(self): """Returns all open Committee Decisions of all Users""" reviews = {} - objects = Review.objects.filter( - stage__gte=Review.CLOSING, - proposal__status__gte=Proposal.SUBMITTED, - proposal__date_confirmed=None, - proposal__reviewing_committee=self.committee, - ).filter( - Q(continuation=Review.GO) | - Q(continuation=Review.GO_POST_HOC) | - Q(continuation=None) - ).select_related( - 'proposal', - "proposal__parent", - 'proposal__created_by', - 'proposal__supervisor', - 'proposal__relation', - ).prefetch_related( - 'proposal__review_set', - 'proposal__applicants', - 'decision_set', - 'decision_set__reviewer' + objects = ( + Review.objects.filter( + stage__gte=Review.Stages.CLOSING, + proposal__status__gte=Proposal.Statuses.SUBMITTED, + proposal__date_confirmed=None, + proposal__reviewing_committee=self.committee, + ) + .filter( + Q(continuation=Review.Continuations.GO) + | Q(continuation=Review.Continuations.GO_POST_HOC) + | Q(continuation=None) + ) + .select_related( + "proposal", + "proposal__parent", + "proposal__created_by", + "proposal__supervisor", + "proposal__relation", + ) + .prefetch_related( + "proposal__review_set", + "proposal__applicants", + "decision_set", + "decision_set__reviewer", + ) ) for obj in objects: @@ -409,48 +418,58 @@ class InRevisionApiView(BaseReviewApiView): """Return reviews for proposals which have been sent back for revision, but for which a revision has not yet been submitted""" - default_sort = ('date_start', 'desc') - group_required = [settings.GROUP_SECRETARY] + default_sort = ("date_start", "desc") + group_required = [ + settings.GROUP_SECRETARY, + settings.GROUP_CHAIR, + settings.GROUP_PO, + ] def get_queryset(self): # 1. Find reviews of revisions: # A revision not having a review means # that the review of its parent is "in revision" revision_reviews = Review.objects.filter( - proposal__is_revision=True, # Not a copy - stage__gte=Review.ASSIGNMENT, # Not a supervisor review + proposal__is_revision=True, # Not a copy + stage__gte=Review.Stages.ASSIGNMENT, # Not a supervisor review ) # 2. Get candidate reviews: # All reviews whose conclusion is "revision necessary" # that are in the current committee candidates = Review.objects.filter( proposal__reviewing_committee=self.committee, - stage=Review.CLOSED, - continuation=Review.REVISION, + stage=Review.Stages.CLOSED, + continuation=Review.Continuations.REVISION, ) # 3. Finally, exclude candidates whose proposal # has a child with a revision review in_revision = candidates.exclude( - Exists(revision_reviews.filter( - # OuterRef refers to the candidate being evaluated - proposal__parent__pk=OuterRef("proposal__pk") + Exists( + revision_reviews.filter( + # OuterRef refers to the candidate being evaluated + proposal__parent__pk=OuterRef("proposal__pk") ) ) ) return in_revision - + class AllOpenReviewsApiView(BaseReviewApiView): - default_sort = ('date_start', 'desc') + default_sort = ("date_start", "desc") def get_group_required(self): # Depending on committee kwarg we test for the correct group - group_required = [settings.GROUP_SECRETARY] + group_required = [ + settings.GROUP_SECRETARY, + settings.GROUP_CHAIR, + settings.GROUP_PO, + ] + settings.GROUP_PO, - if self.committee.name == 'AK': + if self.committee.name == "AK": group_required += [settings.GROUP_GENERAL_CHAMBER] - if self.committee.name == 'LK': + if self.committee.name == "LK": group_required += [settings.GROUP_LINGUISTICS_CHAMBER] return group_required @@ -458,22 +477,26 @@ def get_group_required(self): def get_queryset(self): """Returns all open Reviews""" reviews = OrderedDict() - objects = Review.objects.filter( - stage__gte=Review.ASSIGNMENT, - stage__lte=Review.CLOSING, - proposal__status__gte=Proposal.SUBMITTED, - proposal__reviewing_committee=self.committee, - ).select_related( - 'proposal', - "proposal__parent", - 'proposal__created_by', - 'proposal__supervisor', - 'proposal__relation', - ).prefetch_related( - 'proposal__review_set', - 'proposal__applicants', - 'decision_set', - 'decision_set__reviewer' + objects = ( + Review.objects.filter( + stage__gte=Review.Stages.ASSIGNMENT, + stage__lte=Review.Stages.CLOSING, + proposal__status__gte=Proposal.Statuses.SUBMITTED, + proposal__reviewing_committee=self.committee, + ) + .select_related( + "proposal", + "proposal__parent", + "proposal__created_by", + "proposal__supervisor", + "proposal__relation", + ) + .prefetch_related( + "proposal__review_set", + "proposal__applicants", + "decision_set", + "decision_set__reviewer", + ) ) for obj in objects: @@ -488,16 +511,20 @@ def get_queryset(self): class AllReviewsApiView(BaseReviewApiView): - default_sort = ('date_start', 'desc') + default_sort = ("date_start", "desc") def get_group_required(self): # Depending on committee kwarg we test for the correct group - group_required = [settings.GROUP_SECRETARY] + group_required = [ + settings.GROUP_SECRETARY, + settings.GROUP_CHAIR, + settings.GROUP_PO, + ] - if self.committee.name == 'AK': + if self.committee.name == "AK": group_required += [settings.GROUP_GENERAL_CHAMBER] - if self.committee.name == 'LK': + if self.committee.name == "LK": group_required += [settings.GROUP_LINGUISTICS_CHAMBER] return group_required @@ -505,21 +532,25 @@ def get_group_required(self): def get_queryset(self): """Returns all open Committee Decisions of all Users""" reviews = OrderedDict() - objects = Review.objects.filter( - stage__gte=Review.ASSIGNMENT, - proposal__status__gte=Proposal.SUBMITTED, - proposal__reviewing_committee=self.committee, - ).select_related( - 'proposal', - "proposal__parent", - 'proposal__created_by', - 'proposal__supervisor', - 'proposal__relation', - ).prefetch_related( - 'proposal__review_set', - 'proposal__applicants', - 'decision_set', - 'decision_set__reviewer' + objects = ( + Review.objects.filter( + stage__gte=Review.Stages.ASSIGNMENT, + proposal__status__gte=Proposal.Statuses.SUBMITTED, + proposal__reviewing_committee=self.committee, + ) + .select_related( + "proposal", + "proposal__parent", + "proposal__created_by", + "proposal__supervisor", + "proposal__relation", + ) + .prefetch_related( + "proposal__review_set", + "proposal__applicants", + "decision_set", + "decision_set__reviewer", + ) ) for obj in objects: diff --git a/reviews/forms.py b/reviews/forms.py index 39ab86608..50aad9951 100644 --- a/reviews/forms.py +++ b/reviews/forms.py @@ -11,15 +11,18 @@ from django.core.exceptions import ValidationError -SHORT_LONG_REVISE = [(True, _('korte (2-weken) route')), - (False, _('lange (4-weken) route')), - (None, _('direct naar revisie'))] + +SHORT_LONG_REVISE = [ + (True, _("korte route of revisie (2-weken)")), + (False, _("lange route (4-weken)")), + (None, _("Direct terug naar aanvrager (Nog niet in behandeling)")), +] class ChangeChamberForm(forms.ModelForm): class Meta: model = Proposal - fields = ['reviewing_committee'] + fields = ["reviewing_committee"] def __init__(self, *args, **kwargs): super(ChangeChamberForm, self).__init__(*args, **kwargs) @@ -27,18 +30,18 @@ def __init__(self, *args, **kwargs): general_chamber = Group.objects.get(name=settings.GROUP_GENERAL_CHAMBER) linguistics_chamber = Group.objects.get(name=settings.GROUP_LINGUISTICS_CHAMBER) - self.fields['reviewing_committee'].choices = ( - (general_chamber.pk, _('Algemene Kamer')), - (linguistics_chamber.pk, _('Linguïstiek Kamer')), + self.fields["reviewing_committee"].choices = ( + (general_chamber.pk, _("Algemene Kamer")), + (linguistics_chamber.pk, _("Linguïstiek Kamer")), ) class ReviewAssignForm(ConditionalModelForm): class Meta: model = Review - fields = ['short_route'] + fields = ["short_route"] widgets = { - 'short_route': forms.RadioSelect(choices=SHORT_LONG_REVISE), + "short_route": forms.RadioSelect(choices=SHORT_LONG_REVISE), } def __init__(self, *args, **kwargs): @@ -54,27 +57,30 @@ def __init__(self, *args, **kwargs): [ settings.GROUP_GENERAL_CHAMBER, settings.GROUP_LINGUISTICS_CHAMBER, - settings.GROUP_SECRETARY + settings.GROUP_SECRETARY, ] ) - self.fields['reviewers'] = forms.ModelMultipleChoiceField( + self.fields["reviewers"] = forms.ModelMultipleChoiceField( initial=self.instance.current_reviewers(), queryset=reviewers, - widget=forms.SelectMultiple(attrs={'data-placeholder': _('Selecteer de commissieleden')}), - required=False + widget=forms.SelectMultiple( + attrs={"data-placeholder": _("Selecteer de commissieleden")} + ), + required=False, ) def clean_reviewers(self): - reviewers = self.cleaned_data['reviewers'] + reviewers = self.cleaned_data["reviewers"] if len(reviewers) == 0: raise ValidationError( - _('Er moet tenminste één beoordelaar geselecteerd worden.'), - code='no_reviewer') + _("Er moet tenminste één beoordelaar geselecteerd worden."), + code="no_reviewer", + ) # See PR #188 if a secretary should be added to every review - return self.cleaned_data['reviewers'] + return self.cleaned_data["reviewers"] class ReviewCloseForm(forms.ModelForm): @@ -85,13 +91,13 @@ class ReviewCloseForm(forms.ModelForm): class Meta: model = Review fields = [ - 'continuation', - 'has_minor_revision', - 'minor_revision_description', - 'in_archive', + "continuation", + "has_minor_revision", + "minor_revision_description", + "in_archive", ] widgets = { - 'continuation': forms.RadioSelect(), + "continuation": forms.RadioSelect(), } def __init__(self, *args, **kwargs): @@ -99,30 +105,38 @@ def __init__(self, *args, **kwargs): - Remove long route option if this was already the long route. - Set the label for in_archive """ - allow_long_route_continuation = kwargs.pop('allow_long_route_continuation', False) + allow_long_route_continuation = kwargs.pop( + "allow_long_route_continuation", False + ) super(ReviewCloseForm, self).__init__(*args, **kwargs) if not allow_long_route_continuation: - self.fields['continuation'].choices = [x for x in Review.CONTINUATIONS if x[0] != Review.LONG_ROUTE] + self.fields["continuation"].choices = [ + x + for x in Review.Continuations.choices + if x[0] != Review.Continuations.LONG_ROUTE + ] - self.fields['in_archive'].label = _('Voeg deze aanvraag toe aan het archief') - self.fields['in_archive'].widget = forms.RadioSelect(choices=YES_NO) + self.fields["in_archive"].label = _("Voeg deze aanvraag toe aan het archief") + self.fields["in_archive"].widget = forms.RadioSelect(choices=YES_NO) - self.fields['has_minor_revision'].label = _('Is er een revisie geweest na het indienen van deze aanvraag?') - self.fields['has_minor_revision'].widget = forms.RadioSelect(choices=YES_NO) + self.fields["has_minor_revision"].label = _( + "Is er een revisie geweest na het indienen van deze aanvraag?" + ) + self.fields["has_minor_revision"].widget = forms.RadioSelect(choices=YES_NO) - self.fields['minor_revision_description'].label = _('Opmerkingen over revisie') - self.fields['minor_revision_description'].widget = forms.Textarea() + self.fields["minor_revision_description"].label = _("Opmerkingen over revisie") + self.fields["minor_revision_description"].widget = forms.Textarea() class ReviewDiscontinueForm(forms.ModelForm): - - confirm_discontinue = forms.BooleanField(initial=False, required=True, - label=_('Bevestig beëindiging')) + confirm_discontinue = forms.BooleanField( + initial=False, required=True, label=_("Bevestig beëindiging") + ) class Meta: model = Review fields = [ - 'confirm_discontinue', + "confirm_discontinue", ] def __init__(self, *args, **kwargs): @@ -136,20 +150,19 @@ def __init__(self, *args, **kwargs): class DecisionForm(forms.ModelForm): class Meta: model = Decision - fields = ['go', 'comments'] + fields = ["go", "comments"] widgets = { - 'go': forms.RadioSelect(), + "go": forms.RadioSelect(), } def __init__(self, *args, **kwargs): """Removes the empty label for the go field, and sets it as required""" super(DecisionForm, self).__init__(*args, **kwargs) - self.fields['go'].empty_label = None - self.fields['go'].choices = Decision.APPROVAL - self.fields['go'].required = True + self.fields["go"].empty_label = None + self.fields["go"].choices = Decision.Approval.choices + self.fields["go"].required = True -class StartEndDateForm(forms.Form): - - start_date = DateField(label=_('Start datum periode:')) - end_date = DateField(label=_('Eind datum periode:')) +class StartEndDateForm(forms.Form): + start_date = DateField(label=_("Start datum periode:")) + end_date = DateField(label=_("Eind datum periode:")) diff --git a/reviews/management/commands/send_reminders.py b/reviews/management/commands/send_reminders.py index eafefa46d..3c24de4f3 100644 --- a/reviews/management/commands/send_reminders.py +++ b/reviews/management/commands/send_reminders.py @@ -4,7 +4,7 @@ class Command(BaseCommand): - help = 'Sends reminders to reviewers for short route reviews that needs to be decided in the next 2 days' + help = "Sends reminders to reviewers for short route reviews that needs to be decided in the next 2 days" def handle(self, *args, **options): remind_reviewers() diff --git a/reviews/menus.py b/reviews/menus.py index 462d11514..f02ea99f6 100644 --- a/reviews/menus.py +++ b/reviews/menus.py @@ -4,11 +4,16 @@ from django.utils.translation import gettext_lazy as _ from menu import Menu, MenuItem -from main.templatetags.fetc_filters import in_general_chamber, \ - in_linguistics_chamber, is_secretary +from main.templatetags.fetc_filters import ( + in_general_chamber, + in_linguistics_chamber, + is_chair_or_secretary, + is_po_chair_or_secretary, +) def create_committee_menu(commitee: str) -> List[MenuItem]: + return [ MenuItem( _("Mijn openstaande besluiten"), @@ -21,51 +26,57 @@ def create_committee_menu(commitee: str) -> List[MenuItem]: MenuItem( _("Alle openstaande besluiten commissieleden"), reverse("reviews:open", args=[commitee]), - check=lambda x: is_secretary(x.user), + check=lambda x: is_po_chair_or_secretary(x.user), ), MenuItem( _("Alle openstaande besluiten eindverantwoordelijken"), reverse("reviews:open_supervisors", args=[commitee]), - check=lambda x: is_secretary(x.user), + check=lambda x: is_po_chair_or_secretary(x.user), ), MenuItem( _("Nog af te handelen aanvragen"), reverse("reviews:to_conclude", args=[commitee]), - check=lambda x: is_secretary(x.user), + check=lambda x: is_po_chair_or_secretary(x.user), ), MenuItem( _("Aanvragen in revisie"), reverse("reviews:in_revision", args=[commitee]), - check=lambda x: is_secretary(x.user), + check=lambda x: is_po_chair_or_secretary(x.user), ), MenuItem( _("Alle lopende aanvragen"), reverse("reviews:all_open", args=[commitee]), - check=lambda x: is_secretary(x.user), + check=lambda x: is_po_chair_or_secretary(x.user), ), MenuItem( _("Alle ingezonden aanvragen"), reverse("reviews:archive", args=[commitee]), - check=lambda x: is_secretary(x.user), + check=lambda x: is_po_chair_or_secretary(x.user), ), MenuItem( _("Overzicht werkverdeling commissieleden"), reverse("reviews:workload", args=[commitee]), - check=lambda x: is_secretary(x.user), + check=lambda x: is_chair_or_secretary(x.user), ), ] -Menu.add_item("main", MenuItem( - _("Algemene Kamer"), - "#", - children=create_committee_menu('AK'), - check=lambda x: in_general_chamber(x.user) -)) +Menu.add_item( + "main", + MenuItem( + _("Algemene Kamer"), + "#", + children=create_committee_menu("AK"), + check=lambda x: in_general_chamber(x.user), + ), +) -Menu.add_item("main", MenuItem( - _("Linguïstiek Kamer"), - "#", - children=create_committee_menu('LK'), - check=lambda x: in_linguistics_chamber(x.user) -)) +Menu.add_item( + "main", + MenuItem( + _("Linguïstiek Kamer"), + "#", + children=create_committee_menu("LK"), + check=lambda x: in_linguistics_chamber(x.user), + ), +) diff --git a/reviews/migrations/0001_initial.py b/reviews/migrations/0001_initial.py index cd76d6973..db9b5e74e 100644 --- a/reviews/migrations/0001_initial.py +++ b/reviews/migrations/0001_initial.py @@ -6,47 +6,107 @@ class Migration(migrations.Migration): - dependencies = [ - ('proposals', '0001_initial'), + ("proposals", "0001_initial"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='Decision', + name="Decision", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('go', models.NullBooleanField(default=None, verbose_name='Beslissing')), - ('date_decision', models.DateTimeField(null=True, blank=True)), - ('comments', models.TextField(verbose_name='Ruimte voor eventuele opmerkingen', blank=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "go", + models.NullBooleanField(default=None, verbose_name="Beslissing"), + ), + ("date_decision", models.DateTimeField(null=True, blank=True)), + ( + "comments", + models.TextField( + verbose_name="Ruimte voor eventuele opmerkingen", blank=True + ), + ), ], ), migrations.CreateModel( - name='Review', + name="Review", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('stage', models.PositiveIntegerField(default=0, choices=[(0, 'Beoordeling door eindverantwoordelijke'), (1, 'Aanstelling commissieleden'), (2, 'Beoordeling door commissie'), (3, 'Afsluiting door secretaris'), (4, 'Afgesloten')])), - ('short_route', models.BooleanField(default=True, verbose_name='Route')), - ('go', models.NullBooleanField(default=None, verbose_name='Beslissing')), - ('continuation', models.PositiveIntegerField(default=0, verbose_name='Afhandeling', choices=[(0, 'Goedkeuring door ETCL'), (1, 'Afwijzing door ETCL'), (2, 'Open review met lange (4-weken) route'), (3, 'Laat opnieuw beoordelen door METC')])), - ('date_start', models.DateTimeField()), - ('date_end', models.DateTimeField(null=True, blank=True)), - ('proposal', models.ForeignKey(to='proposals.Proposal', on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "stage", + models.PositiveIntegerField( + default=0, + choices=[ + (0, "Beoordeling door eindverantwoordelijke"), + (1, "Aanstelling commissieleden"), + (2, "Beoordeling door commissie"), + (3, "Afsluiting door secretaris"), + (4, "Afgesloten"), + ], + ), + ), + ( + "short_route", + models.BooleanField(default=True, verbose_name="Route"), + ), + ( + "go", + models.NullBooleanField(default=None, verbose_name="Beslissing"), + ), + ( + "continuation", + models.PositiveIntegerField( + default=0, + verbose_name="Afhandeling", + choices=[ + (0, "Goedkeuring door ETCL"), + (1, "Afwijzing door ETCL"), + (2, "Open review met lange (4-weken) route"), + (3, "Laat opnieuw beoordelen door METC"), + ], + ), + ), + ("date_start", models.DateTimeField()), + ("date_end", models.DateTimeField(null=True, blank=True)), + ( + "proposal", + models.ForeignKey( + to="proposals.Proposal", on_delete=models.CASCADE + ), + ), ], ), migrations.AddField( - model_name='decision', - name='review', - field=models.ForeignKey(to='reviews.Review', on_delete=models.CASCADE), + model_name="decision", + name="review", + field=models.ForeignKey(to="reviews.Review", on_delete=models.CASCADE), ), migrations.AddField( - model_name='decision', - name='reviewer', - field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE), + model_name="decision", + name="reviewer", + field=models.ForeignKey( + to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE + ), ), migrations.AlterUniqueTogether( - name='decision', - unique_together=set([('review', 'reviewer')]), + name="decision", + unique_together=set([("review", "reviewer")]), ), ] diff --git a/reviews/migrations/0002_auto_20160927_2106.py b/reviews/migrations/0002_auto_20160927_2106.py index 9f1dd083b..6e944927e 100644 --- a/reviews/migrations/0002_auto_20160927_2106.py +++ b/reviews/migrations/0002_auto_20160927_2106.py @@ -5,15 +5,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0001_initial'), + ("reviews", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='review', - name='continuation', - field=models.PositiveIntegerField(default=0, verbose_name='Afhandeling', choices=[(0, 'Goedkeuring door ETCL'), (1, 'Revisie noodzakelijk'), (2, 'Afwijzing door ETCL'), (3, 'Open review met lange (4-weken) route'), (4, 'Laat opnieuw beoordelen door METC')]), + model_name="review", + name="continuation", + field=models.PositiveIntegerField( + default=0, + verbose_name="Afhandeling", + choices=[ + (0, "Goedkeuring door ETCL"), + (1, "Revisie noodzakelijk"), + (2, "Afwijzing door ETCL"), + (3, "Open review met lange (4-weken) route"), + (4, "Laat opnieuw beoordelen door METC"), + ], + ), ), ] diff --git a/reviews/migrations/0003_decision_go_char.py b/reviews/migrations/0003_decision_go_char.py index 5b82ec488..f2024fb83 100644 --- a/reviews/migrations/0003_decision_go_char.py +++ b/reviews/migrations/0003_decision_go_char.py @@ -7,28 +7,28 @@ def forwards(apps, schema_editor): - if not schema_editor.connection.alias == 'default': + if not schema_editor.connection.alias == "default": return - for decision in apps.get_model('reviews', 'decision').objects.all(): + for decision in apps.get_model("reviews", "decision").objects.all(): if decision.go is None: - decision.go_char = '' + decision.go_char = "" elif decision.go: - decision.go_char = Decision.APPROVED + decision.go_char = Decision.Approval.APPROVED else: - decision.go_char = Decision.NOT_APPROVED + decision.go_char = Decision.Approval.NOT_APPROVED decision.save() def backwards(apps, schema_editor): - if not schema_editor.connection.alias == 'default': + if not schema_editor.connection.alias == "default": return - for decision in apps.get_model('reviews', 'decision').objects.all(): - if decision.go_char == Decision.APPROVED: + for decision in apps.get_model("reviews", "decision").objects.all(): + if decision.go_char == Decision.Approval.APPROVED: decision.go = True - elif decision.go_char == Decision.NOT_APPROVED: + elif decision.go_char == Decision.Approval.NOT_APPROVED: decision.go = False else: decision.go = None @@ -37,25 +37,33 @@ def backwards(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0002_auto_20160927_2106'), + ("reviews", "0002_auto_20160927_2106"), ] operations = [ migrations.AddField( - model_name='decision', - name='go_char', - field=models.CharField(blank=True, max_length=1, verbose_name='Beslissing', choices=[(b'Y', 'goedgekeurd'), (b'N', 'niet goegekeurd'), (b'?', 'revisie noodzakelijk')]), + model_name="decision", + name="go_char", + field=models.CharField( + blank=True, + max_length=1, + verbose_name="Beslissing", + choices=[ + (b"Y", "goedgekeurd"), + (b"N", "niet goegekeurd"), + (b"?", "revisie noodzakelijk"), + ], + ), ), migrations.RunPython(forwards, backwards), migrations.RemoveField( - model_name='decision', - name='go', + model_name="decision", + name="go", ), migrations.RenameField( - model_name='decision', - old_name='go_char', - new_name='go', + model_name="decision", + old_name="go_char", + new_name="go", ), ] diff --git a/reviews/migrations/0004_auto_20170117_1754.py b/reviews/migrations/0004_auto_20170117_1754.py index 9255a9a82..ba8259cea 100644 --- a/reviews/migrations/0004_auto_20170117_1754.py +++ b/reviews/migrations/0004_auto_20170117_1754.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0003_decision_go_char'), + ("reviews", "0003_decision_go_char"), ] operations = [ migrations.AlterField( - model_name='review', - name='short_route', - field=models.NullBooleanField(default=None, verbose_name='Route'), + model_name="review", + name="short_route", + field=models.NullBooleanField(default=None, verbose_name="Route"), ), ] diff --git a/reviews/migrations/0005_review_date_should_end.py b/reviews/migrations/0005_review_date_should_end.py index d61032eef..933f2b573 100644 --- a/reviews/migrations/0005_review_date_should_end.py +++ b/reviews/migrations/0005_review_date_should_end.py @@ -5,15 +5,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0004_auto_20170117_1754'), + ("reviews", "0004_auto_20170117_1754"), ] operations = [ migrations.AddField( - model_name='review', - name='date_should_end', + model_name="review", + name="date_should_end", field=models.DateField(null=True, blank=True), ), ] diff --git a/reviews/migrations/0006_auto_20180808_1129.py b/reviews/migrations/0006_auto_20180808_1129.py index a85ab4843..570d6e0ef 100644 --- a/reviews/migrations/0006_auto_20180808_1129.py +++ b/reviews/migrations/0006_auto_20180808_1129.py @@ -6,15 +6,23 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0005_review_date_should_end'), + ("reviews", "0005_review_date_should_end"), ] operations = [ migrations.AlterField( - model_name='decision', - name='go', - field=models.CharField(blank=True, choices=[('Y', 'goedgekeurd'), ('N', 'niet goegekeurd'), ('?', 'revisie noodzakelijk')], max_length=1, verbose_name='Beslissing'), + model_name="decision", + name="go", + field=models.CharField( + blank=True, + choices=[ + ("Y", "goedgekeurd"), + ("N", "niet goegekeurd"), + ("?", "revisie noodzakelijk"), + ], + max_length=1, + verbose_name="Beslissing", + ), ), ] diff --git a/reviews/migrations/0007_auto_20190401_1343.py b/reviews/migrations/0007_auto_20190401_1343.py index 9a3412e8b..433d78868 100644 --- a/reviews/migrations/0007_auto_20190401_1343.py +++ b/reviews/migrations/0007_auto_20190401_1343.py @@ -6,15 +6,24 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0006_auto_20180808_1129'), + ("reviews", "0006_auto_20180808_1129"), ] operations = [ migrations.AlterField( - model_name='review', - name='continuation', - field=models.PositiveIntegerField(choices=[(0, 'Goedkeuring door FETC-GW'), (1, 'Revisie noodzakelijk'), (2, 'Afwijzing door FETC-GW'), (3, 'Open review met lange (4-weken) route'), (4, 'Laat opnieuw beoordelen door METC')], default=0, verbose_name='Afhandeling'), + model_name="review", + name="continuation", + field=models.PositiveIntegerField( + choices=[ + (0, "Goedkeuring door FETC-GW"), + (1, "Revisie noodzakelijk"), + (2, "Afwijzing door FETC-GW"), + (3, "Open review met lange (4-weken) route"), + (4, "Laat opnieuw beoordelen door METC"), + ], + default=0, + verbose_name="Afhandeling", + ), ), ] diff --git a/reviews/migrations/0008_auto_20200428_1337.py b/reviews/migrations/0008_auto_20200428_1337.py index 30995d388..fc4505b90 100644 --- a/reviews/migrations/0008_auto_20200428_1337.py +++ b/reviews/migrations/0008_auto_20200428_1337.py @@ -4,25 +4,40 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0007_auto_20190401_1343'), + ("reviews", "0007_auto_20190401_1343"), ] operations = [ migrations.AlterField( - model_name='review', - name='continuation', - field=models.PositiveIntegerField(choices=[(0, 'Goedkeuring door FETC-GW'), (1, 'Revisie noodzakelijk'), (2, 'Afwijzing door FETC-GW'), (3, 'Open review met lange (4-weken) route'), (4, 'Laat opnieuw beoordelen door METC'), (5, 'Positief advies van FETC-GW, post-hoc'), (6, 'Negatief advies van FETC-GW, post-hoc')], default=0, verbose_name='Afhandeling'), + model_name="review", + name="continuation", + field=models.PositiveIntegerField( + choices=[ + (0, "Goedkeuring door FETC-GW"), + (1, "Revisie noodzakelijk"), + (2, "Afwijzing door FETC-GW"), + (3, "Open review met lange (4-weken) route"), + (4, "Laat opnieuw beoordelen door METC"), + (5, "Positief advies van FETC-GW, post-hoc"), + (6, "Negatief advies van FETC-GW, post-hoc"), + ], + default=0, + verbose_name="Afhandeling", + ), ), migrations.AlterField( - model_name='review', - name='go', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='Beslissing'), + model_name="review", + name="go", + field=models.BooleanField( + blank=True, default=None, null=True, verbose_name="Beslissing" + ), ), migrations.AlterField( - model_name='review', - name='short_route', - field=models.BooleanField(blank=True, default=None, null=True, verbose_name='Route'), + model_name="review", + name="short_route", + field=models.BooleanField( + blank=True, default=None, null=True, verbose_name="Route" + ), ), ] diff --git a/reviews/migrations/0008_auto_20201203_0906.py b/reviews/migrations/0008_auto_20201203_0906.py index 72e6c9cb1..d7fb4fa5f 100644 --- a/reviews/migrations/0008_auto_20201203_0906.py +++ b/reviews/migrations/0008_auto_20201203_0906.py @@ -6,15 +6,26 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0007_auto_20190401_1343'), + ("reviews", "0007_auto_20190401_1343"), ] operations = [ migrations.AlterField( - model_name='review', - name='continuation', - field=models.PositiveIntegerField(choices=[(0, 'Goedkeuring door FETC-GW'), (1, 'Revisie noodzakelijk'), (2, 'Afwijzing door FETC-GW'), (3, 'Open review met lange (4-weken) route'), (4, 'Laat opnieuw beoordelen door METC'), (5, 'Positief advies van FETC-GW, post-hoc'), (6, 'Negatief advies van FETC-GW, post-hoc')], default=0, verbose_name='Afhandeling'), + model_name="review", + name="continuation", + field=models.PositiveIntegerField( + choices=[ + (0, "Goedkeuring door FETC-GW"), + (1, "Revisie noodzakelijk"), + (2, "Afwijzing door FETC-GW"), + (3, "Open review met lange (4-weken) route"), + (4, "Laat opnieuw beoordelen door METC"), + (5, "Positief advies van FETC-GW, post-hoc"), + (6, "Negatief advies van FETC-GW, post-hoc"), + ], + default=0, + verbose_name="Afhandeling", + ), ), ] diff --git a/reviews/migrations/0009_merge_20201222_1654.py b/reviews/migrations/0009_merge_20201222_1654.py index f44450831..6e09cefc9 100644 --- a/reviews/migrations/0009_merge_20201222_1654.py +++ b/reviews/migrations/0009_merge_20201222_1654.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0008_auto_20200428_1337'), - ('reviews', '0008_auto_20201203_0906'), + ("reviews", "0008_auto_20200428_1337"), + ("reviews", "0008_auto_20201203_0906"), ] - operations = [ - ] + operations = [] diff --git a/reviews/migrations/0010_auto_20210809_1653.py b/reviews/migrations/0010_auto_20210809_1653.py index 6cf3f7e7c..a9c471c84 100644 --- a/reviews/migrations/0010_auto_20210809_1653.py +++ b/reviews/migrations/0010_auto_20210809_1653.py @@ -4,15 +4,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0009_merge_20201222_1654'), + ("reviews", "0009_merge_20201222_1654"), ] operations = [ migrations.AlterField( - model_name='review', - name='continuation', - field=models.PositiveIntegerField(choices=[(0, 'Goedkeuring door FETC-GW'), (1, 'Revisie noodzakelijk'), (2, 'Afwijzing door FETC-GW'), (3, 'Open review met lange (4-weken) route'), (4, 'Laat opnieuw beoordelen door METC'), (5, 'Positief advies van FETC-GW, post-hoc'), (6, 'Negatief advies van FETC-GW, post-hoc'), (7, 'Niet verder in behandeling genomen door de FETC-GW')], default=0, verbose_name='Afhandeling'), + model_name="review", + name="continuation", + field=models.PositiveIntegerField( + choices=[ + (0, "Goedkeuring door FETC-GW"), + (1, "Revisie noodzakelijk"), + (2, "Afwijzing door FETC-GW"), + (3, "Open review met lange (4-weken) route"), + (4, "Laat opnieuw beoordelen door METC"), + (5, "Positief advies van FETC-GW, post-hoc"), + (6, "Negatief advies van FETC-GW, post-hoc"), + (7, "Niet verder in behandeling genomen door de FETC-GW"), + ], + default=0, + verbose_name="Afhandeling", + ), ), ] diff --git a/reviews/migrations/0011_auto_20210920_1650.py b/reviews/migrations/0011_auto_20210920_1650.py index 1d5741fac..4d20a57e5 100644 --- a/reviews/migrations/0011_auto_20210920_1650.py +++ b/reviews/migrations/0011_auto_20210920_1650.py @@ -4,15 +4,27 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0010_auto_20210809_1653'), + ("reviews", "0010_auto_20210809_1653"), ] operations = [ migrations.AlterField( - model_name='review', - name='continuation', - field=models.PositiveIntegerField(choices=[(0, 'Goedkeuring door FETC-GW'), (1, 'Revisie noodzakelijk'), (2, 'Afwijzing door FETC-GW'), (3, 'Open review met lange (4-weken) route'), (4, 'Laat opnieuw beoordelen door METC'), (5, 'Positief advies van FETC-GW, post-hoc'), (6, 'Negatief advies van FETC-GW, post-hoc'), (7, 'Niet verder in behandeling genomen')], default=0, verbose_name='Afhandeling'), + model_name="review", + name="continuation", + field=models.PositiveIntegerField( + choices=[ + (0, "Goedkeuring door FETC-GW"), + (1, "Revisie noodzakelijk"), + (2, "Afwijzing door FETC-GW"), + (3, "Open review met lange (4-weken) route"), + (4, "Laat opnieuw beoordelen door METC"), + (5, "Positief advies van FETC-GW, post-hoc"), + (6, "Negatief advies van FETC-GW, post-hoc"), + (7, "Niet verder in behandeling genomen"), + ], + default=0, + verbose_name="Afhandeling", + ), ), ] diff --git a/reviews/migrations/0012_auto_20211213_1503.py b/reviews/migrations/0012_auto_20211213_1503.py index e8c79698b..21de01636 100644 --- a/reviews/migrations/0012_auto_20211213_1503.py +++ b/reviews/migrations/0012_auto_20211213_1503.py @@ -4,15 +4,23 @@ class Migration(migrations.Migration): - dependencies = [ - ('reviews', '0011_auto_20210920_1650'), + ("reviews", "0011_auto_20210920_1650"), ] operations = [ migrations.AlterField( - model_name='decision', - name='go', - field=models.CharField(blank=True, choices=[('Y', 'goedgekeurd'), ('N', 'niet goedgekeurd'), ('?', 'revisie noodzakelijk')], max_length=1, verbose_name='Beslissing'), + model_name="decision", + name="go", + field=models.CharField( + blank=True, + choices=[ + ("Y", "goedgekeurd"), + ("N", "niet goedgekeurd"), + ("?", "revisie noodzakelijk"), + ], + max_length=1, + verbose_name="Beslissing", + ), ), ] diff --git a/reviews/migrations/0013_add_is_committee_review.py b/reviews/migrations/0013_add_is_committee_review.py new file mode 100644 index 000000000..2dc8e0056 --- /dev/null +++ b/reviews/migrations/0013_add_is_committee_review.py @@ -0,0 +1,32 @@ +# Generated by Django 3.2.20 on 2023-11-16 13:01 + +from django.db import migrations, models + + +def update_is_committee_review(apps, schema_editor): + Review = apps.get_model("reviews", "Review") + + for review in Review.objects.all(): + # Hardcoded these to account for possible future changes to stages + SUPERVISOR_STAGE = 0 + CLOSED_STAGE = 4 + if review.stage == SUPERVISOR_STAGE: + review.is_committee_review = False + if review.go: + review.stage = CLOSED_STAGE + review.save() + + +class Migration(migrations.Migration): + dependencies = [ + ("reviews", "0012_auto_20211213_1503"), + ] + + operations = [ + migrations.AddField( + model_name="review", + name="is_committee_review", + field=models.BooleanField(default=True), + ), + migrations.RunPython(update_is_committee_review), + ] diff --git a/reviews/mixins.py b/reviews/mixins.py index 0bfb53beb..209331413 100644 --- a/reviews/mixins.py +++ b/reviews/mixins.py @@ -1,6 +1,6 @@ from django.conf import settings from django.contrib.auth.models import Group -from django.core.exceptions import PermissionDenied +from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.utils.functional import cached_property from django.utils.translation import ugettext as _ from django.views.generic.base import ContextMixin @@ -12,26 +12,69 @@ from .utils.review_utils import auto_review -class UserAllowedMixin(SingleObjectMixin): - def get_object(self, queryset=None): +class UserAllowedToDecisionMixin(SingleObjectMixin): + class ReviewClosed(PermissionDenied): """ - Checks whether the current User is a reviewer in this Review, - as well as whether the Review is still open. + ReviewClosed Class + + Subclass of PermissionDenied that represents an exception indicating that a review has been closed and no further actions can be performed on it. + + This is a subclass of PermissionDenied to ensure Django handles it like that. + """ - obj = super(UserAllowedMixin, self).get_object(queryset) - if isinstance(obj, Review): - if not obj.decision_set.filter(reviewer=self.request.user): - raise PermissionDenied + def handle_review_closed(self, request, exception): + """ + Handle the case when a review is closed. - if isinstance(obj, Decision): - reviewer = obj.reviewer - date_end = obj.review.date_end + :param self: The instance of the class. + :param request: The request object. + :param exception: The exception object. - if self.request.user != reviewer or date_end: - raise PermissionDenied + :raises: The same exception object raised by the view as a fallback + """ + # If unhandled by the view, re-raise the exception to ensure we do not + # continue + raise exception - return obj + def dispatch(self, request, *args, **kwargs): + """ + Dispatches the request to the appropriate view method based on the object type and checks user permissions. + + :param request: The request object. + :type request: HttpRequest + :param args: Positional arguments passed to the view method. + :param kwargs: Keyword arguments passed to the view method. + :return: The response returned by the dispatched view method. + :rtype: HttpResponse + :raises PermissionDenied: If the current user does not have permission to access the object. + :raises self.ReviewClosed: If the review of the object is closed and the view does not handle this exception + :raises ImproperlyConfigured: If the mixin is used for a non-decision object. + """ + try: + obj = self.get_object() + + if isinstance(obj, Decision): + reviewer = obj.reviewer + date_end = obj.review.date_end + + if request.user != reviewer: + raise PermissionDenied + + if date_end: + raise self.ReviewClosed + else: + raise ImproperlyConfigured( + "UserAllowedToDecisionMixin used for a non-decision object!" + ) + except self.ReviewClosed as e: + ret = self.handle_review_closed(request, e) + # If the handle method returns None, it deemed it fine to continue + # as if nothing happened + if ret is not None: + return ret + + return super().dispatch(request, *args, **kwargs) class UserOrSecretaryAllowedMixin(SingleObjectMixin): @@ -45,7 +88,9 @@ def get_object(self, queryset=None): current_user = self.request.user if isinstance(obj, Review): - secretary_reviewers = obj.decision_set.filter(reviewer__groups__name=settings.GROUP_SECRETARY) + secretary_reviewers = obj.decision_set.filter( + reviewer__groups__name=settings.GROUP_SECRETARY + ) if secretary_reviewers and is_secretary(current_user): return obj if not obj.decision_set.filter(reviewer=current_user): @@ -57,15 +102,15 @@ def get_object(self, queryset=None): if date_end: raise PermissionDenied - if (self.request.user != reviewer) and \ - not (is_secretary(reviewer) and is_secretary(current_user)): + if (self.request.user != reviewer) and not ( + is_secretary(reviewer) and is_secretary(current_user) + ): raise PermissionDenied return obj -class UsersOrGroupsAllowedMixin(): - +class UsersOrGroupsAllowedMixin: def get_group_required(self): """Is overwritten to provide a dynamic list of groups which have access""" @@ -81,7 +126,7 @@ def get_allowed_users(self): return self.allowed_users def check_membership(self, groups): - """ Check required group(s) """ + """Check required group(s)""" if self.current_user.is_superuser: return True return set(groups).intersection(set(self.current_user_groups)) @@ -89,14 +134,18 @@ def check_membership(self, groups): def dispatch(self, request, *args, **kwargs): authorized = False self.current_user = request.user - self.current_user_groups = set(self.current_user.groups.values_list("name", flat=True)) + self.current_user_groups = set( + self.current_user.groups.values_list("name", flat=True) + ) # Default allowed groups and users - try: group_required = self.group_required + try: + group_required = self.group_required except AttributeError: self.group_required = None - try: allowed_users = self.allowed_users + try: + allowed_users = self.allowed_users except AttributeError: self.allowed_users = None @@ -109,33 +158,30 @@ def dispatch(self, request, *args, **kwargs): if not authorized: raise PermissionDenied - return super(UsersOrGroupsAllowedMixin, self).dispatch( - request, *args, **kwargs) - + return super(UsersOrGroupsAllowedMixin, self).dispatch(request, *args, **kwargs) class CommitteeMixin(ContextMixin): - @cached_property def committee(self): - group = self.kwargs.get('committee') + group = self.kwargs.get("committee") return Group.objects.get(name=group) @cached_property def committee_display_name(self): - committee = _('Algemene Kamer') + committee = _("Algemene Kamer") - if self.committee.name == 'LK': - committee = _('Linguïstiek Kamer') + if self.committee.name == "LK": + committee = _("Linguïstiek Kamer") return committee def get_context_data(self, **kwargs): context = super(CommitteeMixin, self).get_context_data(**kwargs) - context['committee'] = self.committee - context['committee_name'] = self.committee_display_name + context["committee"] = self.committee + context["committee_name"] = self.committee_display_name return context @@ -145,6 +191,6 @@ def get_context_data(self, **kwargs): """Adds the results of the machine-wise review to the context.""" context = super(AutoReviewMixin, self).get_context_data(**kwargs) reasons = auto_review(self.get_object().proposal) - context['auto_review_go'] = len(reasons) == 0 - context['auto_review_reasons'] = reasons + context["auto_review_go"] = len(reasons) == 0 + context["auto_review_reasons"] = reasons return context diff --git a/reviews/models.py b/reviews/models.py index c964e0b20..24f5d8334 100644 --- a/reviews/models.py +++ b/reviews/models.py @@ -8,61 +8,40 @@ class Review(models.Model): - SUPERVISOR = 0 - ASSIGNMENT = 1 - COMMISSION = 2 - CLOSING = 3 - CLOSED = 4 - STAGES = ( - (SUPERVISOR, _('Beoordeling door eindverantwoordelijke')), - (ASSIGNMENT, _('Aanstelling commissieleden')), - (COMMISSION, _('Beoordeling door commissie')), - (CLOSING, _('Afsluiting door secretaris')), - (CLOSED, _('Afgesloten')), - ) - - GO = 0 - REVISION = 1 - NO_GO = 2 - LONG_ROUTE = 3 - METC = 4 - GO_POST_HOC = 5 - NO_GO_POST_HOC = 6 - DISCONTINUED = 7 - CONTINUATIONS = ( - (GO, _('Goedkeuring door FETC-GW')), - (REVISION, _('Revisie noodzakelijk')), - (NO_GO, _('Afwijzing door FETC-GW')), - (LONG_ROUTE, _('Open review met lange (4-weken) route')), - (METC, _('Laat opnieuw beoordelen door METC')), - (GO_POST_HOC, _('Positief advies van FETC-GW, post-hoc')), - (NO_GO_POST_HOC, _('Negatief advies van FETC-GW, post-hoc')), - (DISCONTINUED, _('Niet verder in behandeling genomen')), - ) - - stage = models.PositiveIntegerField(choices=STAGES, default=SUPERVISOR) - short_route = models.BooleanField( - _('Route'), - default=None, - null=True, - blank=True - ) - go = models.BooleanField( - _('Beslissing'), - default=None, - null=True, - blank=True + class Stages(models.IntegerChoices): + SUPERVISOR = 0, _("Beoordeling door eindverantwoordelijke") + ASSIGNMENT = 1, _("Aanstelling commissieleden") + COMMISSION = 2, _("Beoordeling door commissie") + CLOSING = 3, _("Afsluiting door secretaris") + CLOSED = 4, _("Afgesloten") + + class Continuations(models.IntegerChoices): + GO = 0, _("Goedkeuring door FETC-GW") + REVISION = 1, _("Revisie noodzakelijk") + NO_GO = 2, _("Afwijzing door FETC-GW") + LONG_ROUTE = 3, _("Open review met lange (4-weken) route") + METC = 4, _("Laat opnieuw beoordelen door METC") + GO_POST_HOC = 5, _("Positief advies van FETC-GW, post-hoc") + NO_GO_POST_HOC = 6, _("Negatief advies van FETC-GW, post-hoc") + DISCONTINUED = 7, _("Niet verder in behandeling genomen") + + stage = models.PositiveIntegerField( + choices=Stages.choices, default=Stages.SUPERVISOR ) + short_route = models.BooleanField(_("Route"), default=None, null=True, blank=True) + go = models.BooleanField(_("Beslissing"), default=None, null=True, blank=True) continuation = models.PositiveIntegerField( - _('Afhandeling'), - choices=CONTINUATIONS, - default=GO, + _("Afhandeling"), + choices=Continuations.choices, + default=Continuations.GO, ) date_start = models.DateTimeField() date_end = models.DateTimeField(blank=True, null=True) date_should_end = models.DateField(blank=True, null=True) + is_committee_review = models.BooleanField(default=True) + proposal = models.ForeignKey(Proposal, on_delete=models.CASCADE) def update_go(self, last_decision=None): @@ -72,16 +51,16 @@ def update_go(self, last_decision=None): """ # If this review is discontinued, it is set in stone - if self.continuation == self.DISCONTINUED: + if self.continuation == self.Continuations.DISCONTINUED: return all_decisions = self.decision_set.count() closed_decisions = 0 final_go = True for decision in self.decision_set.all(): - if decision.go != '': + if decision.go != "": closed_decisions += 1 - final_go &= decision.go == Decision.APPROVED + final_go &= decision.go == Decision.Approval.APPROVED if all_decisions == closed_decisions: self.go = final_go @@ -89,7 +68,7 @@ def update_go(self, last_decision=None): self.save() # For a supervisor review: - if self.stage == self.SUPERVISOR: + if self.is_committee_review == False: # Update the status of the Proposal with the end date self.proposal.date_reviewed_supervisor = self.date_end self.proposal.save() @@ -98,18 +77,24 @@ def update_go(self, last_decision=None): # Use absolute import. Relative works fine everywhere except # in an uWSGI environment, in which it errors. from reviews.utils import start_assignment_phase + start_assignment_phase(self.proposal) + self.stage = self.Stages.CLOSED # On NO-GO, reset the Proposal status else: # See comment above from reviews.utils import notify_supervisor_nogo + notify_supervisor_nogo(last_decision) - self.proposal.status = Proposal.DRAFT + self.proposal.status = Proposal.Statuses.DRAFT self.proposal.save() # For a review by commission: else: # Set the stage to CLOSING - self.stage = self.CLOSING + from reviews.utils import notify_secretary_all_decisions + + notify_secretary_all_decisions(self) + self.stage = self.Stages.CLOSING self.save() else: # In case there is still an unmade decision, make sure to @@ -122,37 +107,35 @@ def get_continuation_display(self): # If this review hasn't concluded, this will only return 'Approved' as # this is the default. Thus, we return 'unknown' if we are still pre- # conclusion. - if self.stage <= Review.COMMISSION: + if self.stage <= Review.Stages.COMMISSION: return _("Onbekend") # Get the human readable string - continuation = dict(self.CONTINUATIONS).get( - self.continuation, - self.continuation - ) + continuation = self.Continuations(self.continuation).label if self.proposal.has_minor_revision: - continuation += str(_(', met revisie')) + continuation += str(_(", met revisie")) return continuation def get_route_display(self): route_options = { - False: _('lange (4-weken) route'), - True: _('korte (2-weken) route'), - None: _('nog geen route') + False: _("lange (4-weken) route"), + True: _("korte (2-weken) route"), + None: _("nog geen route"), } return route_options[self.short_route] def accountable_user(self): return self.proposal.accountable_user() - + def get_applicant_names_emails(self): names_and_emails = [ - (user.get_full_name(), user.email) for user in self.proposal.applicants.all() + (user.get_full_name(), user.email) + for user in self.proposal.applicants.all() ] - name_email_strings = [] + name_email_strings = [] for pair in names_and_emails: name_email_strings.append(",\n".join(pair)) return name_email_strings @@ -161,34 +144,31 @@ def current_reviewers(self): return get_user_model().objects.filter(decision__review=self) def __str__(self): - return 'Review of %s' % self.proposal + return "Review of %s" % self.proposal class Decision(models.Model): - APPROVED = 'Y' - NOT_APPROVED = 'N' - NEEDS_REVISION = '?' - APPROVAL = ( - (APPROVED, _('goedgekeurd')), - (NOT_APPROVED, _('niet goedgekeurd')), - (NEEDS_REVISION, _('revisie noodzakelijk')), - ) + class Approval(models.TextChoices): + APPROVED = "Y", _("goedgekeurd") + NOT_APPROVED = "N", _("niet goedgekeurd") + NEEDS_REVISION = "?", _("revisie noodzakelijk") go = models.CharField( - _('Beslissing'), - max_length=1, - choices=APPROVAL, - blank=True) + _("Beslissing"), max_length=1, choices=Approval.choices, blank=True + ) + date_decision = models.DateTimeField(blank=True, null=True) - comments = models.TextField( - _('Ruimte voor eventuele opmerkingen'), - blank=True) + + comments = models.TextField(_("Ruimte voor eventuele opmerkingen"), blank=True) review = models.ForeignKey(Review, on_delete=models.CASCADE) reviewer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) class Meta: - unique_together = ('review', 'reviewer',) + unique_together = ( + "review", + "reviewer", + ) def save(self, *args, **kwargs): """ @@ -198,4 +178,9 @@ def save(self, *args, **kwargs): self.review.update_go(last_decision=self) def __str__(self): - return 'Decision #%d by %s on %s: %s' % (self.pk, self.reviewer.username, self.review.proposal, self.go) + return "Decision #%d by %s on %s: %s" % ( + self.pk, + self.reviewer.username, + self.review.proposal, + self.go, + ) diff --git a/reviews/templates/mail/all_decisions_notify.txt b/reviews/templates/mail/all_decisions_notify.txt new file mode 100644 index 000000000..a7ab55478 --- /dev/null +++ b/reviews/templates/mail/all_decisions_notify.txt @@ -0,0 +1,18 @@ +{% extends "mail/base-internal.txt" %} + +{% block content %} +Alle beoordelingen zijn toegevoegd bij de aanvraag {{ review.proposal.reference_number }}. + +De review is klaar om afgesloten te worden. + +Overzicht beoordelingen: +{% for decision in decisions %} +Beoordelaar: {{ decision.reviewer.get_full_name }} +Beoordeling: {{ decision.get_go_display }} +{% endfor %} + +Detailpagina: {{ review_detail_page }} + +Review afsluiten: {{ close_review_page }} + +{% endblock %} diff --git a/reviews/templates/mail/base-internal.html b/reviews/templates/mail/base-internal.html index 8c26cfe1e..e29ecf35a 100644 --- a/reviews/templates/mail/base-internal.html +++ b/reviews/templates/mail/base-internal.html @@ -1,7 +1,9 @@ -{% block content %} -{% endblock %} -
    -Namens de FETC-GW, met de vriendelijke groeten,
    -
    -de FETC-GW secretaris
    +{% block content %}{% endblock %} + +
    +Namens de FETC-GW, met de vriendelijke groeten, +
    +
    +de FETC-GW secretaris +
    {{ secretary }} diff --git a/reviews/templates/mail/base.html b/reviews/templates/mail/base.html index 09d344619..ba00e835d 100644 --- a/reviews/templates/mail/base.html +++ b/reviews/templates/mail/base.html @@ -1,23 +1,32 @@ -[English version below]
    -
    -{% block content_nl %} -{% endblock %} -
    -Namens de FETC-GW, met de vriendelijke groeten,
    -
    -de FETC-GW secretaris,
    -{{ secretary }}
    -
    -Dit is een automatisch gegenereerd bericht.
    -
    -~~~~~
    -
    -{% block content_en %} -{% endblock %} -
    -Kind regards on behalf of the FEtC-H,
    -
    -the secretary of the FEtC-H,
    -{{ secretary }}
    -
    +[English version below] +
    +
    +{% block content_nl %}{% endblock %} + +
    +Namens de FETC-GW, met de vriendelijke groeten, +
    +
    +de FETC-GW secretaris, +
    +{{ secretary }} +
    +
    +Dit is een automatisch gegenereerd bericht. +
    +
    +~~~~~ +
    +
    +{% block content_en %}{% endblock %} + +
    +Kind regards on behalf of the FEtC-H, +
    +
    +the secretary of the FEtC-H, +
    +{{ secretary }} +
    +
    This message was generated automatically. diff --git a/reviews/templates/mail/concept_creator.html b/reviews/templates/mail/concept_creator.html index 93d788ba1..f118bbf70 100644 --- a/reviews/templates/mail/concept_creator.html +++ b/reviews/templates/mail/concept_creator.html @@ -1,21 +1,29 @@ {% extends "mail/base.html" %} {% block content_nl %} -Beste collega,
    -
    -Uw concept-aanmelding wordt door de eindverantwoordelijk onderzoeker {{ supervisor }} van deze aanvraag gecontroleerd. -Zodra deze de concept-aanmelding, evt. na kleine aanpassingen, heeft goedgekeurd en ter toetsing bij de FETC-GW heeft ingediend, krijgt u van ons bericht.
    -Indien de concept-aanmelding nog aanzienlijke wijzigingen uwerzijds behoeft zal de eindverantwoordelijk onderzoeker zelf contact met u opnemen.
    -U kunt uw ingediende aanmelding hier in PDF vorm bekijken.
    -
    + Beste collega, +
    +
    + Uw concept-aanmelding wordt door de eindverantwoordelijk onderzoeker {{ supervisor }} van deze aanvraag gecontroleerd. + Zodra deze de concept-aanmelding, evt. na kleine aanpassingen, heeft goedgekeurd en ter toetsing bij de FETC-GW heeft ingediend, krijgt u van ons bericht. +
    + Indien de concept-aanmelding nog aanzienlijke wijzigingen uwerzijds behoeft zal de eindverantwoordelijk onderzoeker zelf contact met u opnemen. +
    + U kunt uw ingediende aanmelding hier in PDF vorm bekijken. +
    +
    {% endblock %} {% block content_en %} -Dear colleague,
    -
    -Your draft application will be checked by your supervisor {{ supervisor }}, the researcher who has the final responsibility of this study.
    -You will receive a notification as soon as {{ supervisor }} has approved and formally submitted your draft application, possibly after making some minor revisions.
    -In case {{ supervisor }} finds it necessary for you to make more substantial revisions in the application, he/she will notify you about this, and meanwhile formally disapprove the study in order for you to be able to revise and resubmit it.
    -You can find a PDF of your submission here. -
    + Dear colleague, +
    +
    + Your draft application will be checked by your supervisor {{ supervisor }}, the researcher who has the final responsibility of this study. +
    + You will receive a notification as soon as {{ supervisor }} has approved and formally submitted your draft application, possibly after making some minor revisions. +
    + In case {{ supervisor }} finds it necessary for you to make more substantial revisions in the application, he/she will notify you about this, and meanwhile formally disapprove the study in order for you to be able to revise and resubmit it. +
    + You can find a PDF of your submission here. +
    {% endblock %} diff --git a/reviews/templates/mail/concept_other_applicants.html b/reviews/templates/mail/concept_other_applicants.html index 5cc6b946e..6e9b645fa 100644 --- a/reviews/templates/mail/concept_other_applicants.html +++ b/reviews/templates/mail/concept_other_applicants.html @@ -1,23 +1,33 @@ {% extends "mail/base.html" %} {% block content_nl %} -Beste collega,
    -
    -Uw collega {{ creator }} heeft een concept-aanmelding ingediend bij de ethische commissie voor het onderzoek {{ title }}, waar u aan meewerkt.
    -De aanmelding wordt door de eindverantwoordelijk onderzoeker {{ supervisor }} van deze aanvraag gecontroleerd. -Zodra deze de concept-aanmelding, evt. na kleine aanpassingen, heeft goedgekeurd en ter toetsing bij de FETC-GW heeft ingediend, krijgt uw collega {{ creator }} van ons bericht.
    -Indien de concept-aanmelding nog aanzienlijke wijzigingen uwerzijds behoeft zal de eindverantwoordelijk onderzoeker zelf contact met uw collega opnemen.
    -U kunt de ingediende aanmelding hier in PDF vorm bekijken.
    -
    + Beste collega, +
    +
    + Uw collega {{ creator }} (cc) heeft een concept-aanmelding ingediend bij de ethische commissie voor het onderzoek {{ title }}, waar u aan meewerkt. +
    + De aanmelding wordt door de eindverantwoordelijk onderzoeker {{ supervisor }} van deze aanvraag gecontroleerd. + Zodra deze de concept-aanmelding, evt. na kleine aanpassingen, heeft goedgekeurd en ter toetsing bij de FETC-GW heeft ingediend, krijgt uw collega {{ creator }} van ons bericht. +
    + Indien de concept-aanmelding nog aanzienlijke wijzigingen uwerzijds behoeft zal de eindverantwoordelijk onderzoeker zelf contact met uw collega opnemen. +
    + U kunt de ingediende aanmelding hier in PDF vorm bekijken. +
    +
    {% endblock %} {% block content_en %} -Dear colleague,
    -
    -Your colleague {{ creator }} has submitted a draft application to the ethics commision for the study {{ title }}, in which you are participating. -The application will be checked by the study's supervisor {{ supervisor }}, the researcher who has the final responsibility of this study.
    -Your colleague {{ creator }} will receive a notification as soon as {{ supervisor }} has approved and formally submitted your draft application, possibly after making some minor revisions.
    -In case {{ supervisor }} finds it necessary for you to make more substantial revisions in the application, he/she will notify your colleague about this, and meanwhile formally disapprove the study in order for you to be able to revise and resubmit it.
    -You can find a PDF of your submission here.
    -
    + Dear colleague, +
    +
    + Your colleague {{ creator }} (cc) has submitted a draft application to the ethics commission for the study {{ title }}, in which you are participating. + The application will be checked by the study's supervisor {{ supervisor }}, the researcher who has the final responsibility of this study. +
    + Your colleague {{ creator }} will receive a notification as soon as {{ supervisor }} has approved and formally submitted your draft application, possibly after making some minor revisions. +
    + In case {{ supervisor }} finds it necessary for you to make more substantial revisions in the application, he/she will notify your colleague about this, and meanwhile formally disapprove the study in order for you to be able to revise and resubmit it. +
    + You can find a PDF of your submission here. +
    +
    {% endblock %} diff --git a/reviews/templates/mail/concept_other_applicants.txt b/reviews/templates/mail/concept_other_applicants.txt index c40d5a63c..cf23ed1b2 100644 --- a/reviews/templates/mail/concept_other_applicants.txt +++ b/reviews/templates/mail/concept_other_applicants.txt @@ -3,7 +3,7 @@ {% block content_nl %} Beste collega, -Uw collega {{ creator }} heeft een concept-aanmelding ingediend bij de ethische commissie voor het onderzoek {{ title }}, waar u aan meewerkt. +Uw collega {{ creator }} (cc) heeft een concept-aanmelding ingediend bij de ethische commissie voor het onderzoek {{ title }}, waar u aan meewerkt. De aanmelding wordt door de eindverantwoordelijk onderzoeker {{ supervisor }} van deze aanvraag gecontroleerd. Zodra deze de concept-aanmelding, evt. na kleine aanpassingen, heeft goedgekeurd en ter toetsing bij de FETC-GW heeft ingediend, krijgt uw collega {{ creator }} van ons bericht. Indien de concept-aanmelding nog aanzienlijke wijzigingen uwerzijds behoeft zal de eindverantwoordelijk onderzoeker zelf contact met uw collega opnemen. @@ -14,7 +14,7 @@ U kunt de ingediende aanmelding hier in PDF vorm bekijken: {% block content_en %} Dear colleague, -Your colleague {{ creator }} has submitted a draft application to the ethics commision for the study {{ title }}, in which you are participating. +Your colleague {{ creator }} (cc) has submitted a draft application to the ethics commission for the study {{ title }}, in which you are participating. The application will be checked by the study's supervisor {{ supervisor }}, the researcher who has the final responsibility of this study. Your colleague {{ creator }} will receive a notification as soon as {{ supervisor }} has approved and formally submitted your draft application, possibly after making some minor revisions. In case {{ supervisor }} finds it necessary for you to make more substantial revisions in the application, he/she will notify your colleague about this, and meanwhile formally disapprove the study in order for you to be able to revise and resubmit it. diff --git a/reviews/templates/mail/concept_supervisor.html b/reviews/templates/mail/concept_supervisor.html index bf8bc3373..b195da623 100644 --- a/reviews/templates/mail/concept_supervisor.html +++ b/reviews/templates/mail/concept_supervisor.html @@ -1,39 +1,47 @@ {% extends "mail/base.html" %} {% block content_nl %} -Beste collega,
    -
    -{{ creator }} heeft binnen de FETC-GW-webportal een concept-aanvraag opgesteld voor een onderzoek waarbij u als de eindverantwoordelijke onderzoeker bent aangewezen.
    - -

    -{{ proposal.reference_number }}: {{ proposal.title }}

    - -U kunt deze concept-aanmelding hier bekijken, eventueel na aanpassingen van uzelf of {{ creator }}, formeel ter toetsing bij de FETC-GW indienen.
    -Indien {{ creator }} wordt geacht de aanpassingen te maken, dient u de aanvraag formeel af te keuren en zelf {{ creator }} hiervan op de hoogte stellen.
    -
    -U kunt al uw aanmeldingen als supervisor en hun status hier bekijken.
    -
    -{% if revision %} -Let op: het gaat hierbij om een {{ revision_type|lower }} van een eerdere aanmelding.
    -Op het webportaal kunt u de wijzigingen ten opzichte van de vorige aanmelding inzien.
    -{% endif %} + Beste collega, +
    +
    + {{ creator }} heeft binnen de FETC-GW-webportal een concept-aanvraag opgesteld voor een onderzoek waarbij u als de eindverantwoordelijke onderzoeker bent aangewezen. +
    +

    {{ proposal.reference_number }}: {{ proposal.title }}

    + U kunt deze concept-aanmelding hier bekijken, eventueel na aanpassingen van uzelf of {{ creator }}, formeel ter toetsing bij de FETC-GW indienen. +
    + Indien {{ creator }} wordt geacht de aanpassingen te maken, dient u de aanvraag formeel af te keuren en zelf {{ creator }} hiervan op de hoogte stellen. +
    +
    + U kunt al uw aanmeldingen als supervisor en hun status hier bekijken. +
    +
    + {% if revision %} + Let op: het gaat hierbij om een {{ revision_type|lower }} van een eerdere aanmelding. +
    + Op het webportaal kunt u de wijzigingen ten opzichte van de vorige aanmelding inzien. +
    + {% endif %} {% endblock %} {% block content_en %} -Dear colleague,
    -
    -{{ creator }} has created, within the portal of the FEtC-H, a draft application for a study for which you are appointed as the supervisor.
    - -

    -{{ proposal.reference_number }}: {{ proposal.title }}

    - -You can review this draft application here and submit this study to the FEtC-H after you have approved it. Note that in case minor revisions are necessary, you can adjust the study yourself before submitting it.
    -In case the application needs to be revised more substantially by {{ creator }}, we ask you to formally disapprove it in order for {{ creator }} to be able to revise it. In such a case, we ask you to inform {{ creator }} about this.
    -
    -You can view all your supervised applications and their status here.
    -
    -{% if revision %} -Please note that this involves a {{ revision_type | lower }} of a previous application.
    -On the web portal you can check the differences between the current and previous application.
    -{% endif %} + Dear colleague, +
    +
    + {{ creator }} has created, within the portal of the FEtC-H, a draft application for a study for which you are appointed as the supervisor. +
    +

    {{ proposal.reference_number }}: {{ proposal.title }}

    + You can review this draft application here and submit this study to the FEtC-H after you have approved it. Note that in case minor revisions are necessary, you can adjust the study yourself before submitting it. +
    + In case the application needs to be revised more substantially by {{ creator }}, we ask you to formally disapprove it in order for {{ creator }} to be able to revise it. In such a case, we ask you to inform {{ creator }} about this. +
    +
    + You can view all your supervised applications and their status here. +
    +
    + {% if revision %} + Please note that this involves a {{ revision_type | lower }} of a previous application. +
    + On the web portal you can check the differences between the current and previous application. +
    + {% endif %} {% endblock %} diff --git a/reviews/templates/mail/pre_assessment_secretary.html b/reviews/templates/mail/pre_assessment_secretary.html index 0106f0b2d..1ccf5b463 100644 --- a/reviews/templates/mail/pre_assessment_secretary.html +++ b/reviews/templates/mail/pre_assessment_secretary.html @@ -1,7 +1,10 @@ {% extends "mail/base-internal.html" %} {% block content %} -Er is een nieuwe aanvraag voor voortoetsing ingediend (referentienummer: {{ proposal.reference_number }},
    -eindverantwoordelijke: {{ proposal.accountable_user.get_full_name }}).
    -U kunt de aanvraag hier bekijken.
    + Er is een nieuwe aanvraag voor voortoetsing ingediend (referentienummer: {{ proposal.reference_number }}, +
    + eindverantwoordelijke: {{ proposal.accountable_user.get_full_name }}). +
    + U kunt de aanvraag hier bekijken. +
    {% endblock %} diff --git a/reviews/templates/mail/reminder.html b/reviews/templates/mail/reminder.html index bf627a3bd..2c0cc2905 100644 --- a/reviews/templates/mail/reminder.html +++ b/reviews/templates/mail/reminder.html @@ -1,15 +1,21 @@ {% extends "mail/base.html" %} {% block content_nl %} -Beste collega,
    -
    -Je moet met spoed de aanvraag van {{ creator }} beoordelen. De deadline voor beoordeling is (bijna) verlopen.
    -U kunt deze aanvraag beoordelen via {{ proposal_url }}
    + Beste collega, +
    +
    + Je moet met spoed de aanvraag van {{ creator }} beoordelen. De deadline voor beoordeling is (bijna) verlopen. +
    + U kunt deze aanvraag beoordelen via {{ proposal_url }} +
    {% endblock %} {% block content_en %} -Dear colleague,
    -
    -You must urgently review {{creator}}'s study. The deadline for assessment has (almost) expired.
    -You can review this application via {{ proposal_url }}
    + Dear colleague, +
    +
    + You must urgently review {{ creator }}'s study. The deadline for assessment has (almost) expired. +
    + You can review this application via {{ proposal_url }} +
    {% endblock %} diff --git a/reviews/templates/mail/submitted_longroute.html b/reviews/templates/mail/submitted_longroute.html index 9c8c473f5..221c9549e 100644 --- a/reviews/templates/mail/submitted_longroute.html +++ b/reviews/templates/mail/submitted_longroute.html @@ -1,35 +1,45 @@ {% extends "mail/base.html" %} {% block content_nl %} -{% if was_revised %} -Beste collega,
    -
    -Je gereviseerde aanvraag is door de FETC-GW ontvangen.
    -
    -Dit houdt in dat je revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen je binnenkort een beoordeling te kunnen sturen.
    - -{% else %} -Beste collega,
    -
    -Je aanmelding is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status lange-route onderzoek, zie appendix A van het reglement voor de criteria.
    -
    -Dit houdt in dat je aanvraag op de eerstvolgende vergadering van de FETC-GW zal worden besproken, wanneer je aanvraag tenminste een week voor die vergadering is ingediend. Zie de FETC-GW-agenda voor een overzicht van de komende vergaderingen. Zeer kort na de vergadering zult u de beoordeling ontvangen.
    -{% endif %} + {% if was_revised %} + Beste collega, +
    +
    + Je gereviseerde aanvraag is door de FETC-GW ontvangen. +
    +
    + Dit houdt in dat je revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen je binnenkort een beoordeling te kunnen sturen. +
    + {% else %} + Beste collega, +
    +
    + Je aanmelding is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status lange-route onderzoek, zie appendix A van het reglement voor de criteria. +
    +
    + Dit houdt in dat je aanvraag op de eerstvolgende vergadering van de FETC-GW zal worden besproken, wanneer je aanvraag tenminste een week voor die vergadering is ingediend. Zie de FETC-GW-agenda voor een overzicht van de komende vergaderingen. Zeer kort na de vergadering zult u de beoordeling ontvangen. +
    + {% endif %} {% endblock %} {% block content_en %} -{% if was_revised %} -Dear colleague,
    -
    -The FEtC-H has received your revised application.
    -
    -This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send you a review soon.
    - -{% else %} -Dear colleague,
    -
    -The FEtC-H has received your application. The automatic screening of the portal has given your study the status of long-route research, see appendix A in the regulations for the criteria.
    -
    -This means that your study will be discussed during the next FEtC-H meeting, if your application was submitted at least one week before that meeting. See the FEtC-H agenda for an overview of upcoming meetings. You will receive the assessment shortly after the meeting.
    -{% endif %} + {% if was_revised %} + Dear colleague, +
    +
    + The FEtC-H has received your revised application. +
    +
    + This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send you a review soon. +
    + {% else %} + Dear colleague, +
    +
    + The FEtC-H has received your application. The automatic screening of the portal has given your study the status of long-route research, see appendix A in the regulations for the criteria. +
    +
    + This means that your study will be discussed during the next FEtC-H meeting, if your application was submitted at least one week before that meeting. See the FEtC-H agenda for an overview of upcoming meetings. You will receive the assessment shortly after the meeting. +
    + {% endif %} {% endblock %} diff --git a/reviews/templates/mail/submitted_longroute_other_applicants.html b/reviews/templates/mail/submitted_longroute_other_applicants.html index b8f87b052..74cb64eaf 100644 --- a/reviews/templates/mail/submitted_longroute_other_applicants.html +++ b/reviews/templates/mail/submitted_longroute_other_applicants.html @@ -1,37 +1,53 @@ {% extends "mail/base.html" %} {% block content_nl %} -{% if was_revised %} -Beste collega,
    -
    -Uw collega {{ creator }} heeft een gereviseerde aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen.
    -
    -Dit houdt in dat de revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen uw collega, {{ creator }}, binnenkort een beoordeling te kunnen sturen.
    -U kunt de ingediende aanmelding hier in PDF vorm bekijken.
    -{% else %} -Beste collega,
    -
    -Uw collega {{ creator }} heeft een aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status lange-route onderzoek, zie appendix A van het reglement voor de criteria.
    -
    -Dit houdt in dat je aanvraag op de eerstvolgende vergadering van de FETC-GW zal worden besproken, wanneer je aanvraag tenminste een week voor die vergadering is ingediend. Zie de FETC-GW-agenda voor een overzicht van de komende vergaderingen. Kort na de vergadering zal {{ creator }} de beoordeling ontvangen.
    -U kunt de ingediende aanmelding hier in PDF vorm bekijken.
    -{% endif %} + {% if was_revised %} + Beste collega, +
    +
    + Uw collega {{ creator }} (cc) heeft een gereviseerde aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. +
    +
    + Dit houdt in dat de revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen uw collega, {{ creator }}, binnenkort een beoordeling te kunnen sturen. +
    + U kunt de ingediende aanmelding hier in PDF vorm bekijken. +
    + {% else %} + Beste collega, +
    +
    + Uw collega {{ creator }} (cc) heeft een aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status lange-route onderzoek, zie appendix A van het reglement voor de criteria. +
    +
    + Dit houdt in dat je aanvraag op de eerstvolgende vergadering van de FETC-GW zal worden besproken, wanneer je aanvraag tenminste een week voor die vergadering is ingediend. Zie de FETC-GW-agenda voor een overzicht van de komende vergaderingen. Kort na de vergadering zal {{ creator }} de beoordeling ontvangen. +
    + U kunt de ingediende aanmelding hier in PDF vorm bekijken. +
    + {% endif %} {% endblock %} {% block content_en %} -{% if was_revised %} -Dear colleague,
    -
    -Your colleague {{ creator }} has submitted a revised application for the study {{ title }}, in which you are participating. The FEtC-H has received your application.
    -
    -This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send your colleague {{ creator }} a review soon.
    -You can find a PDF of your submission here.
    -{% else %} -Dear colleague,
    -
    -Your colleague {{ creator }} has submitted an application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. The automatic screening of the portal has given your study the status of long-route research, see appendix A in the regulations for the criteria.
    -
    -This means that your study will be discussed during the next FEtC-H meeting, if your application was submitted at least one week before that meeting. See the FEtC-H agenda for an overview of upcoming meetings. {{ creator }} will receive the assessment shortly after the meeting.
    -You can find a PDF of your submission here.
    -{% endif %} + {% if was_revised %} + Dear colleague, +
    +
    + Your colleague {{ creator }} (cc) has submitted a revised application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. +
    +
    + This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send your colleague {{ creator }} a review soon. +
    + You can find a PDF of your submission here. +
    + {% else %} + Dear colleague, +
    +
    + Your colleague {{ creator }} (cc) has submitted an application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. The automatic screening of the portal has given your study the status of long-route research, see appendix A in the regulations for the criteria. +
    +
    + This means that your study will be discussed during the next FEtC-H meeting, if your application was submitted at least one week before that meeting. See the FEtC-H agenda for an overview of upcoming meetings. {{ creator }} will receive the assessment shortly after the meeting. +
    + You can find a PDF of your submission here. +
    + {% endif %} {% endblock %} diff --git a/reviews/templates/mail/submitted_longroute_other_applicants.txt b/reviews/templates/mail/submitted_longroute_other_applicants.txt index 1e5026c1b..371b6b471 100644 --- a/reviews/templates/mail/submitted_longroute_other_applicants.txt +++ b/reviews/templates/mail/submitted_longroute_other_applicants.txt @@ -4,7 +4,7 @@ {% if was_revised %} Beste collega, -Uw collega {{ creator }} heeft een gereviseerde aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. +Uw collega {{ creator }} (cc) heeft een gereviseerde aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. Dit houdt in dat de revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen uw collega, {{ creator }}, binnenkort een beoordeling te kunnen sturen. U kunt de ingediende aanmelding hier in PDF vorm bekijken: @@ -12,7 +12,7 @@ U kunt de ingediende aanmelding hier in PDF vorm bekijken: {% else %} Beste collega, -Uw collega {{ creator }} heeft een aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status 'lange-route onderzoek', zie appendix A van het reglement voor de criteria (https://fetc-gw.wp.hum.uu.nl/reglement-fetc-gw/). +Uw collega {{ creator }} (cc) heeft een aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status 'lange-route onderzoek', zie appendix A van het reglement voor de criteria (https://fetc-gw.wp.hum.uu.nl/reglement-fetc-gw/). Dit houdt in dat je aanvraag op de eerstvolgende vergadering van de FETC-GW zal worden besproken, wanneer je aanvraag tenminste een week voor die vergadering is ingediend. Zie de FETC-GW-agenda (https://fetc-gw.wp.hum.uu.nl/reglement-fetc-gw/) voor een overzicht van de komende vergaderingen. Kort na de vergadering zal {{ creator }} de beoordeling ontvangen. U kunt de ingediende aanmelding hier in PDF vorm bekijken: @@ -24,7 +24,7 @@ U kunt de ingediende aanmelding hier in PDF vorm bekijken: {% if was_revised %} Dear colleague, -Your colleague {{ creator }} has submitted a revised application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. +Your colleague {{ creator }} (cc) has submitted a revised application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send your colleague {{ creator }} a review soon. You can find a PDF file of your submission here: @@ -32,7 +32,7 @@ You can find a PDF file of your submission here: {% else %} Dear colleague, -Your colleague {{ creator }} has submitted an application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. The automatic screening of the portal has given your study the status of long-route research, see appendix A in the regulations for the criteria (https://fetc-gw.wp.hum.uu.nl/en/regulations-fetc-h/). +Your colleague {{ creator }} (cc) has submitted an application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. The automatic screening of the portal has given your study the status of long-route research, see appendix A in the regulations for the criteria (https://fetc-gw.wp.hum.uu.nl/en/regulations-fetc-h/). This means that your study will be discussed during the next FEtC-H meeting, if your application was submitted at least one week before that meeting. See the FEtC-H agenda (https://fetc-gw.wp.hum.uu.nl/en/category/agenda-en/) for an overview of upcoming meetings. {{ creator }} will receive the assessment shortly after the meeting. You can find a PDF file of your submission here: diff --git a/reviews/templates/mail/submitted_shortroute.html b/reviews/templates/mail/submitted_shortroute.html index 5deffff67..4c24abddc 100644 --- a/reviews/templates/mail/submitted_shortroute.html +++ b/reviews/templates/mail/submitted_shortroute.html @@ -1,39 +1,51 @@ {% extends "mail/base.html" %} {% block content_nl %} -{% if was_revised %} -Beste collega,
    -
    -Je gereviseerde aanvraag is door de FETC-GW ontvangen.
    -
    -Dit houdt in dat je revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen je binnenkort een beoordeling te kunnen sturen.
    - -{% else %} -Beste collega,
    -
    -Je aanmelding is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status korte-route onderzoek gekregen.
    -
    -Dit houdt in dat wij ernaar streven om je binnen twee werkweken een eerste beoordeling van de FETC-GW te sturen.
    -
    -NB: Het is mogelijk dat je aanvraag alsnog als 'lange-route onderzoek' wordt aangemerkt, in welk geval de beoordeling langer kan duren, zie het reglement. Houdt u hier a.u.b. rekening mee.
    -{% endif %} + {% if was_revised %} + Beste collega, +
    +
    + Je gereviseerde aanvraag is door de FETC-GW ontvangen. +
    +
    + Dit houdt in dat je revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen je binnenkort een beoordeling te kunnen sturen. +
    + {% else %} + Beste collega, +
    +
    + Je aanmelding is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status korte-route onderzoek gekregen. +
    +
    + Dit houdt in dat wij ernaar streven om je binnen twee werkweken een eerste beoordeling van de FETC-GW te sturen. +
    +
    + NB: Het is mogelijk dat je aanvraag alsnog als 'lange-route onderzoek' wordt aangemerkt, in welk geval de beoordeling langer kan duren, zie het reglement. Houdt u hier a.u.b. rekening mee. +
    + {% endif %} {% endblock %} {% block content_en %} -{% if was_revised %} -Dear colleague,
    -
    -The FEtC-H has received your revised application.
    -
    -This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send you a review soon.
    - -{% else %} -Dear colleague,
    -
    -The FEtC-H has received your application. The automatic screening of the portal has given your study the status of short-route research. -This means that you will receive an assessment within two working weeks.
    -
    -Note: It is possible that your application may still be classified as a 'long-route research', in which case the asssessment procedure may take longer, see the regulations for information. If the latter case, see section 2.8, p. 14 for the possible time paths.
    -Please be aware of these possibilities and the different time paths involved.
    -{% endif %} + {% if was_revised %} + Dear colleague, +
    +
    + The FEtC-H has received your revised application. +
    +
    + This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send you a review soon. +
    + {% else %} + Dear colleague, +
    +
    + The FEtC-H has received your application. The automatic screening of the portal has given your study the status of short-route research. + This means that you will receive an assessment within two working weeks. +
    +
    + Note: It is possible that your application may still be classified as a 'long-route research', in which case the asssessment procedure may take longer, see the regulations for information. If the latter case, see section 2.8, p. 14 for the possible time paths. +
    + Please be aware of these possibilities and the different time paths involved. +
    + {% endif %} {% endblock %} diff --git a/reviews/templates/mail/submitted_shortroute_other_applicants.html b/reviews/templates/mail/submitted_shortroute_other_applicants.html index 0ff83a5c1..de4f41442 100644 --- a/reviews/templates/mail/submitted_shortroute_other_applicants.html +++ b/reviews/templates/mail/submitted_shortroute_other_applicants.html @@ -1,39 +1,56 @@ {% extends "mail/base.html" %} {% block content_nl %} -{% if was_revised %} -Beste collega,
    -
    -Uw collega {{ creator }} heeft een gereviseerde aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen.
    -
    -Dit houdt in dat de revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen uw collega, {{ creator }}, binnenkort een beoordeling te kunnen sturen.
    -U kunt de ingediende aanmelding hier in PDF vorm bekijken.
    -{% else %} -Beste collega,
    -
    -Uw collega {{ creator }} heeft een aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status korte-route onderzoek gekregen.
    -
    -Dit houdt in dat wij ernaar streven om uw collega binnen twee werkweken een eerste beoordeling van de FETC-GW te sturen.
    -U kunt de ingediende aanmelding hier in PDF vorm bekijken.
    -
    -NB: Het is mogelijk dat je aanvraag alsnog als 'lange-route onderzoek' wordt aangemerkt, in welk geval de beoordeling langer kan duren, zie het reglement. Houdt u hier a.u.b. rekening mee.
    -{% endif %} + {% if was_revised %} + Beste collega, +
    +
    + Uw collega {{ creator }} (cc) heeft een gereviseerde aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. +
    +
    + Dit houdt in dat de revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen uw collega, {{ creator }}, binnenkort een beoordeling te kunnen sturen. +
    + U kunt de ingediende aanmelding hier in PDF vorm bekijken. +
    + {% else %} + Beste collega, +
    +
    + Uw collega {{ creator }} (cc) heeft een aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status korte-route onderzoek gekregen. +
    +
    + Dit houdt in dat wij ernaar streven om uw collega binnen twee werkweken een eerste beoordeling van de FETC-GW te sturen. +
    + U kunt de ingediende aanmelding hier in PDF vorm bekijken. +
    +
    + NB: Het is mogelijk dat je aanvraag alsnog als 'lange-route onderzoek' wordt aangemerkt, in welk geval de beoordeling langer kan duren, zie het reglement. Houdt u hier a.u.b. rekening mee. +
    + {% endif %} {% endblock %} {% block content_en %} -{% if was_revised %} -Dear colleague,
    -
    -Your colleague {{ creator }} has submitted a revised application for the study {{ title }}, in which you are participating. The FEtC-H has received your revised application.
    -
    -This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send you a review soon.
    -You can find a PDF of your submission here.
    -{% else %} -Dear colleague,
    -
    -Your colleague {{ creator }} has submitted an application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. The automatic screening of the portal has given your study the status of short-route research. This means that your colleague will receive an assessment within two working weeks.
    -You can find a PDF of your submission here.
    -
    -Note: It is possible that your application may still be classified as a 'long-route research', in which case the asssessment procedure may take longer, see the regulations for information. If the latter case, see section 2.8, p. 14 for the possible time paths.
    -{% endif %} + {% if was_revised %} + Dear colleague, +
    +
    + Your colleague {{ creator }} (cc) has submitted a revised application for the study {{ title }}, in which you are participating. The FEtC-H has received your revised application. +
    +
    + This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send you a review soon. +
    + You can find a PDF of your submission here. +
    + {% else %} + Dear colleague, +
    +
    + Your colleague {{ creator }} (cc) has submitted an application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. The automatic screening of the portal has given your study the status of short-route research. This means that your colleague will receive an assessment within two working weeks. +
    + You can find a PDF of your submission here. +
    +
    + Note: It is possible that your application may still be classified as a 'long-route research', in which case the asssessment procedure may take longer, see the regulations for information. If the latter case, see section 2.8, p. 14 for the possible time paths. +
    + {% endif %} {% endblock %} diff --git a/reviews/templates/mail/submitted_shortroute_other_applicants.txt b/reviews/templates/mail/submitted_shortroute_other_applicants.txt index d7d3d5683..5bb882d67 100644 --- a/reviews/templates/mail/submitted_shortroute_other_applicants.txt +++ b/reviews/templates/mail/submitted_shortroute_other_applicants.txt @@ -4,7 +4,7 @@ {% if was_revised %} Beste collega, -Uw collega {{ creator }} heeft een gereviseerde aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. +Uw collega {{ creator }} (cc) heeft een gereviseerde aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. Dit houdt in dat de revisie nu door twee leden van de FETC-GW zal worden beoordeeld; een eenvoudige revisie wordt alleen door de secretaris beoordeeld. We hopen uw collega, {{ creator }}, binnenkort een beoordeling te kunnen sturen. U kunt de ingediende aanmelding hier in PDF vorm bekijken: @@ -12,7 +12,7 @@ U kunt de ingediende aanmelding hier in PDF vorm bekijken: {% else %} Beste collega, -Uw collega {{ creator }} heeft een aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status 'korte-route onderzoek' gekregen. +Uw collega {{ creator }} (cc) heeft een aanvraag ingediend voor het onderzoek {{ title }}, waar u aan meewerkt, bij de ethische commissie. De aanvraag is door de FETC-GW ontvangen. De automatische screening van de portal heeft op basis van de door jou gegeven beschrijving voorlopig de status 'korte-route onderzoek' gekregen. Dit houdt in dat wij ernaar streven om uw collega binnen twee werkweken een eerste beoordeling van de FETC-GW te sturen. U kunt de ingediende aanmelding hier in PDF vorm bekijken: @@ -26,7 +26,7 @@ NB: Het is mogelijk dat de aanvraag alsnog als 'lange-route onderzoek' wordt aan {% if was_revised %} Dear colleague, -Your colleague {{ creator }} has submitted a revised application for the study {{ title }}, in which you are participating. The FEtC-H has received your revised application. +Your colleague {{ creator }} (cc) has submitted a revised application for the study {{ title }}, in which you are participating. The FEtC-H has received your revised application. This means that your study will be assessed by two members of the FEtC-H; minor revisions will be assessed by the secretary only. We hope to be able to send your colleague {{ creator }} a review soon. You can find a PDF file of your submission here: @@ -34,7 +34,7 @@ You can find a PDF file of your submission here: {% else %} Dear colleague, -Your colleague {{ creator }} has submitted an application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. The automatic screening of the portal has given your study the status of 'short-route research'. +Your colleague {{ creator }} (cc) has submitted an application for the study {{ title }}, in which you are participating. The FEtC-H has received your application. The automatic screening of the portal has given your study the status of 'short-route research'. This means that we aim to send your colleague an initial assessment of the FETC-GW within two working weeks. You can find a PDF file of your submission here: diff --git a/reviews/templates/reviews/action_explaination.html b/reviews/templates/reviews/action_explaination.html index b17bce316..fd106c7fc 100644 --- a/reviews/templates/reviews/action_explaination.html +++ b/reviews/templates/reviews/action_explaination.html @@ -14,30 +14,37 @@ {% static 'reviews/images/website.png' as img_export %} {% static 'reviews/images/report_go.png' as img_confirm %} {% static 'reviews/images/tick.png' as img_confirmed %} -

    {% trans "Uitleg" %}

    • - {% blocktrans %} - Klik op om een ingediende aanvraag in te zien. + {% blocktrans trimmed %} + Klik op + + om een ingediende aanvraag in te zien. {% endblocktrans %}
    • - {% blocktrans %} - Klik op om de verschillen met de voorgaande + {% blocktrans trimmed %} + Klik op + + om de verschillen met de voorgaande versie te zien (alleen beschikbaar voor revisies/amendementen). {% endblocktrans %}
    • - {% blocktrans %} - Klik op om alle details en beoordelingen van + {% blocktrans trimmed %} + Klik op + + om alle details en beoordelingen van een ingediende aanvraag te zien. {% endblocktrans %}
    • - {% blocktrans %} - Klik op om je beslissing door te geven. + {% blocktrans trimmed %} + Klik op + + om je beslissing door te geven. {% endblocktrans %}
    @@ -47,42 +54,56 @@

    {% trans "Uitleg secretaris" %}

      {% if request.user|is_secretary %}
    • - {% blocktrans %} - Klik op om een ingediende aanvraag te verbergen uit het + {% blocktrans trimmed %} + Klik op + + om een ingediende aanvraag te verbergen uit het archief. {% endblocktrans %}
    • {% blocktrans trimmed %} - Klik op om een ingediende aanvraag toe te voegen + Klik op + + om een ingediende aanvraag toe te voegen aan het archief. {% endblocktrans %}
    • - {% blocktrans %} - Klik op om beoordelaars aan te stellen. + {% blocktrans trimmed %} + Klik op + + om beoordelaars aan te stellen. {% endblocktrans %}
    • - {% blocktrans %} - Klik op om een aanvraag + {% blocktrans trimmed %} + Klik op + + om een aanvraag te verplaatsen naar een andere kamer. {% endblocktrans %}
    • - {% blocktrans %} - Klik op om een aanvraag af te sluiten. + {% blocktrans trimmed %} + Klik op + + om een aanvraag af te sluiten. {% endblocktrans %}
    • - {% blocktrans %} - Klik op om aan te geven dat de + {% blocktrans trimmed %} + Klik op + + om aan te geven dat de bevestigingsbrief is verstuurd. {% endblocktrans %}
    • - {% blocktrans %} - Klik op om de opgegeven datum + {% blocktrans trimmed %} + Klik op + + om de opgegeven datum van de bevestigingsbrief te veranderen. {% endblocktrans %}
    • diff --git a/reviews/templates/reviews/auto_review.html b/reviews/templates/reviews/auto_review.html index f716b2316..0009e6681 100644 --- a/reviews/templates/reviews/auto_review.html +++ b/reviews/templates/reviews/auto_review.html @@ -4,17 +4,15 @@

      {% trans "Uitkomst automatische review" %}

      {% if auto_review_go %} - {% trans "Volgens de automatische review kan dit voorstel de korte (2-weken) route volgen." %} + {% trans "Volgens de automatische review kan dit voorstel de korte (2-weken) route volgen." %} {% else %} - {% trans "Volgens de automatische review moet dit voorstel nader worden bekeken." %} + {% trans "Volgens de automatische review moet dit voorstel nader worden bekeken." %} {% endif %}
      {% if not auto_review_go %} -

      {% trans "Redenen" %}

      -
        - {% for reason in auto_review_reasons %} -
      • {{ reason }}
      • - {% endfor %} -
      +

      {% trans "Redenen" %}

      +
        + {% for reason in auto_review_reasons %}
      • {{ reason }}
      • {% endfor %} +
      {% endif %}

      diff --git a/reviews/templates/reviews/change_chamber_form.html b/reviews/templates/reviews/change_chamber_form.html index 1b7ee7482..8daafe976 100644 --- a/reviews/templates/reviews/change_chamber_form.html +++ b/reviews/templates/reviews/change_chamber_form.html @@ -10,13 +10,17 @@ {% block content %}
      -

      - {% trans "Beoordelende kamer wijzigen" %} -

      - {% csrf_token %} - {{ form.as_table }}
      - - {% trans "Terug naar de vorige pagina" %} +

      {% trans "Beoordelende kamer wijzigen" %}

      + + {% csrf_token %} + + {{ form.as_table }} +
      + + {% trans "Terug naar de vorige pagina" %}
      diff --git a/reviews/templates/reviews/committee_members_workload.html b/reviews/templates/reviews/committee_members_workload.html index d337de54e..99455a54d 100644 --- a/reviews/templates/reviews/committee_members_workload.html +++ b/reviews/templates/reviews/committee_members_workload.html @@ -15,81 +15,73 @@ {% block content %}
      -

      {% trans 'Lopende reviews' %} {{ committee }}

      - +

      {% trans 'Lopende reviews' %} {{ committee }}

      - - - - - - - + + + + + + + - {% for decision in decisions %} - - - - - - {% if decision.review.date_should_end < today %} - + + - {% else %} - - {% endif %} - - {% endfor %} + + {% if decision.review.date_should_end < today %} + + {% else %} + + {% endif %} + + {% endfor %}
      {% trans "Reviewer" %}{% trans "Traject" %}{% trans "Referentienummer" %}{% trans "Datum ingediend" %}{% trans "Gewenste einddatum" %}
      {% trans "Reviewer" %}{% trans "Traject" %}{% trans "Referentienummer" %}{% trans "Datum ingediend" %}{% trans "Gewenste einddatum" %}
      {{ decision.reviewer.get_full_name }} - {% if decision.review.proposal.is_revision == True %} - {% trans 'Revisie' %} - {% elif decision.review.short_route == True %} - {% trans 'Korte route' %} - {% else %} - {% trans 'Lange route' %} - {% endif %} - - - {{ decision.review.proposal.reference_number }} - - {{decision.review.proposal.title}} - {{ decision.review.date_start|date:"j M Y" }} - {{ decision.review.date_should_end|date:"j M Y" }} + {% for decision in decisions %} +
      {{ decision.reviewer.get_full_name }} + {% if decision.review.proposal.is_revision == True %} + {% trans 'Revisie' %} + {% elif decision.review.short_route == True %} + {% trans 'Korte route' %} + {% else %} + {% trans 'Lange route' %} + {% endif %} - {{ decision.review.date_should_end|date:"j M Y" }} + + {{ decision.review.proposal.reference_number }} - {{ decision.review.proposal.title }}
      {{ decision.review.date_start|date:"j M Y" }}{{ decision.review.date_should_end|date:"j M Y" }}{{ decision.review.date_should_end|date:"j M Y" }}

      -

      {% trans 'Werkverdeling overzicht van afgelopen periode' %}

      -

      - {% trans 'Vul hieronder een start- en einddatum in voor de periode van dit overzicht.'%} -

      +

      {% trans 'Werkverdeling overzicht van afgelopen periode' %}

      +

      {% trans 'Vul hieronder een start- en einddatum in voor de periode van dit overzicht.' %}

      {% csrf_token %} - {{ form.as_table }} + {{ form.as_table }}
      - +

      - - - - - - - + + + + + + + {% for reviewer in reviewers %} - - - - - + + + + + {% endfor %} diff --git a/reviews/templates/reviews/decision_form.html b/reviews/templates/reviews/decision_form.html index 4a07c5c54..0f0d8b9ff 100644 --- a/reviews/templates/reviews/decision_form.html +++ b/reviews/templates/reviews/decision_form.html @@ -9,16 +9,13 @@ {% block content %}
      - {% with review=decision.review %} - {% include "reviews/review_detail_sidebar.html" %} - {% endwith %} + {% with review=decision.review %} + {% include "reviews/review_detail_sidebar.html" %} + {% endwith %}
      -

      - {% trans "Aanvraag beoordelen" %} -

      +

      {% trans "Aanvraag beoordelen" %}

      {% with proposal=decision.review.proposal %} {% url 'proposals:pdf' proposal.id as pdf_url %} - {% url 'proposals:update' proposal.id as update_url %} {% if user != proposal.supervisor %}

      {% blocktrans trimmed with title=proposal.title refnum=proposal.reference_number chamber=proposal.reviewing_committee %} @@ -29,8 +26,9 @@

      {% else %}

      - {% blocktrans trimmed with title=proposal.title %} - Je kunt nu de aanvraag {{ title }} bekijken.
      + {% blocktrans trimmed with title=proposal.title %} + Je kunt nu de aanvraag {{ title }} bekijken. +
      {% endblocktrans %}

      @@ -49,7 +47,8 @@

      1. {% blocktrans trimmed %} - door de supervisor (jijzelf)
        + door de supervisor (jijzelf) +
        Als supervisor kan je deze aanvraag hier aanpassen. Daarna word je teruggeleid naar deze pagina en kun je hieronder de aanvraag goedkeuren; dat betekent dat de aanvraag wordt ingediend bij de FETC-GW. @@ -57,12 +56,13 @@

      2. {% blocktrans trimmed %} - door de indiener (je student of promovendus)
        + door de indiener (je student of promovendus) +
        Indien je wilt dat de indiener de aanvraag zelf aanpast voordat je de studie kunt goedkeuren en daarmee bij de FETC-GW indient, selecteer dan 'revisie noodzakelijk' of ‘niet goedgekeurd’ hieronder, voeg eventuele opmerkingen toe, en klik op 'Beslissing opslaan'. Zodra je dit gedaan hebt kan de indiener weer aanpassingen doen. -
        +
        {% endblocktrans %}
      3. {# This list item is a somewhat hacky way to simulate a p tag, as you can't use those in a li #} @@ -77,20 +77,22 @@

        {% if proposal.is_revision %}

        {% url 'proposals:diff' proposal.id as diff_url %} - {% blocktrans %} + {% blocktrans trimmed %} Dit is een revisie van of amendement op een vorige aanvraag. De verschillen met de vorige aanvraag zijn hier in te zien. {% endblocktrans %}

        {% endif %} -
        {% csrf_token %} -

      {% trans "Reviewer" %}{% trans "Totaal" %}{% trans "Korte route" %}{% trans "Lange Route" %}{% trans "Revisie" %}
      {% trans "Reviewer" %}{% trans "Totaal" %}{% trans "Korte route" %}{% trans "Lange Route" %}{% trans "Revisie" %}
      {{ reviewer.get_full_name }} {{ reviewer.total }}{{ reviewer.num_short_route }}{{ reviewer.num_long_route }}{{ reviewer.num_revision }}{{ reviewer.get_full_name }}{{ reviewer.total }}{{ reviewer.num_short_route }}{{ reviewer.num_long_route }}{{ reviewer.num_revision }}
      {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      {% endwith %} diff --git a/reviews/templates/reviews/documents_list.html b/reviews/templates/reviews/documents_list.html index 42c683277..587a204b3 100644 --- a/reviews/templates/reviews/documents_list.html +++ b/reviews/templates/reviews/documents_list.html @@ -5,47 +5,34 @@ {% load compare_tags %} {% load documents_list %} - - {% for container in containers %} - -
      - {{container.header}} -
      - - - -{% if container.dmp_edit_link %} - - {% trans "Data Management Plan wijzigen" %} - - -{% endif %} - -{% if container.edit_link %} - - {% trans "Documenten wijzigen" %} - - -{% endif %} - - + {% endif %} + {% if container.edit_link %} + + {% trans "Documenten wijzigen" %} + + + {% endif %} {% endfor %} diff --git a/reviews/templates/reviews/review_assign_form.html b/reviews/templates/reviews/review_assign_form.html index 1c8b95f80..e639c5d94 100644 --- a/reviews/templates/reviews/review_assign_form.html +++ b/reviews/templates/reviews/review_assign_form.html @@ -22,32 +22,32 @@ {% block content %}
      - - {% with review=review %} - {% include "reviews/review_detail_sidebar.html" %} - {% endwith %} - + {% with review=review %} + {% include "reviews/review_detail_sidebar.html" %} + {% endwith %}
      -

      - {% trans "Commissieleden aanstellen" %} -

      - +

      {% trans "Commissieleden aanstellen" %}

      {% url 'reviews:workload' review.proposal.reviewing_committee as workload_url %} {% blocktrans trimmed with title=review.proposal.title %}

      Kies hier de geschikte route en commissieleden voor de aanvraag {{ title }}. klik hier voor een overzicht van de werkverdeling van deze commissie. - +

      {% endblocktrans %} -
      {% csrf_token %} - {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      -
      {% if not review.proposal.is_pre_assessment %} {% include "reviews/auto_review.html" %} diff --git a/reviews/templates/reviews/review_close_form.html b/reviews/templates/reviews/review_close_form.html index d560fb90e..9a892a9ea 100644 --- a/reviews/templates/reviews/review_close_form.html +++ b/reviews/templates/reviews/review_close_form.html @@ -21,11 +21,9 @@ {% block content %}
      -

      - {% trans "Review afsluiten" %} -

      +

      {% trans "Review afsluiten" %}

      - {% blocktrans with title=review.proposal.title %} + {% blocktrans trimmed with title=review.proposal.title %} Sluit hier de beoordeling van de aanvraag {{ title }} af. Hieronder volgen de individuele beslissingen. {% endblocktrans %} @@ -33,19 +31,16 @@

      {% trans "Individuele beslissingen" %}

      {% include "reviews/review_table.html" %}

      {% trans "Uiteindelijk besluit" %}

      - -
      {% csrf_token %} - {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      -
      - - {% endblock %} diff --git a/reviews/templates/reviews/review_closed.html b/reviews/templates/reviews/review_closed.html new file mode 100644 index 000000000..16bf1d18a --- /dev/null +++ b/reviews/templates/reviews/review_closed.html @@ -0,0 +1,44 @@ +{% extends "base/base.html" %} + +{% load static %} +{% load proposal_filters %} +{% load fetc_filters %} +{% load i18n %} +{% load compare_tags %} +{% load uil_filters %} + +{% block header_title %} + {% trans 'Aanvraag al beoordeeld' %} + - {{ review.proposal.reference_number }} - {{ block.super }} +{% endblock %} + +{% block content %} + {% url 'proposals:my_supervised' as my_supervised_url %} +
      +
      +

      + {% trans 'Aanvraag al beoordeeld' %} + - {{ review.proposal.reference_number }} +

      +

      + {% blocktrans trimmed %} + Je hebt deze aanvraag al beoordeeld. Controleer of dit inderdaad de aanvraag is die je wilde beoordelen. Op deze pagina vind je alle aanvragen waarvan je de eindverantwoordelijke bent. + {% endblocktrans %} +

      +

      + {% blocktrans trimmed %} + Wil je je beoordeling veranderen? Neem dan contact op met de secretaris van de FETC. + {% endblocktrans %} +

      +

      + {% blocktrans trimmed %} + Denk je dat dit niet klopt? + {% endblocktrans %} + {% blocktrans trimmed %} + Neem dan contact op met het technisch beheer van de portal via portalsupport.gw@uu.nl. + {% endblocktrans %} +

      +
      + {% include "reviews/review_detail_sidebar.html" %} +
      +{% endblock %} diff --git a/reviews/templates/reviews/review_detail.html b/reviews/templates/reviews/review_detail.html index 43378ba83..29c95cb7d 100644 --- a/reviews/templates/reviews/review_detail.html +++ b/reviews/templates/reviews/review_detail.html @@ -8,7 +8,7 @@ {% load uil_filters %} {% block header_title %} - {% blocktrans with proposal=review.proposal.title %} + {% blocktrans trimmed with proposal=review.proposal.title %} Details van besluitvorming bij aanmelding {{ proposal }} {% endblocktrans %} - {{ review.proposal.reference_number }} - {{ block.super }} @@ -18,7 +18,7 @@

      - {% blocktrans with proposal=review.proposal.title %} + {% blocktrans trimmed with proposal=review.proposal.title %} Details van besluitvorming bij aanmelding {{ proposal }} {% endblocktrans %} - {{ review.proposal.reference_number }} @@ -26,33 +26,23 @@

      - - {% with review=review %} - {% include "reviews/review_detail_sidebar.html" %} - {% endwith %} - + {% with review=review %} + {% include "reviews/review_detail_sidebar.html" %} + {% endwith %}
      -

      - {% trans "Reviewers" %} -

      +

      {% trans "Reviewers" %}

      {% include "reviews/review_table.html" %}

      {% trans "Handelingen" %}

        - {% for action in detail_actions %} -
      • - {{ action }} -
      • + {% for action in detail_actions %} +
      • {{ action }}
      • {% empty %} -
      • - {% trans "Geen handelingen beschikbaar" %} -
      • - {% endfor %} +
      • {% trans "Geen handelingen beschikbaar" %}
      • + {% endfor %}
      {% if not review.proposal.is_pre_assessment %} {% include "reviews/auto_review.html" %} {% endif %}
      -
      - {% endblock %} diff --git a/reviews/templates/reviews/review_detail_sidebar.html b/reviews/templates/reviews/review_detail_sidebar.html index ae1f10c15..ce1dfadb8 100644 --- a/reviews/templates/reviews/review_detail_sidebar.html +++ b/reviews/templates/reviews/review_detail_sidebar.html @@ -12,26 +12,22 @@ Remember to include it in a with statement if the view does not provide it. {% endcomment %} -
      -

      - {% trans "Details" %} -

      +

      {% trans "Details" %}

        -
      • - {% trans "Referentie" %}: {{ review.proposal.reference_number }} -
      • -
      • - {% trans "Commissie" %}: {{review.proposal.reviewing_committee}} -
      • +
      • {% trans "Referentie" %}: {{ review.proposal.reference_number }}
      • +
      • {% trans "Commissie" %}: {{ review.proposal.reviewing_committee }}
      • {% if review.proposal.amendment_or_revision %}
      • {% blocktrans trimmed with parent=review.proposal.parent.reference_number r_or_a=review.proposal.amendment_or_revision %} - {{r_or_a}} van
        {{ parent }} + {{ r_or_a }} van +
        + {{ parent }} {% endblocktrans %}
        - +
      • @@ -39,43 +35,49 @@

      • {% trans "Aanvrager(s)" %}:
          - {% for name_email in review.get_applicant_names_emails %} -
        • {{ name_email }}
        • - {% endfor %} + {% for name_email in review.get_applicant_names_emails %}
        • {{ name_email }}
        • {% endfor %}
        {{ review.get_applicant_names }}
      • {% if review.proposal.supervisor %} -
      • - {% trans "Supervisor" %}: {{ review.proposal.supervisor }} -
      • +
      • {% trans "Supervisor" %}: {{ review.proposal.supervisor.get_full_name }}
      • {% endif %}
      • - {% blocktrans with date_start=review.date_start|date:"j F Y, G:i" %} - Reviewronde gestart op
        {{ date_start }}. + {% blocktrans trimmed with date_start=review.date_start|date:"j F Y, G:i" %} + Reviewronde gestart op +
        + {{ date_start }}. {% endblocktrans %}
      • {% if review.date_end %}
      • - {% blocktrans with date_end=review.date_end|date:"j F Y, G:i" %} - Reviewronde beëindigd op
        {{ date_end }}. + {% blocktrans trimmed with date_end=review.date_end|date:"j F Y, G:i" %} + Reviewronde beëindigd op +
        + {{ date_end }}. {% endblocktrans %}
      • {% endif %} - {% if review.stage == review.CLOSED %} + {% if review.stage == review.Stages.CLOSED %}
      • - {% blocktrans with continuation=review.get_continuation_display %} - Afhandeling:
        {{ continuation }}. + {% blocktrans trimmed with continuation=review.get_continuation_display %} + Afhandeling: +
        + {{ continuation }}. {% endblocktrans %}
      • {% if review.proposal.date_confirmed %}
      • - {% blocktrans with date_confirmed=review.proposal.date_confirmed|date:"j F Y" %} - Bevestiging verzonden op
        {{ date_confirmed }}. + {% blocktrans trimmed with date_confirmed=review.proposal.date_confirmed|date:"j F Y" %} + Bevestiging verzonden op +
        + {{ date_confirmed }}. {% endblocktrans %} {% if review.proposal.confirmation_comments %} - {% blocktrans with comments=review.proposal.confirmation_comments %} - Opmerkingen:
        {{ comments }}. + {% blocktrans trimmed with comments=review.proposal.confirmation_comments %} + Opmerkingen: +
        + {{ comments }}. {% endblocktrans %} {% endif %}
      • @@ -84,13 +86,13 @@

        {% if review.proposal.is_pre_assessment %}
      • - {% blocktrans %} + {% blocktrans trimmed %} Dit is een aanvraag voor voortoetsing. {% endblocktrans %}
      • {% endif %} - {% if review.stage == review.SUPERVISOR %} + {% if not review.is_committee_review %}
      • {% blocktrans trimmed %} @@ -100,23 +102,23 @@

      • {% endif %}

      - - - {% if review.proposal.has_minor_revision %} -

      {% trans 'Revisie' %}

      -

      {% blocktrans %} + {% if review.proposal.has_minor_revision %} +

      {% trans 'Revisie' %}

      +

      + {% blocktrans trimmed %} Deze aanvraag heeft een revisie gehad tijdens het beslisproces. - {% endblocktrans %}

      - {% if review.proposal.minor_revision_description %} -

      {% blocktrans %} - Er zijn de volgende opmerkingen bijgevoegd:
      + {% endblocktrans %} +

      + {% if review.proposal.minor_revision_description %} +

      + {% blocktrans trimmed %} + Er zijn de volgende opmerkingen bijgevoegd: +
      {% endblocktrans %} - {{ review.proposal.minor_revision_description }}

      - {% endif %} + {{ review.proposal.minor_revision_description }} +

      {% endif %} - - -

      {% trans "Documenten" %}

      - {% documents_list review user %} - + {% endif %} +

      {% trans "Documenten" %}

      + {% documents_list review user %}
      diff --git a/reviews/templates/reviews/review_discontinue_form.html b/reviews/templates/reviews/review_discontinue_form.html index c0ee9b92f..abf941f0a 100644 --- a/reviews/templates/reviews/review_discontinue_form.html +++ b/reviews/templates/reviews/review_discontinue_form.html @@ -22,59 +22,57 @@ {% block content %}
      - - {% with review=review %} - {% include "reviews/review_detail_sidebar.html" %} - {% endwith %} - + {% with review=review %} + {% include "reviews/review_detail_sidebar.html" %} + {% endwith %}
      -

      - {% trans "Afhandeling definitief beëindigen" %} -

      - +

      {% trans "Afhandeling definitief beëindigen" %}

      {% blocktrans trimmed %} - Als een aanvraag definitief niet meer door de FETC-GW - afgehandeld gaat worden, en deze in de weg staat, - kan er voor gekozen worden deze te beëindigen. + Als een aanvraag definitief niet meer door de FETC-GW + afgehandeld gaat worden, en deze in de weg staat, + kan er voor gekozen worden deze te beëindigen. {% endblocktrans %}

      {% blocktrans trimmed %} - Een beëindigde aanvraag verschijnt niet meer in de pagina's - van de secretaris en beoordelaars. Deze - aanvraag kan ook niet meer gereviseerd worden, - maar nog wel gekopieerd. De aanvraag is nog wel zichtbaar - in de lijst met "alle ingediende aanvragen". - {% endblocktrans %} -

      - {% if review.stage == review.CLOSED %} -

      - - {% trans "Attentie" %} - : - {% blocktrans trimmed %} - Deze aanvraag heeft op dit moment geen lopende beoordeling. Om deze aanvraag definitief te - beëindigen, moeten we de uitkomst van laatste beoordeling (zie linker balk) veranderen. - Dit kan verwarring veroorzaken bij de indiener, dus houd hier rekening mee. + Een beëindigde aanvraag verschijnt niet meer in de pagina's + van de secretaris en beoordelaars. Deze + aanvraag kan ook niet meer gereviseerd worden, + maar nog wel gekopieerd. De aanvraag is nog wel zichtbaar + in de lijst met "alle ingediende aanvragen". {% endblocktrans %}

      + {% if review.stage == review.Stages.CLOSED %} +

      + {% trans "Attentie" %}: + {% blocktrans trimmed %} + Deze aanvraag heeft op dit moment geen lopende beoordeling. Om deze aanvraag definitief te + beëindigen, moeten we de uitkomst van laatste beoordeling (zie linker balk) veranderen. + Dit kan verwarring veroorzaken bij de indiener, dus houd hier rekening mee. + {% endblocktrans %} +

      {% endif %}

      {% trans "Aanvraag" %}: {% blocktrans with title=review.proposal.title author=review.proposal.created_by trimmed %} - {{title}} door {{author}} + {{ title }} door {{ author }} {% endblocktrans %} -

      {% csrf_token %} - {{ form.as_table }}
      - - -
      +
      + {% csrf_token %} + + {{ form.as_table }} +
      + +
      +
      -
      -{% endblock %} + {% endblock %} diff --git a/reviews/templates/reviews/review_table.html b/reviews/templates/reviews/review_table.html index f107068d5..481c1a4be 100644 --- a/reviews/templates/reviews/review_table.html +++ b/reviews/templates/reviews/review_table.html @@ -13,12 +13,12 @@ {% for decision in review.decision_set.all %} - - {{ decision.reviewer }} - {{ decision.get_go_display|default:_("open") }} - {{ decision.date_decision|date:"j F Y, G:i" }} - {{ decision.comments }} - + + {{ decision.reviewer.get_full_name }} + {{ decision.get_go_display|default:_("open") }} + {{ decision.date_decision|date:"j F Y, G:i" }} + {{ decision.comments }} + {% endfor %} diff --git a/reviews/templates/reviews/simple_compare_link.html b/reviews/templates/reviews/simple_compare_link.html index 5225ca6f2..a547d9ef8 100644 --- a/reviews/templates/reviews/simple_compare_link.html +++ b/reviews/templates/reviews/simple_compare_link.html @@ -1,10 +1,9 @@ - {% load static %} {% load i18n %} - {% if compare_url %} - - - + + + {% endif %} diff --git a/reviews/templates/reviews/ufl_list.html b/reviews/templates/reviews/ufl_list.html index 5fcdabf30..19b54414d 100644 --- a/reviews/templates/reviews/ufl_list.html +++ b/reviews/templates/reviews/ufl_list.html @@ -6,20 +6,14 @@ {% load vue_tags %} {% get_current_language as LANGUAGE_CODE %} - -{% block header_title %} - {{ committee_name }} - {{ title }} - {{ block.super }} -{% endblock %} +{% block header_title %}{{ committee_name }} - {{ title }} - {{ block.super }}{% endblock %} {% block html_head %} - {# This template loads in either the dev or prod Vue library, depending on settings.DEBUG #} {% include 'uil.vue/vueloader.html' %} {# Load in the base component FancyList #} {% load_vue_component 'FancyList' %} - {% include list_template %} - + {% endblock %} {% block content %} @@ -77,25 +77,23 @@ {% with nav_items=study.proposal.available_urls active=3 %} {% include 'base/navigation.html' %} {% endwith %} - -

      - {% trans "De deelnemers" %} -

      - +

      {% trans "De deelnemers" %}

      {% include "studies/study_title.html" %} - {% if not study.proposal.relation %}
      {% url 'proposals:update' study.proposal.pk as url %} - {% blocktrans %} + {% blocktrans trimmed %} Let op! Je hebt de vraag 'In welke hoedanigheid ben je betrokken bij deze aanvraag?' nog niet ingevuld, waardoor deze pagina nog kan veranderen op basis van je antwoord. {% endblocktrans %}
      {% endif %} -
      {% csrf_token %} - {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      {% with proposal=study.proposal %} - {% include "base/form_buttons.html" %} + {% include "base/form_buttons.html" %} {% endwith %}
      diff --git a/studies/templates/studies/study_title.html b/studies/templates/studies/study_title.html index a9893f7e1..4ff01ca80 100644 --- a/studies/templates/studies/study_title.html +++ b/studies/templates/studies/study_title.html @@ -1,15 +1,15 @@ {% load i18n %} {% if study.proposal.studies_number > 1 %} -

      - {% if study.name %} - {% blocktrans with order=study.order name=study.name %} - Traject {{ order }} ({{ name }}) - {% endblocktrans %} - {% else %} - {% blocktrans with order=study.order %} - Traject {{ order }} - {% endblocktrans %} - {% endif %} -

      +

      + {% if study.name %} + {% blocktrans trimmed with order=study.order name=study.name %} + Traject {{ order }} ({{ name }}) + {% endblocktrans %} + {% else %} + {% blocktrans trimmed with order=study.order %} + Traject {{ order }} + {% endblocktrans %} + {% endif %} +

      {% endif %} diff --git a/studies/templates/studies/study_update_attachments.html b/studies/templates/studies/study_update_attachments.html index 5ee3d6560..7d6ca5288 100644 --- a/studies/templates/studies/study_update_attachments.html +++ b/studies/templates/studies/study_update_attachments.html @@ -10,20 +10,24 @@ {% block content %}
      -

      - {% trans "Formulieren aanpassen" %} -

      +

      {% trans "Formulieren aanpassen" %}

      {% blocktrans trimmed with title=documents.proposal.title ref_number=documents.proposal.reference_number order=documents.study.order %} - Op deze pagina kan je de formulieren aanpassen behorende bij de aanvraag {{ title }} - (referentienummer {{ ref_number }}), traject {{ order }}. + Op deze pagina kan je de formulieren aanpassen behorende bij de aanvraag {{ title }} + (referentienummer {{ ref_number }}), traject {{ order }}. {% endblocktrans %}

      -
      {% csrf_token %} - {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      - - {% trans "Terug naar de vorige pagina" %} + + {% trans "Terug naar de vorige pagina" %}
      diff --git a/studies/templatetags/describe_documents.py b/studies/templatetags/describe_documents.py index 46fbafac9..59d3849f1 100644 --- a/studies/templatetags/describe_documents.py +++ b/studies/templatetags/describe_documents.py @@ -20,25 +20,25 @@ def describe_file(file): field_name = file.field.name - nice_name = _('bestand') + nice_name = _("bestand") - if field_name == 'informed_consent': - nice_name = _('informed consent') + if field_name == "informed_consent": + nice_name = _("informed consent") - if field_name == 'briefing': - nice_name = _('informatiebrief') + if field_name == "briefing": + nice_name = _("informatiebrief") - if field_name == 'director_consent_declaration': - nice_name = _('informed consent voor de schoolleiding of het departementshoofd') + if field_name == "director_consent_declaration": + nice_name = _("informed consent voor de schoolleiding of het departementshoofd") - if field_name == 'director_consent_information': - nice_name = _('informatiebrief voor de schoolleiding of het departementshoofd') + if field_name == "director_consent_information": + nice_name = _("informatiebrief voor de schoolleiding of het departementshoofd") - if field_name == 'parents_information': - nice_name = _('informatiebrief voor de ouders of verzorgers') + if field_name == "parents_information": + nice_name = _("informatiebrief voor de ouders of verzorgers") - if field_name == 'dmp_file': - nice_name = _('data management plan') + if field_name == "dmp_file": + nice_name = _("data management plan") parent = file.instance @@ -56,25 +56,31 @@ def describe_file(file): trajectory_name = give_name(parent).lower() if has_trajectory: - trajectory_name = trajectory_name.replace('hoofdtraject', - 'het hoofdtraject', - ) - out_string = _(''' + trajectory_name = trajectory_name.replace( + "hoofdtraject", + "het hoofdtraject", + ) + out_string = _( + """ {} bij {} van aanvraag {}-{}: {} - ''').format(nice_name.capitalize(), - trajectory_name, - proposal.reviewing_committee.name, - proposal.reference_number, - escape(proposal.title), - ) + """ + ).format( + nice_name.capitalize(), + trajectory_name, + proposal.reviewing_committee.name, + proposal.reference_number, + escape(proposal.title), + ) else: - out_string = _(''' + out_string = _( + """ {} van aanvraag {}-{}: {} - ''').format(nice_name.capitalize(), - proposal.reviewing_committee.name, - proposal.reference_number, - escape(proposal.title), - ) - + """ + ).format( + nice_name.capitalize(), + proposal.reviewing_committee.name, + proposal.reference_number, + escape(proposal.title), + ) return mark_safe(out_string) diff --git a/studies/tests.py b/studies/tests.py index 10d42c889..6b51874ff 100644 --- a/studies/tests.py +++ b/studies/tests.py @@ -1,11 +1,11 @@ from __future__ import division -from proposals.tests import BaseProposalTestCase +from proposals.tests import MiscProposalTestCase from .models import Study from .utils import STUDY_PROGRESS_START, STUDY_PROGRESS_TOTAL, get_study_progress -class ProgressTestCase(BaseProposalTestCase): +class ProgressTestCase(MiscProposalTestCase): def test_progress_single(self): self.p1.studies_number = 1 self.p1.save() @@ -18,7 +18,9 @@ def test_progress_double(self): s1 = Study.objects.create(proposal=self.p1, order=1) s2 = Study.objects.create(proposal=self.p1, order=2) self.assertEqual(STUDY_PROGRESS_START, get_study_progress(s1)) - self.assertEqual(STUDY_PROGRESS_START + 1/2 * STUDY_PROGRESS_TOTAL, get_study_progress(s2)) + self.assertEqual( + STUDY_PROGRESS_START + 1 / 2 * STUDY_PROGRESS_TOTAL, get_study_progress(s2) + ) def test_progress_triple(self): self.p1.studies_number = 3 @@ -27,5 +29,11 @@ def test_progress_triple(self): s2 = Study.objects.create(proposal=self.p1, order=2) s3 = Study.objects.create(proposal=self.p1, order=3) self.assertEqual(int(STUDY_PROGRESS_START), get_study_progress(s1)) - self.assertEqual(int(STUDY_PROGRESS_START + 1/3 * STUDY_PROGRESS_TOTAL), get_study_progress(s2)) - self.assertEqual(int(STUDY_PROGRESS_START + 2/3 * STUDY_PROGRESS_TOTAL), get_study_progress(s3)) + self.assertEqual( + int(STUDY_PROGRESS_START + 1 / 3 * STUDY_PROGRESS_TOTAL), + get_study_progress(s2), + ) + self.assertEqual( + int(STUDY_PROGRESS_START + 2 / 3 * STUDY_PROGRESS_TOTAL), + get_study_progress(s3), + ) diff --git a/studies/translation.py b/studies/translation.py index c4fe26238..88e250b69 100644 --- a/studies/translation.py +++ b/studies/translation.py @@ -5,23 +5,24 @@ @register(AgeGroup) class AgeGroupTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) @register(Compensation) class CompensationTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) @register(Recruitment) class RecruitmentTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) @register(Trait) class TraitTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) + @register(SpecialDetail) class SpecialDetailTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) diff --git a/studies/urls.py b/studies/urls.py index c81504e02..acbc42bf5 100644 --- a/studies/urls.py +++ b/studies/urls.py @@ -1,24 +1,28 @@ from django.urls import path from .views.session_views import SessionStart -from .views.study_views import StudyUpdate, StudyDesign, StudyUpdateAttachments, StudyEnd, \ - has_adults, necessity_required +from .views.study_views import ( + StudyUpdate, + StudyDesign, + StudyUpdateAttachments, + StudyEnd, + has_adults, + necessity_required, +) -app_name = 'studies' +app_name = "studies" urlpatterns = [ # Study - path('update//', StudyUpdate.as_view(), name='update'), - - path('design//', StudyDesign.as_view(), name='design'), - path('end//', StudyEnd.as_view(), name='design_end'), - - path('attachments//', StudyUpdateAttachments.as_view(), name='attachments'), - + path("update//", StudyUpdate.as_view(), name="update"), + path("design//", StudyDesign.as_view(), name="design"), + path("end//", StudyEnd.as_view(), name="design_end"), + path("attachments//", StudyUpdateAttachments.as_view(), name="attachments"), # Session(s) - path('session/start//', SessionStart.as_view(), name='session_start'), - + path("session/start//", SessionStart.as_view(), name="session_start"), # Checks on conditional fields - path('check_has_adults/', has_adults, name='check_has_adults'), - path('check_necessity_required/', necessity_required, name='check_necessity_required'), + path("check_has_adults/", has_adults, name="check_has_adults"), + path( + "check_necessity_required/", necessity_required, name="check_necessity_required" + ), ] diff --git a/studies/utils.py b/studies/utils.py index 6b7ab7dd3..30c3e9206 100644 --- a/studies/utils.py +++ b/studies/utils.py @@ -18,7 +18,9 @@ def check_has_adults(selected_age_groups): """ from .models import AgeGroup - adult_age_groups = AgeGroup.objects.filter(is_adult=True).values_list('id', flat=True) + adult_age_groups = AgeGroup.objects.filter(is_adult=True).values_list( + "id", flat=True + ) return bool(set(selected_age_groups).intersection(adult_age_groups)) @@ -34,7 +36,9 @@ def check_necessity_required(proposal, age_groups, legally_incapable): if proposal.relation and not proposal.relation.needs_supervisor: result = False else: - required_values = AgeGroup.objects.filter(needs_details=True).values_list('id', flat=True) + required_values = AgeGroup.objects.filter(needs_details=True).values_list( + "id", flat=True + ) result = bool(set(required_values).intersection(age_groups)) result |= bool(legally_incapable) return result @@ -45,7 +49,7 @@ def get_study_progress(study, is_end=False): return STUDY_PROGRESS_START progress = STUDY_PROGRESS_TOTAL / study.proposal.studies_number if not is_end: - progress *= (study.order - 1) + progress *= study.order - 1 else: progress *= study.order return int(STUDY_PROGRESS_START + progress) @@ -60,15 +64,15 @@ def study_urls(study, prev_study_completed): """ urls = list() - study_url = AvailableURL(title=_('Deelnemers')) + study_url = AvailableURL(title=_("Deelnemers")) if study: - study_url.url = reverse('studies:update', args=(study.pk,)) + study_url.url = reverse("studies:update", args=(study.pk,)) urls.append(study_url) - design_url = AvailableURL(title=_('Onderzoekstype(n)')) + design_url = AvailableURL(title=_("Onderzoekstype(n)")) if study.compensation: - design_url.url = reverse('studies:design', args=(study.pk,)) + design_url.url = reverse("studies:design", args=(study.pk,)) urls.append(design_url) if study.has_intervention: @@ -81,15 +85,15 @@ def study_urls(study, prev_study_completed): urls.append(session_urls(study)) end_url = AvailableURL( - title=_('Overzicht'), + title=_("Overzicht"), ) if prev_study_completed: - end_url.url = reverse('studies:design_end', args=(study.pk,)) + end_url.url = reverse("studies:design_end", args=(study.pk,)) urls.append(end_url) return AvailableURL( - title=_('Traject {}').format(study.order), + title=_("Traject {}").format(study.order), is_title=True, children=urls, ) @@ -117,7 +121,9 @@ def copy_study_to_proposal(proposal, original_study): traits = original_study.traits.all() compensation = original_study.compensation recruitment = original_study.recruitment.all() - intervention = original_study.intervention if original_study.has_intervention else None + intervention = ( + original_study.intervention if original_study.has_intervention else None + ) observation = original_study.observation if original_study.has_observation else None sessions = original_study.session_set.all() if original_study.has_sessions else [] diff --git a/studies/views/session_views.py b/studies/views/session_views.py index 7a638d13c..2583c6eef 100644 --- a/studies/views/session_views.py +++ b/studies/views/session_views.py @@ -16,20 +16,23 @@ ###################### class SessionStart(AllowErrorsOnBackbuttonMixin, UpdateView): """Initial creation of Sessions""" + model = Study form_class = SessionStartForm - template_name = 'studies/session_start.html' - success_message = _('%(sessions_number)s sessie(s) voor studie %(title)s aangemaakt') + template_name = "studies/session_start.html" + success_message = _( + "%(sessions_number)s sessie(s) voor studie %(title)s aangemaakt" + ) def get_context_data(self, **kwargs): """Setting the progress on the context""" context = super(SessionStart, self).get_context_data(**kwargs) - context['progress'] = get_study_progress(self.object) + 9 + context["progress"] = get_study_progress(self.object) + 9 return context def form_valid(self, form): """Creates or deletes Sessions on save""" - nr_sessions = form.cleaned_data['sessions_number'] + nr_sessions = form.cleaned_data["sessions_number"] study = form.instance current = study.session_set.count() or 0 @@ -49,7 +52,7 @@ def form_valid(self, form): def get_next_url(self): """Continue to the addition of Tasks""" - return reverse('tasks:start', args=(self.object.first_session().pk,)) + return reverse("tasks:start", args=(self.object.first_session().pk,)) def get_back_url(self): """ @@ -57,16 +60,18 @@ def get_back_url(self): return to this part. Otherwise, return to the Study design overview. """ study = self.object - next_url = 'studies:design' + next_url = "studies:design" pk = study.pk if study.has_observation: - next_url = 'observations:update' + next_url = "observations:update" pk = study.observation.pk elif study.has_intervention: - next_url = 'interventions:update' + next_url = "interventions:update" pk = study.intervention.pk return reverse(next_url, args=(pk,)) def get_success_message(self, cleaned_data): """Fill the success message using the cleaned_data""" - return self.success_message % dict(cleaned_data, title=self.object.proposal.title) + return self.success_message % dict( + cleaned_data, title=self.object.proposal.title + ) diff --git a/studies/views/study_views.py b/studies/views/study_views.py index b2843c36b..38e100737 100644 --- a/studies/views/study_views.py +++ b/studies/views/study_views.py @@ -14,7 +14,13 @@ from interventions.models import Intervention from observations.models import Observation -from ..forms import StudyForm, StudyDesignForm, StudyConsentForm, StudyEndForm, StudyUpdateAttachmentsForm +from ..forms import ( + StudyForm, + StudyDesignForm, + StudyConsentForm, + StudyEndForm, + StudyUpdateAttachmentsForm, +) from ..models import Study, Documents from ..utils import check_has_adults, check_necessity_required, get_study_progress @@ -24,34 +30,35 @@ ####################### class StudyUpdate(AllowErrorsOnBackbuttonMixin, UpdateView): """Updates a Study from a StudyForm""" + model = Study form_class = StudyForm - success_message = _('Studie opgeslagen') + success_message = _("Studie opgeslagen") def get_context_data(self, **kwargs): """Setting the progress on the context""" context = super(StudyUpdate, self).get_context_data(**kwargs) - context['progress'] = get_study_progress(self.object) + context["progress"] = get_study_progress(self.object) return context def get_form_kwargs(self): """Sets the Proposal as a form kwarg""" kwargs = super(StudyUpdate, self).get_form_kwargs() - kwargs['proposal'] = self.object.proposal + kwargs["proposal"] = self.object.proposal return kwargs def get_back_url(self): proposal = self.object.proposal if self.object.order == 1: - return reverse('proposals:study_start', args=(proposal.pk,)) + return reverse("proposals:study_start", args=(proposal.pk,)) else: prev = self.object.order - 1 prev_study = Study.objects.get(proposal=proposal, order=prev) - return reverse('studies:design_end', args=(prev_study.pk,)) + return reverse("studies:design_end", args=(prev_study.pk,)) def get_next_url(self): """Continue to the Study design overview""" - return reverse('studies:design', args=(self.object.pk,)) + return reverse("studies:design", args=(self.object.pk,)) ############### @@ -60,13 +67,13 @@ def get_next_url(self): class StudyDesign(AllowErrorsOnBackbuttonMixin, UpdateView): model = Study form_class = StudyDesignForm - success_message = _('Traject opgeslagen') - template_name = 'studies/study_design.html' + success_message = _("Traject opgeslagen") + template_name = "studies/study_design.html" def get_context_data(self, **kwargs): """Setting the progress on the context""" context = super(StudyDesign, self).get_context_data(**kwargs) - context['progress'] = get_study_progress(self.object) + 3 + context["progress"] = get_study_progress(self.object) + 3 return context def get_next_url(self): @@ -75,48 +82,50 @@ def get_next_url(self): continue to this part. Otherwise, continue to the Study start overview. """ study = self.object - next_url = 'studies:design_end' + next_url = "studies:design_end" pk = study.pk if study.has_intervention: - if hasattr(study, 'intervention'): - next_url = 'interventions:update' + if hasattr(study, "intervention"): + next_url = "interventions:update" pk = study.intervention.pk else: - next_url = 'interventions:create' + next_url = "interventions:create" elif study.has_observation: - if hasattr(study, 'observation'): - next_url = 'observations:update' + if hasattr(study, "observation"): + next_url = "observations:update" pk = study.observation.pk else: - next_url = 'observations:create' + next_url = "observations:create" elif study.has_sessions: - next_url = 'studies:session_start' + next_url = "studies:session_start" return reverse(next_url, args=(pk,)) def get_back_url(self): """ Return to the Study overview """ - return reverse('studies:update', args=(self.kwargs['pk'],)) + return reverse("studies:update", args=(self.kwargs["pk"],)) + class StudyEnd(AllowErrorsOnBackbuttonMixin, UpdateView): """ Completes a Study """ + model = Study form_class = StudyEndForm - template_name = 'studies/study_end.html' + template_name = "studies/study_end.html" def get_context_data(self, **kwargs): """Setting the progress on the context""" context = super(StudyEnd, self).get_context_data(**kwargs) - context['progress'] = get_study_progress(self.object, True) - 10 + context["progress"] = get_study_progress(self.object, True) - 10 return context def get_form_kwargs(self): """Sets the Study as a form kwarg""" kwargs = super(StudyEnd, self).get_form_kwargs() - kwargs['study'] = self.object + kwargs["study"] = self.object return kwargs def get_next_url(self): @@ -128,23 +137,23 @@ def get_next_url(self): if self.object.order < proposal.studies_number: next_order = self.object.order + 1 next_study = Study.objects.get(proposal=proposal, order=next_order) - return reverse('studies:update', args=(next_study.pk,)) + return reverse("studies:update", args=(next_study.pk,)) else: - return reverse('proposals:translated', args=(proposal.pk,)) + return reverse("proposals:translated", args=(proposal.pk,)) def get_back_url(self): study = self.object if study.has_sessions: - next_url = 'tasks:end' + next_url = "tasks:end" pk = self.object.last_session().pk elif study.has_intervention: - next_url = 'interventions:update' + next_url = "interventions:update" pk = Intervention.objects.get(study=study).pk elif study.has_observation: - next_url = 'observations:update' + next_url = "observations:update" pk = Observation.objects.get(study=study).pk else: - next_url = 'studies:design' + next_url = "studies:design" pk = study.pk return reverse(next_url, args=(pk,)) @@ -154,8 +163,9 @@ class StudyUpdateAttachments(braces.GroupRequiredMixin, generic.UpdateView): """ Allows the secretary to change the attachments on Study level """ + model = Documents - template_name = 'studies/study_update_attachments.html' + template_name = "studies/study_update_attachments.html" form_class = StudyUpdateAttachmentsForm group_required = settings.GROUP_SECRETARY @@ -171,7 +181,7 @@ def form_valid(self, form): def get_success_url(self): """Continue to the URL specified in the 'next' POST parameter""" - return self.request.POST.get('next', '/') + return self.request.POST.get("next", "/") ################ @@ -182,8 +192,8 @@ def has_adults(request): """ This call checks whether the selected AgeGroups contain adult age groups. """ - age_groups = map(int, request.POST.getlist('age_groups[]')) - return JsonResponse({'result': check_has_adults(age_groups)}) + age_groups = map(int, request.POST.getlist("age_groups[]")) + return JsonResponse({"result": check_has_adults(age_groups)}) @csrf_exempt @@ -195,7 +205,9 @@ def necessity_required(request): ** Participants have been selected on certain traits. ** Participants are legally incapable. """ - proposal = Proposal.objects.get(pk=request.POST.get('proposal_pk')) - age_groups = map(int, request.POST.getlist('age_groups[]')) - legally_incapable = string_to_bool(request.POST.get('legally_incapable')) - return JsonResponse({'result': check_necessity_required(proposal, age_groups, legally_incapable)}) + proposal = Proposal.objects.get(pk=request.POST.get("proposal_pk")) + age_groups = map(int, request.POST.getlist("age_groups[]")) + legally_incapable = string_to_bool(request.POST.get("legally_incapable")) + return JsonResponse( + {"result": check_necessity_required(proposal, age_groups, legally_incapable)} + ) diff --git a/tasks/admin.py b/tasks/admin.py index 0ebaec78f..6f647082d 100644 --- a/tasks/admin.py +++ b/tasks/admin.py @@ -5,13 +5,27 @@ @admin.register(Registration) class RegistrationAdmin(admin.ModelAdmin): - list_display = ('order', 'description', 'is_local', 'needs_details', 'needs_kind', 'requires_review', 'age_min', ) - list_display_links = ('description', ) - ordering = ['order'] + list_display = ( + "order", + "description", + "is_local", + "needs_details", + "needs_kind", + "requires_review", + "age_min", + ) + list_display_links = ("description",) + ordering = ["order"] @admin.register(RegistrationKind) class RegistrationKindAdmin(admin.ModelAdmin): - list_display = ('registration', 'order', 'description', 'needs_details', 'requires_review', ) - list_display_links = ('description', ) - ordering = ['registration', 'order'] + list_display = ( + "registration", + "order", + "description", + "needs_details", + "requires_review", + ) + list_display_links = ("description",) + ordering = ["registration", "order"] diff --git a/tasks/fixtures/registrations.json b/tasks/fixtures/00_registrations.json similarity index 96% rename from tasks/fixtures/registrations.json rename to tasks/fixtures/00_registrations.json index 7acbf8c3d..6d796ae4b 100644 --- a/tasks/fixtures/registrations.json +++ b/tasks/fixtures/00_registrations.json @@ -49,9 +49,9 @@ "pk": 4, "fields": { "order": 4, - "description": "gedrags- en/of reactietijd-registratie via experimentsoftware zoals jsPsych, Zep, Presentation, E-prime, etc", - "description_nl": "gedrags- en/of reactietijd-registratie via experimentsoftware zoals jsPsych, Zep, Presentation, E-prime, etc", - "description_en": "behavioral- and/or reaction time registration using experiment software such as jsPsych, Zep, Presentation, E-prime, etc.", + "description": "gedrags- en/of reactietijd-registratie via experimentsoftware zoals jsPsych, Zep, Presentation, etc", + "description_nl": "gedrags- en/of reactietijd-registratie via experimentsoftware zoals jsPsych, Zep, Presentation, etc", + "description_en": "behavioral- and/or reaction time registration using experiment software such as jsPsych, Zep, Presentation, etc.", "is_local": true, "needs_details": false, "needs_kind": false, diff --git a/tasks/fixtures/registrationkinds.json b/tasks/fixtures/01_registrationkinds.json similarity index 100% rename from tasks/fixtures/registrationkinds.json rename to tasks/fixtures/01_registrationkinds.json diff --git a/tasks/forms.py b/tasks/forms.py index 1036fdf25..33f756a42 100644 --- a/tasks/forms.py +++ b/tasks/forms.py @@ -10,34 +10,42 @@ from django.utils.safestring import mark_safe from django.utils.functional import lazy + mark_safe_lazy = lazy(mark_safe, str) + class TaskStartForm(SoftValidationMixin, ConditionalModelForm): is_copy = forms.BooleanField( - label=_('Is deze sessie een kopie van een voorgaande sessie?'), - help_text=_(u'Na het kopiëren zijn alle velden bewerkbaar.'), + label=_("Is deze sessie een kopie van een voorgaande sessie?"), + help_text=_("Na het kopiëren zijn alle velden bewerkbaar."), widget=forms.RadioSelect(choices=YES_NO), initial=False, - required=False) + required=False, + ) parent_session = forms.ModelChoiceField( - label=_(u'Te kopiëren sessie'), - queryset=Session.objects.all(), - required=False) + label=_("Te kopiëren sessie"), queryset=Session.objects.all(), required=False + ) class Meta: model = Session fields = [ - 'setting', 'setting_details', 'supervision', 'leader_has_coc', - 'tasks_number', + "setting", + "setting_details", + "supervision", + "leader_has_coc", + "tasks_number", ] widgets = { - 'setting': forms.CheckboxSelectMultiple(), - 'supervision': forms.RadioSelect(choices=YES_NO), - 'leader_has_coc': forms.RadioSelect(choices=YES_NO), + "setting": forms.CheckboxSelectMultiple(), + "supervision": forms.RadioSelect(choices=YES_NO), + "leader_has_coc": forms.RadioSelect(choices=YES_NO), } _soft_validation_fields = [ - 'setting', 'setting_details', 'supervision', 'leader_has_coc' + "setting", + "setting_details", + "supervision", + "leader_has_coc", ] def __init__(self, *args, **kwargs): @@ -48,21 +56,22 @@ def __init__(self, *args, **kwargs): - Remove option to copy altogether from first Session - Don't ask the supervision question when there are only adult AgeGroups in this Study """ - self.study = kwargs.pop('study', None) + self.study = kwargs.pop("study", None) super(TaskStartForm, self).__init__(*args, **kwargs) - self.fields['tasks_number'].required = False - self.fields['parent_session'].queryset = Session.objects.filter(study=self.instance.study.pk, - order__lt=self.instance.order) + self.fields["tasks_number"].required = False + self.fields["parent_session"].queryset = Session.objects.filter( + study=self.instance.study.pk, order__lt=self.instance.order + ) if self.instance.order == 1: - del self.fields['is_copy'] - del self.fields['parent_session'] + del self.fields["is_copy"] + del self.fields["parent_session"] # TODO: add warning if not self.study.has_children(): - del self.fields['supervision'] - del self.fields['leader_has_coc'] + del self.fields["supervision"] + del self.fields["leader_has_coc"] def clean(self): """ @@ -73,41 +82,58 @@ def clean(self): """ cleaned_data = super(TaskStartForm, self).clean() - self.mark_soft_required(cleaned_data, 'setting') + self.mark_soft_required(cleaned_data, "setting") - self.check_dependency_multiple(cleaned_data, 'setting', 'needs_details', 'setting_details') + self.check_dependency_multiple( + cleaned_data, "setting", "needs_details", "setting_details" + ) if self.study.has_children(): - self.check_dependency_multiple(cleaned_data, 'setting', 'needs_supervision', 'supervision') - self.check_dependency(cleaned_data, 'supervision', 'leader_has_coc', f1_value=False) - - self.check_dependency(cleaned_data, 'is_copy', 'parent_session') - if not cleaned_data.get('is_copy') and not cleaned_data.get('tasks_number'): + self.check_dependency_multiple( + cleaned_data, "setting", "needs_supervision", "supervision" + ) + self.check_dependency( + cleaned_data, "supervision", "leader_has_coc", f1_value=False + ) + + self.check_dependency(cleaned_data, "is_copy", "parent_session") + if not cleaned_data.get("is_copy") and not cleaned_data.get("tasks_number"): # Prevent double required errors - if 'tasks_number' not in self.errors: - self.add_error('tasks_number', forms.ValidationError(_('Dit veld is verplicht.'), code='required')) + if "tasks_number" not in self.errors: + self.add_error( + "tasks_number", + forms.ValidationError(_("Dit veld is verplicht."), code="required"), + ) - class TaskForm(SoftValidationMixin, ConditionalModelForm): class Meta: model = Task fields = [ - 'name', 'description', 'duration', - 'registrations', 'registrations_details', - 'registration_kinds', 'registration_kinds_details', - 'feedback', 'feedback_details', + "name", + "description", + "duration", + "registrations", + "registrations_details", + "registration_kinds", + "registration_kinds_details", + "feedback", + "feedback_details", ] labels = { - 'duration': mark_safe_lazy(_('Wat is de duur van deze taak van begin tot eind in minuten, \ + "duration": mark_safe_lazy( + _( + "Wat is de duur van deze taak van begin tot eind in minuten, \ dus vanaf het moment dat de taak van start gaat tot en met het einde van de taak \ (exclusief instructie maar inclusief oefensessie)? \ Indien de taakduur per deelnemer varieert (self-paced taak of task-to-criterion), \ -geef dan het redelijkerwijs te verwachten maximum op.')), - } +geef dan het redelijkerwijs te verwachten maximum op." + ) + ), + } widgets = { - 'registrations': forms.CheckboxSelectMultiple(), - 'registration_kinds': forms.CheckboxSelectMultiple(), - 'feedback': forms.RadioSelect(choices=YES_NO), + "registrations": forms.CheckboxSelectMultiple(), + "registration_kinds": forms.CheckboxSelectMultiple(), + "feedback": forms.RadioSelect(choices=YES_NO), } def __init__(self, *args, **kwargs): @@ -130,23 +156,32 @@ def clean(self): self.mark_soft_required( cleaned_data, - 'name', - 'description', - 'duration', + "name", + "description", + "duration", #'registrations', ) - self.check_empty(cleaned_data, 'feedback') - self.check_dependency_multiple(cleaned_data, 'registrations', 'needs_kind', 'registration_kinds') - self.check_dependency_multiple(cleaned_data, 'registrations', 'needs_details', 'registrations_details') - self.check_dependency_multiple(cleaned_data, 'registration_kinds', 'needs_details', 'registration_kinds_details') - self.check_dependency(cleaned_data, 'feedback', 'feedback_details') + self.check_empty(cleaned_data, "feedback") + self.check_dependency_multiple( + cleaned_data, "registrations", "needs_kind", "registration_kinds" + ) + self.check_dependency_multiple( + cleaned_data, "registrations", "needs_details", "registrations_details" + ) + self.check_dependency_multiple( + cleaned_data, + "registration_kinds", + "needs_details", + "registration_kinds_details", + ) + self.check_dependency(cleaned_data, "feedback", "feedback_details") class TaskEndForm(SoftValidationMixin, forms.ModelForm): class Meta: model = Session - fields = ['tasks_duration'] + fields = ["tasks_duration"] def __init__(self, *args, **kwargs): """ @@ -155,11 +190,11 @@ def __init__(self, *args, **kwargs): """ super(TaskEndForm, self).__init__(*args, **kwargs) - tasks_duration = self.fields['tasks_duration'] + tasks_duration = self.fields["tasks_duration"] label = tasks_duration.label % self.instance.net_duration() tasks_duration.label = mark_safe(label) - _soft_validation_fields = ['tasks_duration'] + _soft_validation_fields = ["tasks_duration"] def is_initial_visit(self) -> bool: return True @@ -167,7 +202,7 @@ def is_initial_visit(self) -> bool: def clean(self): cleaned_data = super(TaskEndForm, self).clean() - self.mark_soft_required(cleaned_data, 'tasks_duration') + self.mark_soft_required(cleaned_data, "tasks_duration") return cleaned_data @@ -175,9 +210,12 @@ def clean_tasks_duration(self): """ Check that the net duration is at least equal to the gross duration """ - tasks_duration = self.cleaned_data.get('tasks_duration') + tasks_duration = self.cleaned_data.get("tasks_duration") if tasks_duration and tasks_duration < self.instance.net_duration(): - raise forms.ValidationError(_('Totale sessieduur moet minstens gelijk zijn aan netto sessieduur.'), code='comparison') + raise forms.ValidationError( + _("Totale sessieduur moet minstens gelijk zijn aan netto sessieduur."), + code="comparison", + ) return tasks_duration diff --git a/tasks/migrations/0001_initial.py b/tasks/migrations/0001_initial.py index 7c514c215..1f60df860 100644 --- a/tasks/migrations/0001_initial.py +++ b/tasks/migrations/0001_initial.py @@ -6,85 +6,207 @@ class Migration(migrations.Migration): - dependencies = [ - ('studies', '0001_initial'), - ('main', '0001_initial'), + ("studies", "0001_initial"), + ("main", "0001_initial"), ] operations = [ migrations.CreateModel( - name='Registration', + name="Registration", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('order', models.PositiveIntegerField(unique=True)), - ('description', models.CharField(max_length=200)), - ('needs_details', models.BooleanField(default=False)), - ('needs_kind', models.BooleanField(default=False)), - ('requires_review', models.BooleanField(default=False)), - ('age_min', models.PositiveIntegerField(null=True, blank=True)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("order", models.PositiveIntegerField(unique=True)), + ("description", models.CharField(max_length=200)), + ("needs_details", models.BooleanField(default=False)), + ("needs_kind", models.BooleanField(default=False)), + ("requires_review", models.BooleanField(default=False)), + ("age_min", models.PositiveIntegerField(null=True, blank=True)), ], options={ - 'ordering': ['order'], + "ordering": ["order"], }, ), migrations.CreateModel( - name='RegistrationKind', + name="RegistrationKind", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('order', models.PositiveIntegerField(unique=True)), - ('description', models.CharField(max_length=200)), - ('needs_details', models.BooleanField(default=False)), - ('requires_review', models.BooleanField(default=False)), - ('registration', models.ForeignKey(to='tasks.Registration', on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("order", models.PositiveIntegerField(unique=True)), + ("description", models.CharField(max_length=200)), + ("needs_details", models.BooleanField(default=False)), + ("requires_review", models.BooleanField(default=False)), + ( + "registration", + models.ForeignKey( + to="tasks.Registration", on_delete=models.CASCADE + ), + ), ], options={ - 'ordering': ['order'], + "ordering": ["order"], }, ), migrations.CreateModel( - name='Session', + name="Session", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('setting_details', models.CharField(max_length=200, verbose_name='Namelijk', blank=True)), - ('supervision', models.NullBooleanField(verbose_name='Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?')), - ('order', models.PositiveIntegerField()), - ('tasks_number', models.PositiveIntegerField(help_text='Wanneer u bijvoorbeeld eerst de deelnemer observeert en de deelnemer vervolgens een vragenlijst afneemt, dan vult u hierboven "2" in. Electrodes plakken, sessie-debriefing en kort (< 3 minuten) exit-interview gelden niet als een taak.', null=True, verbose_name='Hoeveel taken worden er binnen deze sessie bij de deelnemer afgenomen?', validators=[django.core.validators.MinValueValidator(1)])), - ('tasks_duration', models.PositiveIntegerField(null=True, verbose_name='De totale geschatte netto taakduur van uw sessie komt op basis van uw opgave per taak uit op %d minuten. Hoe lang duurt de totale sessie, inclusief ontvangst, instructies per taak, pauzes tussen taken, en debriefing? (bij labbezoek dus van binnenkomst tot vertrek)')), - ('setting', models.ManyToManyField(to='main.Setting', - verbose_name='Geef aan waar de dataverzameling plaatsvindt')), - ('study', models.ForeignKey(to='studies.Study', on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "setting_details", + models.CharField( + max_length=200, verbose_name="Namelijk", blank=True + ), + ), + ( + "supervision", + models.NullBooleanField( + verbose_name="Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?" + ), + ), + ("order", models.PositiveIntegerField()), + ( + "tasks_number", + models.PositiveIntegerField( + help_text='Wanneer u bijvoorbeeld eerst de deelnemer observeert en de deelnemer vervolgens een vragenlijst afneemt, dan vult u hierboven "2" in. Electrodes plakken, sessie-debriefing en kort (< 3 minuten) exit-interview gelden niet als een taak.', + null=True, + verbose_name="Hoeveel taken worden er binnen deze sessie bij de deelnemer afgenomen?", + validators=[django.core.validators.MinValueValidator(1)], + ), + ), + ( + "tasks_duration", + models.PositiveIntegerField( + null=True, + verbose_name="De totale geschatte netto taakduur van uw sessie komt op basis van uw opgave per taak uit op %d minuten. Hoe lang duurt de totale sessie, inclusief ontvangst, instructies per taak, pauzes tussen taken, en debriefing? (bij labbezoek dus van binnenkomst tot vertrek)", + ), + ), + ( + "setting", + models.ManyToManyField( + to="main.Setting", + verbose_name="Geef aan waar de dataverzameling plaatsvindt", + ), + ), + ( + "study", + models.ForeignKey(to="studies.Study", on_delete=models.CASCADE), + ), ], options={ - 'ordering': ['order'], + "ordering": ["order"], }, ), migrations.CreateModel( - name='Task', + name="Task", fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('order', models.PositiveIntegerField()), - ('name', models.CharField(max_length=200, verbose_name='Wat is de naam van de taak?')), - ('description', models.TextField(verbose_name='Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort uit hoe deze taak (en de eventuele manipulaties daarbinnen) aan de beantwoording van uw onderzoeksvragen bijdraagt.')), - ('duration', models.PositiveIntegerField(default=0, verbose_name='Wat is de duur van deze taak van begin tot eind in minuten, dus vanaf het moment dat de taak van start gaat tot en met het einde van de taak (exclusief instructie maar inclusief oefensessie)? Indien de taakduur per deelnemer varieert (self-paced taak of task-to-criterion), geef dan het redelijkerwijs te verwachten maximum op.', validators=[django.core.validators.MinValueValidator(1)])), - ('registrations_details', models.CharField(max_length=200, verbose_name='Namelijk', blank=True)), - ('registration_kinds_details', models.CharField(max_length=200, verbose_name='Namelijk', blank=True)), - ('feedback', models.NullBooleanField(verbose_name='Krijgt de deelnemer tijdens of na deze taak feedback op zijn/haar gedrag of toestand?')), - ('feedback_details', models.TextField(verbose_name='Beschrijf hoe de feedback wordt gegeven.', blank=True)), - ('registration_kinds', models.ManyToManyField(to='tasks.RegistrationKind', verbose_name='Kies het soort meting', blank=True)), - ('registrations', models.ManyToManyField(to='tasks.Registration', verbose_name='Hoe wordt het gedrag of de toestand van de deelnemer bij deze taak vastgelegd?')), - ('session', models.ForeignKey(to='tasks.Session', on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ("order", models.PositiveIntegerField()), + ( + "name", + models.CharField( + max_length=200, verbose_name="Wat is de naam van de taak?" + ), + ), + ( + "description", + models.TextField( + verbose_name="Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort uit hoe deze taak (en de eventuele manipulaties daarbinnen) aan de beantwoording van uw onderzoeksvragen bijdraagt." + ), + ), + ( + "duration", + models.PositiveIntegerField( + default=0, + verbose_name="Wat is de duur van deze taak van begin tot eind in minuten, dus vanaf het moment dat de taak van start gaat tot en met het einde van de taak (exclusief instructie maar inclusief oefensessie)? Indien de taakduur per deelnemer varieert (self-paced taak of task-to-criterion), geef dan het redelijkerwijs te verwachten maximum op.", + validators=[django.core.validators.MinValueValidator(1)], + ), + ), + ( + "registrations_details", + models.CharField( + max_length=200, verbose_name="Namelijk", blank=True + ), + ), + ( + "registration_kinds_details", + models.CharField( + max_length=200, verbose_name="Namelijk", blank=True + ), + ), + ( + "feedback", + models.NullBooleanField( + verbose_name="Krijgt de deelnemer tijdens of na deze taak feedback op zijn/haar gedrag of toestand?" + ), + ), + ( + "feedback_details", + models.TextField( + verbose_name="Beschrijf hoe de feedback wordt gegeven.", + blank=True, + ), + ), + ( + "registration_kinds", + models.ManyToManyField( + to="tasks.RegistrationKind", + verbose_name="Kies het soort meting", + blank=True, + ), + ), + ( + "registrations", + models.ManyToManyField( + to="tasks.Registration", + verbose_name="Hoe wordt het gedrag of de toestand van de deelnemer bij deze taak vastgelegd?", + ), + ), + ( + "session", + models.ForeignKey(to="tasks.Session", on_delete=models.CASCADE), + ), ], options={ - 'ordering': ['order'], + "ordering": ["order"], }, ), migrations.AlterUniqueTogether( - name='task', - unique_together=set([('session', 'order')]), + name="task", + unique_together=set([("session", "order")]), ), migrations.AlterUniqueTogether( - name='session', - unique_together=set([('study', 'order')]), + name="session", + unique_together=set([("study", "order")]), ), ] diff --git a/tasks/migrations/0002_auto_20160927_2106.py b/tasks/migrations/0002_auto_20160927_2106.py index 6f6ec63b7..01d4f3fe2 100644 --- a/tasks/migrations/0002_auto_20160927_2106.py +++ b/tasks/migrations/0002_auto_20160927_2106.py @@ -6,20 +6,25 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0001_initial'), + ("tasks", "0001_initial"), ] operations = [ migrations.AlterField( - model_name='task', - name='description', - field=models.TextField(verbose_name='Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort uit hoe deze taak (en de eventuele manipulaties daarbinnen) aan de beantwoording van uw onderzoeksvragen bijdraagt. Geef, kort, een paar voorbeelden (of beschrijvingen) van het type stimuli dat u van plan bent aan de deelnemer aan te bieden. Het moet voor de commissieleden duidelijk zijn wat u precies gaat doen.'), + model_name="task", + name="description", + field=models.TextField( + verbose_name="Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort uit hoe deze taak (en de eventuele manipulaties daarbinnen) aan de beantwoording van uw onderzoeksvragen bijdraagt. Geef, kort, een paar voorbeelden (of beschrijvingen) van het type stimuli dat u van plan bent aan de deelnemer aan te bieden. Het moet voor de commissieleden duidelijk zijn wat u precies gaat doen." + ), ), migrations.AlterField( - model_name='task', - name='duration', - field=models.PositiveIntegerField(default=0, verbose_name='Wat is de duur van deze taak van begin tot eind in minuten, dus vanaf het moment dat de taak van start gaat tot en met het einde van de taak (exclusief instructie maar inclusief oefensessie)? Indien de taakduur per deelnemer varieert (self-paced taak of task-to-criterion), geef dan het redelijkerwijs te verwachten maximum op.', validators=[django.core.validators.MinValueValidator(1)]), + model_name="task", + name="duration", + field=models.PositiveIntegerField( + default=0, + verbose_name="Wat is de duur van deze taak van begin tot eind in minuten, dus vanaf het moment dat de taak van start gaat tot en met het einde van de taak (exclusief instructie maar inclusief oefensessie)? Indien de taakduur per deelnemer varieert (self-paced taak of task-to-criterion), geef dan het redelijkerwijs te verwachten maximum op.", + validators=[django.core.validators.MinValueValidator(1)], + ), ), ] diff --git a/tasks/migrations/0003_auto_20161013_1959.py b/tasks/migrations/0003_auto_20161013_1959.py index 2611dae59..2b112c733 100644 --- a/tasks/migrations/0003_auto_20161013_1959.py +++ b/tasks/migrations/0003_auto_20161013_1959.py @@ -5,30 +5,29 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0002_auto_20160927_2106'), + ("tasks", "0002_auto_20160927_2106"), ] operations = [ migrations.AddField( - model_name='registration', - name='description_en', + model_name="registration", + name="description_en", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='registration', - name='description_nl', + model_name="registration", + name="description_nl", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='registrationkind', - name='description_en', + model_name="registrationkind", + name="description_en", field=models.CharField(max_length=200, null=True), ), migrations.AddField( - model_name='registrationkind', - name='description_nl', + model_name="registrationkind", + name="description_nl", field=models.CharField(max_length=200, null=True), ), ] diff --git a/tasks/migrations/0004_auto_20170601_0816.py b/tasks/migrations/0004_auto_20170601_0816.py index fc4bd1a9d..e3272efbd 100644 --- a/tasks/migrations/0004_auto_20170601_0816.py +++ b/tasks/migrations/0004_auto_20170601_0816.py @@ -5,19 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0003_auto_20161013_1959'), + ("tasks", "0003_auto_20161013_1959"), ] operations = [ migrations.AlterModelOptions( - name='registration', - options={'ordering': ['order'], 'verbose_name': 'Vastlegging gedrag'}, + name="registration", + options={"ordering": ["order"], "verbose_name": "Vastlegging gedrag"}, ), migrations.AddField( - model_name='registration', - name='is_local', + model_name="registration", + name="is_local", field=models.BooleanField(default=False), ), ] diff --git a/tasks/migrations/0005_session_leader_has_coc.py b/tasks/migrations/0005_session_leader_has_coc.py index 3ad3c71f7..90d51d7a0 100644 --- a/tasks/migrations/0005_session_leader_has_coc.py +++ b/tasks/migrations/0005_session_leader_has_coc.py @@ -5,15 +5,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0004_auto_20170601_0816'), + ("tasks", "0004_auto_20170601_0816"), ] operations = [ migrations.AddField( - model_name='session', - name='leader_has_coc', - field=models.NullBooleanField(help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De ETCL neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', verbose_name='Is de testleider in het bezit van een VOG?'), + model_name="session", + name="leader_has_coc", + field=models.NullBooleanField( + help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De ETCL neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', + verbose_name="Is de testleider in het bezit van een VOG?", + ), ), ] diff --git a/tasks/migrations/0006_auto_20190206_1452.py b/tasks/migrations/0006_auto_20190206_1452.py index 3120dda0e..8e93d3058 100644 --- a/tasks/migrations/0006_auto_20190206_1452.py +++ b/tasks/migrations/0006_auto_20190206_1452.py @@ -7,35 +7,52 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0005_session_leader_has_coc'), + ("tasks", "0005_session_leader_has_coc"), ] operations = [ migrations.AlterField( - model_name='session', - name='setting', - field=models.ManyToManyField(blank=True, to='main.Setting', verbose_name='Geef aan waar de dataverzameling plaatsvindt'), + model_name="session", + name="setting", + field=models.ManyToManyField( + blank=True, + to="main.Setting", + verbose_name="Geef aan waar de dataverzameling plaatsvindt", + ), ), migrations.AlterField( - model_name='session', - name='tasks_duration', - field=models.PositiveIntegerField(blank=True, null=True, verbose_name='De totale geschatte netto taakduur van uw sessie komt op basis van uw opgave per taak uit op %d minuten. Hoe lang duurt de totale sessie, inclusief ontvangst, instructies per taak, pauzes tussen taken, en debriefing? (bij labbezoek dus van binnenkomst tot vertrek)'), + model_name="session", + name="tasks_duration", + field=models.PositiveIntegerField( + blank=True, + null=True, + verbose_name="De totale geschatte netto taakduur van uw sessie komt op basis van uw opgave per taak uit op %d minuten. Hoe lang duurt de totale sessie, inclusief ontvangst, instructies per taak, pauzes tussen taken, en debriefing? (bij labbezoek dus van binnenkomst tot vertrek)", + ), ), migrations.AlterField( - model_name='task', - name='description', - field=models.TextField(blank=True, verbose_name='Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort uit hoe deze taak (en de eventuele manipulaties daarbinnen) aan de beantwoording van uw onderzoeksvragen bijdraagt. Geef, kort, een paar voorbeelden (of beschrijvingen) van het type stimuli dat u van plan bent aan de deelnemer aan te bieden. Het moet voor de commissieleden duidelijk zijn wat u precies gaat doen.'), + model_name="task", + name="description", + field=models.TextField( + blank=True, + verbose_name="Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort uit hoe deze taak (en de eventuele manipulaties daarbinnen) aan de beantwoording van uw onderzoeksvragen bijdraagt. Geef, kort, een paar voorbeelden (of beschrijvingen) van het type stimuli dat u van plan bent aan de deelnemer aan te bieden. Het moet voor de commissieleden duidelijk zijn wat u precies gaat doen.", + ), ), migrations.AlterField( - model_name='task', - name='duration', - field=models.PositiveIntegerField(blank=True, default=0, validators=[django.core.validators.MinValueValidator(1)], verbose_name='Wat is de duur van deze taak van begin tot eind in minuten, dus vanaf het moment dat de taak van start gaat tot en met het einde van de taak (exclusief instructie maar inclusief oefensessie)? Indien de taakduur per deelnemer varieert (self-paced taak of task-to-criterion), geef dan het redelijkerwijs te verwachten maximum op.'), + model_name="task", + name="duration", + field=models.PositiveIntegerField( + blank=True, + default=0, + validators=[django.core.validators.MinValueValidator(1)], + verbose_name="Wat is de duur van deze taak van begin tot eind in minuten, dus vanaf het moment dat de taak van start gaat tot en met het einde van de taak (exclusief instructie maar inclusief oefensessie)? Indien de taakduur per deelnemer varieert (self-paced taak of task-to-criterion), geef dan het redelijkerwijs te verwachten maximum op.", + ), ), migrations.AlterField( - model_name='task', - name='name', - field=models.CharField(blank=True, max_length=200, verbose_name='Wat is de naam van de taak?'), + model_name="task", + name="name", + field=models.CharField( + blank=True, max_length=200, verbose_name="Wat is de naam van de taak?" + ), ), ] diff --git a/tasks/migrations/0007_auto_20190401_1343.py b/tasks/migrations/0007_auto_20190401_1343.py index 97fb938cd..6b78c9266 100644 --- a/tasks/migrations/0007_auto_20190401_1343.py +++ b/tasks/migrations/0007_auto_20190401_1343.py @@ -6,15 +6,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0006_auto_20190206_1452'), + ("tasks", "0006_auto_20190206_1452"), ] operations = [ migrations.AlterField( - model_name='session', - name='leader_has_coc', - field=models.NullBooleanField(help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', verbose_name='Is de testleider in het bezit van een VOG?'), + model_name="session", + name="leader_has_coc", + field=models.NullBooleanField( + help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', + verbose_name="Is de testleider in het bezit van een VOG?", + ), ), ] diff --git a/tasks/migrations/0008_auto_20200428_1337.py b/tasks/migrations/0008_auto_20200428_1337.py index fffe371b6..bb500c031 100644 --- a/tasks/migrations/0008_auto_20200428_1337.py +++ b/tasks/migrations/0008_auto_20200428_1337.py @@ -4,25 +4,37 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0007_auto_20190401_1343'), + ("tasks", "0007_auto_20190401_1343"), ] operations = [ migrations.AlterField( - model_name='session', - name='leader_has_coc', - field=models.BooleanField(blank=True, help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', null=True, verbose_name='Is de testleider in het bezit van een VOG?'), + model_name="session", + name="leader_has_coc", + field=models.BooleanField( + blank=True, + help_text='Iedereen die op een school werkt moet in het bezit zijn van een Verklaring Omtrent Gedrag (VOG, zie https://www.justis.nl/producten/vog/). Het is de verantwoordelijkheid van de school om hierom te vragen. De FETC-GW neemt hierin een adviserende rol en wil de onderzoekers waarschuwen dat de school om een VOG kan vragen.', + null=True, + verbose_name="Is de testleider in het bezit van een VOG?", + ), ), migrations.AlterField( - model_name='session', - name='supervision', - field=models.BooleanField(blank=True, null=True, verbose_name='Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?'), + model_name="session", + name="supervision", + field=models.BooleanField( + blank=True, + null=True, + verbose_name="Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of een ander persoon die bevoegd is?", + ), ), migrations.AlterField( - model_name='task', - name='feedback', - field=models.BooleanField(blank=True, null=True, verbose_name='Krijgt de deelnemer tijdens of na deze taak feedback op zijn/haar gedrag of toestand?'), + model_name="task", + name="feedback", + field=models.BooleanField( + blank=True, + null=True, + verbose_name="Krijgt de deelnemer tijdens of na deze taak feedback op zijn/haar gedrag of toestand?", + ), ), ] diff --git a/tasks/migrations/0009_auto_20210301_1626.py b/tasks/migrations/0009_auto_20210301_1626.py index a0393656b..a093ffde7 100644 --- a/tasks/migrations/0009_auto_20210301_1626.py +++ b/tasks/migrations/0009_auto_20210301_1626.py @@ -5,15 +5,22 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0008_auto_20200428_1337'), + ("tasks", "0008_auto_20200428_1337"), ] operations = [ migrations.AlterField( - model_name='session', - name='tasks_number', - field=models.PositiveIntegerField(help_text='Wanneer u bijvoorbeeld eerst de deelnemer observeert en de deelnemer vervolgens een vragenlijst afneemt, dan vult u hierboven "2" in. Electrodes plakken, sessie-debriefing en kort (< 3 minuten) exit-interview gelden niet als een taak.', null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Hoeveel taken worden er binnen deze sessie bij de deelnemer afgenomen?'), + model_name="session", + name="tasks_number", + field=models.PositiveIntegerField( + help_text='Wanneer u bijvoorbeeld eerst de deelnemer observeert en de deelnemer vervolgens een vragenlijst afneemt, dan vult u hierboven "2" in. Electrodes plakken, sessie-debriefing en kort (< 3 minuten) exit-interview gelden niet als een taak.', + null=True, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100), + ], + verbose_name="Hoeveel taken worden er binnen deze sessie bij de deelnemer afgenomen?", + ), ), ] diff --git a/tasks/migrations/0010_auto_20211213_1503.py b/tasks/migrations/0010_auto_20211213_1503.py index 39d558e5b..e5d9b8da1 100644 --- a/tasks/migrations/0010_auto_20211213_1503.py +++ b/tasks/migrations/0010_auto_20211213_1503.py @@ -5,30 +5,48 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0009_auto_20210301_1626'), + ("tasks", "0009_auto_20210301_1626"), ] operations = [ migrations.AlterField( - model_name='session', - name='tasks_duration', - field=models.PositiveIntegerField(blank=True, null=True, verbose_name='De totale geschatte netto taakduur van je sessie komt op basis van je opgave per taak uit op %d minuten. Hoe lang duurt de totale sessie, inclusief ontvangst, instructies per taak, pauzes tussen taken, en debriefing? (bij labbezoek dus van binnenkomst tot vertrek)'), + model_name="session", + name="tasks_duration", + field=models.PositiveIntegerField( + blank=True, + null=True, + verbose_name="De totale geschatte netto taakduur van je sessie komt op basis van je opgave per taak uit op %d minuten. Hoe lang duurt de totale sessie, inclusief ontvangst, instructies per taak, pauzes tussen taken, en debriefing? (bij labbezoek dus van binnenkomst tot vertrek)", + ), ), migrations.AlterField( - model_name='session', - name='tasks_number', - field=models.PositiveIntegerField(help_text='Wanneer je bijvoorbeeld eerst de deelnemer observeert en de deelnemer vervolgens een vragenlijst afneemt, dan vul je hierboven "2" in. Electrodes plakken, sessie-debriefing en kort (< 3 minuten) exit-interview gelden niet als een taak.', null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Hoeveel taken worden er binnen deze sessie bij de deelnemer afgenomen?'), + model_name="session", + name="tasks_number", + field=models.PositiveIntegerField( + help_text='Wanneer je bijvoorbeeld eerst de deelnemer observeert en de deelnemer vervolgens een vragenlijst afneemt, dan vul je hierboven "2" in. Electrodes plakken, sessie-debriefing en kort (< 3 minuten) exit-interview gelden niet als een taak.', + null=True, + validators=[ + django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100), + ], + verbose_name="Hoeveel taken worden er binnen deze sessie bij de deelnemer afgenomen?", + ), ), migrations.AlterField( - model_name='task', - name='description', - field=models.TextField(blank=True, verbose_name='Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort uit hoe deze taak (en de eventuele manipulaties daarbinnen) aan de beantwoording van jouw onderzoeksvragen bijdraagt. Geef, kort, een paar voorbeelden (of beschrijvingen) van het type stimuli dat je van plan bent aan de deelnemer aan te bieden. Het moet voor de commissieleden duidelijk zijn wat je precies gaat doen.'), + model_name="task", + name="description", + field=models.TextField( + blank=True, + verbose_name="Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort uit hoe deze taak (en de eventuele manipulaties daarbinnen) aan de beantwoording van jouw onderzoeksvragen bijdraagt. Geef, kort, een paar voorbeelden (of beschrijvingen) van het type stimuli dat je van plan bent aan de deelnemer aan te bieden. Het moet voor de commissieleden duidelijk zijn wat je precies gaat doen.", + ), ), migrations.AlterField( - model_name='task', - name='feedback', - field=models.BooleanField(blank=True, null=True, verbose_name='Krijgt de deelnemer tijdens of na deze taak feedback op hun gedrag of toestand?'), + model_name="task", + name="feedback", + field=models.BooleanField( + blank=True, + null=True, + verbose_name="Krijgt de deelnemer tijdens of na deze taak feedback op hun gedrag of toestand?", + ), ), ] diff --git a/tasks/migrations/0011_alter_task_registrations.py b/tasks/migrations/0011_alter_task_registrations.py index 0248812e4..2262f2527 100644 --- a/tasks/migrations/0011_alter_task_registrations.py +++ b/tasks/migrations/0011_alter_task_registrations.py @@ -4,15 +4,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0010_auto_20211213_1503'), + ("tasks", "0010_auto_20211213_1503"), ] operations = [ migrations.AlterField( - model_name='task', - name='registrations', - field=models.ManyToManyField(help_text='Help!', to='tasks.Registration', verbose_name='Hoe wordt het gedrag of de toestand van de deelnemer bij deze taak vastgelegd?'), + model_name="task", + name="registrations", + field=models.ManyToManyField( + help_text="Help!", + to="tasks.Registration", + verbose_name="Hoe wordt het gedrag of de toestand van de deelnemer bij deze taak vastgelegd?", + ), ), ] diff --git a/tasks/migrations/0012_alter_task_registrations.py b/tasks/migrations/0012_alter_task_registrations.py index f08b9fcf7..5ad7e4174 100644 --- a/tasks/migrations/0012_alter_task_registrations.py +++ b/tasks/migrations/0012_alter_task_registrations.py @@ -4,15 +4,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('tasks', '0011_alter_task_registrations'), + ("tasks", "0011_alter_task_registrations"), ] operations = [ migrations.AlterField( - model_name='task', - name='registrations', - field=models.ManyToManyField(help_text="Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het gebruik van de term ‘anoniem’ of ‘geanonimiseerd’ in je documenten voor deelnemers. Voor meer informatie, zie de Richtlijnen voor geïnformeerde toestemming, ‘Beeld en geluid’.", to='tasks.Registration', verbose_name='Hoe wordt het gedrag of de toestand van de deelnemer bij deze taak vastgelegd?'), + model_name="task", + name="registrations", + field=models.ManyToManyField( + help_text="Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het gebruik van de term ‘anoniem’ of ‘geanonimiseerd’ in je documenten voor deelnemers. Voor meer informatie, zie de Richtlijnen voor geïnformeerde toestemming, ‘Beeld en geluid’.", + to="tasks.Registration", + verbose_name="Hoe wordt het gedrag of de toestand van de deelnemer bij deze taak vastgelegd?", + ), ), ] diff --git a/tasks/models.py b/tasks/models.py index b616d0bfe..cc4297b1f 100644 --- a/tasks/models.py +++ b/tasks/models.py @@ -11,21 +11,28 @@ class Session(SettingModel): # Fields with respect to Tasks tasks_number = models.PositiveIntegerField( - _('Hoeveel taken worden er binnen deze sessie bij de deelnemer afgenomen?'), + _("Hoeveel taken worden er binnen deze sessie bij de deelnemer afgenomen?"), null=True, - validators=[MinValueValidator(1), MaxValueValidator(100)], # Max of 100 is a technical safeguard - help_text=_('Wanneer je bijvoorbeeld eerst de deelnemer observeert \ + validators=[ + MinValueValidator(1), + MaxValueValidator(100), + ], # Max of 100 is a technical safeguard + help_text=_( + 'Wanneer je bijvoorbeeld eerst de deelnemer observeert \ en de deelnemer vervolgens een vragenlijst afneemt, dan vul je hierboven "2" ' - 'in. Electrodes plakken, sessie-debriefing en kort ' - '(< 3 minuten) exit-interview gelden niet als een taak.') + "in. Electrodes plakken, sessie-debriefing en kort " + "(< 3 minuten) exit-interview gelden niet als een taak." + ), ) tasks_duration = models.PositiveIntegerField( - _('De totale geschatte netto taakduur van je sessie komt \ + _( + "De totale geschatte netto taakduur van je sessie komt \ op basis van je opgave per taak uit op %d minuten. \ Hoe lang duurt de totale sessie, inclusief ontvangst, \ instructies per taak, pauzes tussen taken, en debriefing? \ -(bij labbezoek dus van binnenkomst tot vertrek)'), +(bij labbezoek dus van binnenkomst tot vertrek)" + ), null=True, blank=True, ) @@ -34,24 +41,21 @@ class Session(SettingModel): study = models.ForeignKey(Study, on_delete=models.CASCADE) class Meta: - ordering = ['order'] - unique_together = ('study', 'order') + ordering = ["order"] + unique_together = ("study", "order") def net_duration(self): - if duration := self.task_set.aggregate(models.Sum('duration'))[ - 'duration__sum' - ]: + if duration := self.task_set.aggregate(models.Sum("duration"))["duration__sum"]: return duration return 0 - def first_task(self): - tasks = self.task_set.order_by('order') + tasks = self.task_set.order_by("order") return tasks[0] if tasks else None def last_task(self): - tasks = self.task_set.order_by('-order') + tasks = self.task_set.order_by("-order") return tasks[0] if tasks else None def current_task(self): @@ -81,7 +85,7 @@ def is_completed(self): return result def __str__(self): - return _('Sessie {}').format(self.order) + return _("Sessie {}").format(self.order) class Registration(models.Model): @@ -94,8 +98,8 @@ class Registration(models.Model): age_min = models.PositiveIntegerField(blank=True, null=True) class Meta: - ordering = ['order'] - verbose_name = _('Vastlegging gedrag') + ordering = ["order"] + verbose_name = _("Vastlegging gedrag") def __str__(self): return self.description @@ -109,7 +113,7 @@ class RegistrationKind(models.Model): registration = models.ForeignKey(Registration, on_delete=models.CASCADE) class Meta: - ordering = ['order'] + ordering = ["order"] def __str__(self): return self.description @@ -118,27 +122,31 @@ def __str__(self): class Task(models.Model): order = models.PositiveIntegerField() name = models.CharField( - _('Wat is de naam van de taak?'), + _("Wat is de naam van de taak?"), max_length=200, blank=True, ) description = models.TextField( - _('Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort \ + _( + "Beschrijf de taak die de deelnemer moet uitvoeren, en leg kort \ uit hoe deze taak (en de eventuele manipulaties daarbinnen) aan de \ beantwoording van jouw onderzoeksvragen bijdraagt. \ Geef, kort, een paar voorbeelden (of beschrijvingen) van het type stimuli \ dat je van plan bent aan de deelnemer aan te bieden. \ -Het moet voor de commissieleden duidelijk zijn wat je precies gaat doen.'), +Het moet voor de commissieleden duidelijk zijn wat je precies gaat doen." + ), blank=True, ) duration = models.PositiveIntegerField( - _('Wat is de duur van deze taak van begin tot eind in minuten, \ + _( + "Wat is de duur van deze taak van begin tot eind in minuten, \ dus vanaf het moment dat de taak van start gaat tot en met het einde van de taak \ (exclusief instructie maar inclusief oefensessie)? \ Indien de taakduur per deelnemer varieert (self-paced taak of task-to-criterion), \ -geef dan het redelijkerwijs te verwachten maximum op.'), +geef dan het redelijkerwijs te verwachten maximum op." + ), default=0, validators=[MinValueValidator(1)], blank=True, @@ -146,40 +154,46 @@ class Task(models.Model): registrations = models.ManyToManyField( Registration, - verbose_name=_('Hoe wordt het gedrag of de toestand van de deelnemer bij deze taak vastgelegd?'), - help_text = _("Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het gebruik van de term \ + verbose_name=_( + "Hoe wordt het gedrag of de toestand van de deelnemer bij deze taak vastgelegd?" + ), + help_text=_( + "Opnames zijn nooit anoniem en niet te anonimiseren. Let hierop bij het gebruik van de term \ ‘anoniem’ of ‘geanonimiseerd’ in je documenten voor deelnemers. Voor meer informatie, zie de \ \ - Richtlijnen voor geïnformeerde toestemming, ‘Beeld en geluid’.") + Richtlijnen voor geïnformeerde toestemming, ‘Beeld en geluid’." + ), ) registrations_details = models.CharField( - _('Namelijk'), + _("Namelijk"), max_length=200, blank=True, ) registration_kinds = models.ManyToManyField( RegistrationKind, - verbose_name=_('Kies het soort meting'), + verbose_name=_("Kies het soort meting"), blank=True, ) registration_kinds_details = models.CharField( - _('Namelijk'), + _("Namelijk"), max_length=200, blank=True, ) feedback = models.BooleanField( - _('Krijgt de deelnemer tijdens of na deze taak feedback op hun ' - 'gedrag of toestand?'), + _( + "Krijgt de deelnemer tijdens of na deze taak feedback op hun " + "gedrag of toestand?" + ), null=True, blank=True, ) feedback_details = models.TextField( - _('Beschrijf hoe de feedback wordt gegeven.'), + _("Beschrijf hoe de feedback wordt gegeven."), blank=True, ) @@ -187,11 +201,11 @@ class Task(models.Model): session = models.ForeignKey(Session, on_delete=models.CASCADE) class Meta: - ordering = ['order'] - unique_together = ('session', 'order') + ordering = ["order"] + unique_together = ("session", "order") def is_completed(self): - return self.name != '' + return self.name != "" def delete(self, *args, **kwargs): """ @@ -203,4 +217,4 @@ def delete(self, *args, **kwargs): session.save() def __str__(self): - return _('Taak {} in sessie {}').format(self.order, self.session.order) + return _("Taak {} in sessie {}").format(self.order, self.session.order) diff --git a/tasks/templates/tasks/session_confirm_delete.html b/tasks/templates/tasks/session_confirm_delete.html index f479ff79f..f5cbacfbd 100644 --- a/tasks/templates/tasks/session_confirm_delete.html +++ b/tasks/templates/tasks/session_confirm_delete.html @@ -6,17 +6,19 @@ {% trans "Sessie verwijderen" %} - {{ block.super }} {% endblock %} - {% block content %}
      -

      - {% trans "Sessie verwijderen" %} -

      -
      {% csrf_token %} -

      Weet u zeker dat u deze sessie {{ session.order }} in de aanvraag {{ session.study.proposal.title }} wilt verwijderen?

      - - {% trans "Annuleren" %} +

      {% trans "Sessie verwijderen" %}

      + + {% csrf_token %} +

      + Weet u zeker dat u deze sessie {{ session.order }} in de aanvraag {{ session.study.proposal.title }} wilt verwijderen? +

      + + {% trans "Annuleren" %}
      diff --git a/tasks/templates/tasks/session_title.html b/tasks/templates/tasks/session_title.html index 2e549d91c..758f841e6 100644 --- a/tasks/templates/tasks/session_title.html +++ b/tasks/templates/tasks/session_title.html @@ -1,23 +1,23 @@ {% load i18n %} {% with order=session.order study_order=session.study.order study_name=session.study.name studies_number=session.study.proposal.studies_number sessions_number=session.study.sessions_number %} -{% if studies_number > 1 and sessions_number > 1 %} -

      - {% blocktrans %} - Traject {{ study_order }} ({{ study_name }}), sessie {{ order }} - {% endblocktrans %} -

      -{% elif studies_number > 1 %} -

      - {% blocktrans %} - Traject {{ study_order }} ({{ study_name }}) - {% endblocktrans %} -

      -{% elif sessions_number >= 1 %} -

      - {% blocktrans %} - Sessie {{ order }} - {% endblocktrans %} -

      -{% endif %} + {% if studies_number > 1 and sessions_number > 1 %} +

      + {% blocktrans trimmed %} + Traject {{ study_order }} ({{ study_name }}), sessie {{ order }} + {% endblocktrans %} +

      + {% elif studies_number > 1 %} +

      + {% blocktrans trimmed %} + Traject {{ study_order }} ({{ study_name }}) + {% endblocktrans %} +

      + {% elif sessions_number >= 1 %} +

      + {% blocktrans trimmed %} + Sessie {{ order }} + {% endblocktrans %} +

      + {% endif %} {% endwith %} diff --git a/tasks/templates/tasks/task_confirm_delete.html b/tasks/templates/tasks/task_confirm_delete.html index 17e2e7ae7..70eb88b56 100644 --- a/tasks/templates/tasks/task_confirm_delete.html +++ b/tasks/templates/tasks/task_confirm_delete.html @@ -9,13 +9,16 @@ {% block content %}
      -

      - {% trans "Taak verwijderen" %} -

      -
      {% csrf_token %} -

      Weet u zeker dat u de taak {{ task.name }} uit sessie {{ task.session.order }} in de aanvraag {{ task.session.study.proposal.title }} wilt verwijderen?

      - - {% trans "Annuleren" %} +

      {% trans "Taak verwijderen" %}

      + + {% csrf_token %} +

      + Weet u zeker dat u de taak {{ task.name }} uit sessie {{ task.session.order }} in de aanvraag {{ task.session.study.proposal.title }} wilt verwijderen? +

      + + {% trans "Annuleren" %}
      diff --git a/tasks/templates/tasks/task_end.html b/tasks/templates/tasks/task_end.html index ae76ec69b..8c2d8fa00 100644 --- a/tasks/templates/tasks/task_end.html +++ b/tasks/templates/tasks/task_end.html @@ -7,16 +7,13 @@ {% trans "Overzicht van het takenonderzoek" %} - {{ block.super }} {% endblock %} - {% block content %}
      {% with nav_items=session.study.proposal.available_urls active=3 %} {% include 'base/navigation.html' %} {% endwith %} -

      - {% trans "Overzicht van het takenonderzoek" %} -

      +

      {% trans "Overzicht van het takenonderzoek" %}

      {% include "tasks/session_title.html" %}

      @@ -25,13 +22,15 @@

      {% include "tasks/task_list.html" %}

      {% trans "Beantwoord op basis van dit overzicht de volgende vragen:" %}

      -
      {% csrf_token %} - {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      {% with proposal=session.study.proposal study=session.study %} - {% include "base/form_buttons.html" %} + {% include "base/form_buttons.html" %} {% endwith %}
      - {% endblock %} diff --git a/tasks/templates/tasks/task_form.html b/tasks/templates/tasks/task_form.html index ccb16265d..53fce3fee 100644 --- a/tasks/templates/tasks/task_form.html +++ b/tasks/templates/tasks/task_form.html @@ -8,32 +8,31 @@ {% endblock %} {% block html_head %} - + {% endblock %} - {% block content %}
      {% with nav_items=task.session.study.proposal.available_urls active=3 %} {% include 'base/navigation.html' %} {% endwith %} - -

      - {% trans "Het takenonderzoek en interviews" %} -

      +

      {% trans "Het takenonderzoek en interviews" %}

      {% include "tasks/task_title.html" %} -
      {% csrf_token %} - {{ form.as_table }}
      + + {% csrf_token %} + + {{ form.as_table }} +
      {% with proposal=task.session.study.proposal study=task.session.study session=task.session %} - {% include "base/form_buttons.html" %} + {% include "base/form_buttons.html" %} {% endwith %}
      diff --git a/tasks/templates/tasks/task_list.html b/tasks/templates/tasks/task_list.html index 73137d60d..63fa4cb79 100644 --- a/tasks/templates/tasks/task_list.html +++ b/tasks/templates/tasks/task_list.html @@ -13,27 +13,30 @@ {% for task in session.task_set.all %} - - {{ task.name }} - {{ task.duration }} - {{ task.registrations.all|unordered_list }} - - {{ task.feedback|yesno:_("ja,nee") }} - {% if task.feedback %} - {{ task.feedback_details }} - {% endif %} - - - - {% if session.tasks_number > 1 %} - - {% endif %} - - + + {{ task.name }} + {{ task.duration }} + {{ task.registrations.all|unordered_list }} + + {{ task.feedback|yesno:_("ja,nee") }} + {% if task.feedback %}{{ task.feedback_details }}{% endif %} + + + + + + {% if session.tasks_number > 1 %} + + + + {% endif %} + + {% endfor %} - + {% endblock %} {% block content %} @@ -24,21 +24,19 @@ {% with nav_items=session.study.proposal.available_urls active=3 %} {% include 'base/navigation.html' %} {% endwith %} -

      - {% trans "Het takenonderzoek en interviews" %} -

      +

      {% trans "Het takenonderzoek en interviews" %}

      {% include "main/setting_checks.html" %} {% include "tasks/session_title.html" %} -
      {% csrf_token %} - {{ form.as_table }}
      -

      - {% trans "Voor elke taak stellen we in de komende schermen steeds dezelfde vragen." %} -

      + + {% csrf_token %} + + {{ form.as_table }} +
      +

      {% trans "Voor elke taak stellen we in de komende schermen steeds dezelfde vragen." %}

      {% with proposal=session.study.proposal study=session.study %} - {% include "base/form_buttons.html" %} + {% include "base/form_buttons.html" %} {% endwith %}
      - {% endblock %} diff --git a/tasks/templates/tasks/task_title.html b/tasks/templates/tasks/task_title.html index 51f26d6f3..7a0352a8d 100644 --- a/tasks/templates/tasks/task_title.html +++ b/tasks/templates/tasks/task_title.html @@ -1,17 +1,17 @@ {% load i18n %} {% with order=task.order session_order=task.session.order study_order=task.session.study.order study_name=task.session.study.name studies_number=task.session.study.proposal.studies_number %} -{% if studies_number > 1 %} -

      - {% blocktrans %} - Traject {{ study_order }} ({{ study_name }}), sessie {{ session_order }}, taak {{ order }} - {% endblocktrans %} -

      -{% else %} -

      - {% blocktrans %} - Sessie {{ session_order }}, taak {{ order }} - {% endblocktrans %} -

      -{% endif %} + {% if studies_number > 1 %} +

      + {% blocktrans trimmed %} + Traject {{ study_order }} ({{ study_name }}), sessie {{ session_order }}, taak {{ order }} + {% endblocktrans %} +

      + {% else %} +

      + {% blocktrans trimmed %} + Sessie {{ session_order }}, taak {{ order }} + {% endblocktrans %} +

      + {% endif %} {% endwith %} diff --git a/tasks/translation.py b/tasks/translation.py index e8de002d9..447307d08 100644 --- a/tasks/translation.py +++ b/tasks/translation.py @@ -5,9 +5,9 @@ @register(Registration) class RegistrationTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) @register(RegistrationKind) class RegistrationKindTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ("description",) diff --git a/tasks/urls.py b/tasks/urls.py index 3816c065a..739b0320e 100644 --- a/tasks/urls.py +++ b/tasks/urls.py @@ -3,15 +3,14 @@ from .views.session_views import TaskStart, TaskEnd, SessionDelete from .views.task_views import TaskUpdate, TaskDelete -app_name = 'tasks' +app_name = "tasks" urlpatterns = [ # Session(s) - path('session/delete//', SessionDelete.as_view(), name='session_delete'), - path('start//', TaskStart.as_view(), name='start'), - path('end//', TaskEnd.as_view(), name='end'), - + path("session/delete//", SessionDelete.as_view(), name="session_delete"), + path("start//", TaskStart.as_view(), name="start"), + path("end//", TaskEnd.as_view(), name="end"), # Task(s) - path('update//', TaskUpdate.as_view(), name='update'), - path('delete//', TaskDelete.as_view(), name='delete'), + path("update//", TaskUpdate.as_view(), name="update"), + path("delete//", TaskDelete.as_view(), name="delete"), ] diff --git a/tasks/utils.py b/tasks/utils.py index 74758e473..3742292fa 100644 --- a/tasks/utils.py +++ b/tasks/utils.py @@ -12,9 +12,10 @@ def get_session_progress(session, is_end=False): from studies.utils import get_study_progress + progress = SESSION_PROGRESS_TOTAL / session.study.sessions_number if not is_end: - progress *= (session.order - 1) + progress *= session.order - 1 else: progress *= session.order return int(get_study_progress(session.study) + SESSION_PROGRESS_START + progress) @@ -24,29 +25,36 @@ def get_task_progress(task): session = task.session session_progress = get_session_progress(session) task_progress = task.order / session.tasks_number - return int(session_progress + (SESSION_PROGRESS_TOTAL / session.study.sessions_number) * task_progress - SESSION_PROGRESS_EPSILON) + return int( + session_progress + + (SESSION_PROGRESS_TOTAL / session.study.sessions_number) * task_progress + - SESSION_PROGRESS_EPSILON + ) def session_urls(study): - - tasks_url = AvailableURL(title=_('Takenonderzoek')) + tasks_url = AvailableURL(title=_("Takenonderzoek")) if study.has_sessions: - tasks_url.url = reverse('studies:session_start', args=(study.pk,)) + tasks_url.url = reverse("studies:session_start", args=(study.pk,)) if study.has_sessions: prev_session_completed = True for session in study.session_set.all(): - task_start_url = AvailableURL(title=_('Het takenonderzoek: sessie {}').format(session.order)) + task_start_url = AvailableURL( + title=_("Het takenonderzoek: sessie {}").format(session.order) + ) if prev_session_completed: - task_start_url.url = reverse('tasks:start', args=(session.pk,)) + task_start_url.url = reverse("tasks:start", args=(session.pk,)) tasks_url.children.append(task_start_url) tasks_url.children.extend(tasks_urls(session)) - task_end_url = AvailableURL(title=_('Overzicht van takenonderzoek: sessie {}').format(session.order)) + task_end_url = AvailableURL( + title=_("Overzicht van takenonderzoek: sessie {}").format(session.order) + ) if session.tasks_completed(): - task_end_url.url = reverse('tasks:end', args=(session.pk,)) + task_end_url.url = reverse("tasks:end", args=(session.pk,)) tasks_url.children.append(task_end_url) prev_session_completed = session.is_completed() @@ -59,9 +67,13 @@ def tasks_urls(session): prev_task_completed = True for task in session.task_set.all(): - task_url = AvailableURL(title=_('Het takenonderzoek: sessie {} taak {}').format(session.order, task.order)) + task_url = AvailableURL( + title=_("Het takenonderzoek: sessie {} taak {}").format( + session.order, task.order + ) + ) if prev_task_completed: - task_url.url = reverse('tasks:update', args=(task.pk,)) + task_url.url = reverse("tasks:update", args=(task.pk,)) result.append(task_url) prev_task_completed = task.is_completed() @@ -78,9 +90,7 @@ def copy_task_to_session(session, original_task): t.save() t.registrations.set(original_task.registrations.all()) - t.registration_kinds.set( - original_task.registration_kinds.all() - ) + t.registration_kinds.set(original_task.registration_kinds.all()) t.save() diff --git a/tasks/views/session_views.py b/tasks/views/session_views.py index d07ae197a..dd079898b 100644 --- a/tasks/views/session_views.py +++ b/tasks/views/session_views.py @@ -16,10 +16,10 @@ ###################### class SessionDelete(DeletionAllowedMixin, DeleteView): model = Session - success_message = _('Sessie verwijderd') + success_message = _("Sessie verwijderd") def get_success_url(self): - return reverse('studies:design_end', args=(self.object.study.pk,)) + return reverse("studies:design_end", args=(self.object.study.pk,)) def delete(self, request, *args, **kwargs): """ @@ -49,25 +49,26 @@ def delete(self, request, *args, **kwargs): ################## class TaskStart(AllowErrorsOnBackbuttonMixin, UpdateView): """Initial creation of Tasks for a Session""" + model = Session form_class = TaskStartForm - template_name = 'tasks/task_start.html' - success_message = _('%(tasks_number)s ta(a)k(en) aangemaakt') + template_name = "tasks/task_start.html" + success_message = _("%(tasks_number)s ta(a)k(en) aangemaakt") def get_form_kwargs(self): """Sets the Study as a form kwarg""" kwargs = super(TaskStart, self).get_form_kwargs() - kwargs['study'] = self.object.study + kwargs["study"] = self.object.study return kwargs def get_context_data(self, **kwargs): context = super(TaskStart, self).get_context_data(**kwargs) - context['progress'] = get_session_progress(self.object) + context["progress"] = get_session_progress(self.object) return context def form_valid(self, form): """Copies, creates or deletes Tasks on save""" - if 'is_copy' in form.cleaned_data and form.cleaned_data['is_copy']: + if "is_copy" in form.cleaned_data and form.cleaned_data["is_copy"]: session = form.instance # Delete all existing Tasks @@ -75,19 +76,19 @@ def form_valid(self, form): task.delete() # Copy fields from the parent Session - s = form.cleaned_data['parent_session'] + s = form.cleaned_data["parent_session"] session.tasks_number = s.tasks_number session.tasks_duration = s.tasks_duration session.save() # Update cleaned_data as well, to make sure this isn't overridden on the super call below - form.cleaned_data['tasks_number'] = s.tasks_number + form.cleaned_data["tasks_number"] = s.tasks_number # Copy Tasks from the parent Session for task in s.task_set.all(): copy_task_to_session(session, task) else: - nr_tasks = form.cleaned_data['tasks_number'] + nr_tasks = form.cleaned_data["tasks_number"] session = form.instance current = session.task_set.count() or 0 @@ -111,34 +112,37 @@ def form_valid(self, form): return super(TaskStart, self).form_valid(form) def get_next_url(self): - return reverse('tasks:update', args=(self.object.first_task().pk,)) + return reverse("tasks:update", args=(self.object.first_task().pk,)) def get_back_url(self): try: # Try to return to task_end of the previous Session - prev_session = Session.objects.get(study=self.object.study, order=self.object.order - 1) - return reverse('tasks:end', args=(prev_session.pk,)) + prev_session = Session.objects.get( + study=self.object.study, order=self.object.order - 1 + ) + return reverse("tasks:end", args=(prev_session.pk,)) except Session.DoesNotExist: # If this is the first Session, return to session_start - return reverse('studies:session_start', args=(self.object.study.pk,)) + return reverse("studies:session_start", args=(self.object.study.pk,)) class TaskEnd(AllowErrorsOnBackbuttonMixin, UpdateView): """Completes a Session""" + model = Session form_class = TaskEndForm - template_name = 'tasks/task_end.html' - success_message = _(u'Taken toevoegen beëindigd') + template_name = "tasks/task_end.html" + success_message = _("Taken toevoegen beëindigd") def get_context_data(self, **kwargs): context = super(TaskEnd, self).get_context_data(**kwargs) - context['progress'] = get_session_progress(self.object, True) + context["progress"] = get_session_progress(self.object, True) return context def get_form_kwargs(self): kwargs = super().get_form_kwargs() - referrer = self.request.META.get('HTTP_REFERRER') + referrer = self.request.META.get("HTTP_REFERRER") if referrer: pass @@ -147,11 +151,13 @@ def get_form_kwargs(self): def get_next_url(self): try: # Try to continue to next Session - next_session = Session.objects.get(study=self.object.study, order=self.object.order + 1) - return reverse('tasks:start', args=(next_session.pk,)) + next_session = Session.objects.get( + study=self.object.study, order=self.object.order + 1 + ) + return reverse("tasks:start", args=(next_session.pk,)) except Session.DoesNotExist: # If this is the last Session, continue to design_end - return reverse('studies:design_end', args=(self.object.study.pk,)) + return reverse("studies:design_end", args=(self.object.study.pk,)) def get_back_url(self): - return reverse('tasks:update', args=(self.object.last_task().pk,)) + return reverse("tasks:update", args=(self.object.last_task().pk,)) diff --git a/tasks/views/task_views.py b/tasks/views/task_views.py index 97f5add5a..3ed3975ef 100644 --- a/tasks/views/task_views.py +++ b/tasks/views/task_views.py @@ -16,41 +16,47 @@ ###################### class TaskUpdate(AllowErrorsOnBackbuttonMixin, UpdateView): """Updates a Task""" + model = Task form_class = TaskForm - success_message = _('Taak bewerkt') + success_message = _("Taak bewerkt") def get_context_data(self, **kwargs): context = super(TaskUpdate, self).get_context_data(**kwargs) - context['progress'] = get_task_progress(self.object) + context["progress"] = get_task_progress(self.object) return context def get_next_url(self): try: # Try to continue to next Task - next_task = Task.objects.get(session=self.object.session, order=self.object.order + 1) - return reverse('tasks:update', args=(next_task.pk,)) + next_task = Task.objects.get( + session=self.object.session, order=self.object.order + 1 + ) + return reverse("tasks:update", args=(next_task.pk,)) except Task.DoesNotExist: # If this is the last Task, continue to task_end - return reverse('tasks:end', args=(self.object.session.pk,)) + return reverse("tasks:end", args=(self.object.session.pk,)) def get_back_url(self): try: # Try to return to previous Task - prev_task = Task.objects.get(session=self.object.session, order=self.object.order - 1) - return reverse('tasks:update', args=(prev_task.pk,)) + prev_task = Task.objects.get( + session=self.object.session, order=self.object.order - 1 + ) + return reverse("tasks:update", args=(prev_task.pk,)) except Task.DoesNotExist: # If this is the first Task, return to task_start - return reverse('tasks:start', args=(self.object.session.pk,)) + return reverse("tasks:start", args=(self.object.session.pk,)) class TaskDelete(DeletionAllowedMixin, DeleteView): """Deletes a Task""" + model = Task - success_message = _('Taak verwijderd') + success_message = _("Taak verwijderd") def get_success_url(self): - return reverse('tasks:end', args=(self.object.session.pk,)) + return reverse("tasks:end", args=(self.object.session.pk,)) def delete(self, request, *args, **kwargs): """