diff --git a/fetc/constants.py b/fetc/constants.py new file mode 100644 index 000000000..a35827f82 --- /dev/null +++ b/fetc/constants.py @@ -0,0 +1,12 @@ +# A list of constants imported into settings.py +# 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' + +# Route durations +PREASSESSMENT_ROUTE_WEEKS = 1 +SHORT_ROUTE_WEEKS = 2 diff --git a/fetc/saml_settings.example.py b/fetc/saml_settings.example.py index ebf1ac262..bae4171da 100644 --- a/fetc/saml_settings.example.py +++ b/fetc/saml_settings.example.py @@ -36,8 +36,7 @@ 'mail': ('email',), 'givenName': ('first_name',), 'uuPrefixedSn': ('last_name',), - # TODO: create an attribute on the user model to store this value - # 'uuLegacyDepartment': (), + 'uuLegacyDepartment': ('process_faculties', ), } # Controls which mechanism is used to exchange SAML data with the IdP diff --git a/fetc/settings.py b/fetc/settings.py index af8a1f782..45697d112 100644 --- a/fetc/settings.py +++ b/fetc/settings.py @@ -11,6 +11,7 @@ """ import os +from django.core.exceptions import ImproperlyConfigured from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ @@ -162,22 +163,17 @@ MENU_SELECT_PARENTS = True MENU_HIDE_EMPTY = False -# Group names -GROUP_SECRETARY = 'Secretaris' -GROUP_PRIMARY_SECRETARY = 'Primaire secretaris' -GROUP_LINGUISTICS_CHAMBER = 'LK' -GROUP_GENERAL_CHAMBER = 'AK' - -# Route durations -PREASSESSMENT_ROUTE_WEEKS = 1 -SHORT_ROUTE_WEEKS = 2 - # Base URL BASE_URL = '127.0.0.1:8000' # CSRF Setting CSRF_FAILURE_VIEW = 'main.error_views.csrf_failure' +try: + from .constants import * +except ImportError: + raise ImproperlyConfigured("constants.py is missing!") + try: from .ldap_settings import * except ImportError: @@ -193,5 +189,8 @@ LOGIN_URL = reverse_lazy('saml-login') SHOW_SAML_LOGIN = True + # Custom proxy model for SAML attribute processing + SAML_USER_MODEL = 'main.SamlUserProxy' + except ImportError: print('Proceeding without SAML settings') diff --git a/fetc/urls.py b/fetc/urls.py index f3050cd94..09b9285ed 100644 --- a/fetc/urls.py +++ b/fetc/urls.py @@ -55,7 +55,7 @@ # If SAML is enabled, add the required URL patterns for SAML if 'cdh.federated_auth' in settings.INSTALLED_APPS: - from djangosaml2.views import LoginView + from djangosaml2.views import EchoAttributesView, LoginView from cdh.federated_auth.saml.views import LogoutInitView urlpatterns.extend([ @@ -65,6 +65,15 @@ path('saml/logout/', LogoutInitView.as_view(), name='logout'), path('saml/', include('djangosaml2.urls')), ]) + + if settings.DEBUG: + urlpatterns.append( + path( + 'saml/echo_attributes/', + EchoAttributesView.as_view(), + name='saml-attributes' + ) + ) else: # If not, append the default logout-view urlpatterns.append( diff --git a/locale/en/LC_MESSAGES/django.mo b/locale/en/LC_MESSAGES/django.mo index 0d7f6c558..e2ce9e52c 100644 Binary files a/locale/en/LC_MESSAGES/django.mo and b/locale/en/LC_MESSAGES/django.mo differ diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index c5df1cabd..b1b412cf1 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-08-22 12:34+0200\n" +"POT-Creation-Date: 2023-10-05 17:20+0200\n" "PO-Revision-Date: 2020-10-07 11:22+0200\n" "Last-Translator: Anna Asbury \n" "Language-Team: \n" @@ -62,7 +62,7 @@ msgstr "" "X-Generator: Poedit 2.4.1\n" #: faqs/menus.py:7 main/templates/base/menu.html:125 -#: main/templates/main/index.html:169 +#: main/templates/main/index.html:201 msgid "FETC-GW website" msgstr "FEtC-H website" @@ -74,13 +74,13 @@ 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:172 +#: faqs/menus.py:13 main/templates/main/index.html:204 #: proposals/templates/proposals/proposal_start_pre_approved.html:14 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:177 +#: main/templates/main/index.html:209 #: proposals/templates/proposals/proposal_pdf.html:430 #: proposals/templates/proposals/study_consent.html:8 #: proposals/templates/proposals/translated_consent_forms.html:7 @@ -152,7 +152,7 @@ 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:280 +#: 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 @@ -201,11 +201,11 @@ msgstr "" msgid "Feedback verstuurd" msgstr "Feedback sent" -#: fetc/settings.py:122 +#: fetc/settings.py:133 msgid "Nederlands" msgstr "Dutch" -#: fetc/settings.py:123 +#: fetc/settings.py:134 msgid "Engels" msgstr "English" @@ -289,7 +289,7 @@ msgid "Het interventieonderzoek" msgstr "Intervention study" #: interventions/templates/interventions/intervention_form.html:17 -#: main/models.py:55 +#: 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 @@ -331,43 +331,43 @@ msgstr "Intervention saved" msgid "Dit veld is verplicht." msgstr "This field is required." -#: main/menus.py:5 main/templates/base/menu.html:7 -#: main/templates/main/index.html:7 main/templates/main/index.html:24 +#: main/menus.py:6 main/templates/base/menu.html:7 +#: main/templates/main/index.html:7 main/templates/main/index.html:56 #: main/templates/main/landing.html:34 msgid "Startpagina" msgstr "Start page" -#: main/menus.py:10 +#: main/menus.py:11 msgid "Log in" msgstr "Log in" -#: main/menus.py:15 main/templates/base/login_header.html:7 +#: main/menus.py:16 main/templates/base/login_header.html:7 msgid "Log uit" msgstr "Log out" -#: main/models.py:8 main/utils.py:13 +#: main/models.py:10 main/utils.py:13 msgid "ja" msgstr "yes" -#: main/models.py:9 main/utils.py:13 +#: main/models.py:11 main/utils.py:13 msgid "nee" msgstr "no" -#: main/models.py:10 +#: main/models.py:12 msgid "twijfel" msgstr "uncertain" -#: main/models.py:64 +#: main/models.py:66 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:253 +#: main/models.py:70 observations/models.py:129 proposals/models.py:255 #: studies/models.py:208 studies/models.py:244 tasks/models.py:157 #: tasks/models.py:169 msgid "Namelijk" msgstr "Please specify" -#: main/models.py:73 +#: main/models.py:75 msgid "" "Vindt het afnemen van de taak plaats onder het toeziend oog van de leraar of " "een ander persoon die bevoegd is?" @@ -375,13 +375,13 @@ msgstr "" "Will the task be conducted under the supervision of the teacher or another " "qualified person?" -#: main/models.py:79 +#: main/models.py:81 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:80 +#: main/models.py:82 msgid "" "Iedereen die op een school werkt moet in het bezit zijn van een " "Verklaring Omtrent Gedrag (VOG, zie portalsupport.gw@uu.nl." +msgstr "" +"If you suspect this is incorrect, please contact support at portalsupport.gw@uu.nl. " + +#: main/templates/main/index.html:64 msgid "" "Formele goedkeuring door één van beide kamers van de FETC-GW (middels een " "formele goedkeuringsbrief) is vereist voor mensgebonden onderzoek binnen de " @@ -852,7 +885,7 @@ msgstr "" "even to recruiting participants. Therefore, always wait for the letter of " "approval before starting research activities." -#: main/templates/main/index.html:39 +#: main/templates/main/index.html:71 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 " @@ -862,7 +895,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:47 +#: main/templates/main/index.html:79 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 " @@ -873,13 +906,13 @@ msgstr "" "email to portalsupport.gw@uu.nl." -#: main/templates/main/index.html:54 +#: main/templates/main/index.html:86 #: proposals/templates/proposals/proposal_start.html:16 #: proposals/templates/proposals/proposal_start_practice.html:18 msgid "Check voor het indienen:" msgstr "Before submitting an application, please consult:" -#: main/templates/main/index.html:57 +#: main/templates/main/index.html:89 #: proposals/templates/proposals/proposal_start.html:19 #: proposals/templates/proposals/proposal_start_practice.html:21 msgid "" @@ -889,7 +922,7 @@ msgstr "" "The UU-" "webpage of the FEtC-H for news and upcoming dates." -#: main/templates/main/index.html:64 +#: main/templates/main/index.html:96 msgid "" "Het reglement van de FETC-GW." @@ -897,7 +930,7 @@ msgstr "" "The regulations of the FEtC-H ." -#: main/templates/main/index.html:70 +#: main/templates/main/index.html:102 msgid "" "Gebruik de juiste (meest recente) model documents for informed consent. (Latest " "version: December 2021)" -#: main/templates/main/index.html:74 +#: main/templates/main/index.html:106 msgid "" "
  • Voor advies over data management (plannen): datamanagement.gw@uu.nl.
  • Voor advies " @@ -926,97 +959,97 @@ msgstr "" "itself: portalsupport.gw@uu.nl." "
  • " -#: main/templates/main/index.html:83 +#: main/templates/main/index.html:115 msgid "In deze portal kan je het volgende doen:" msgstr "In this portal you can do the following:" -#: main/templates/main/index.html:92 +#: main/templates/main/index.html:124 msgid "Dien een nieuwe aanvraag in" msgstr "Submit a new proposal" -#: main/templates/main/index.html:97 +#: main/templates/main/index.html:129 msgid "die volledig nieuw is in deze portal;" msgstr "that is completely new in this portal;" -#: main/templates/main/index.html:100 +#: main/templates/main/index.html:132 msgid "op basis van een kopie van een oude aanvraag;" msgstr "from a copy of an old proposal;" -#: main/templates/main/index.html:103 +#: main/templates/main/index.html:135 msgid "voor (al dan niet goedgekeurde) subsidieaanvragen;" msgstr "to supplement a grant application" -#: main/templates/main/index.html:106 +#: main/templates/main/index.html:138 msgid "die al goedgekeurd is door een andere ethische toetsingscomissie." msgstr "that has been approved by another ethics committee." -#: main/templates/main/index.html:112 +#: main/templates/main/index.html:144 msgid "Een aanvraag reviseren" msgstr "Revise a proposal" -#: main/templates/main/index.html:117 +#: main/templates/main/index.html:149 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:120 +#: main/templates/main/index.html:152 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:128 +#: main/templates/main/index.html:160 msgid "Bekijk" msgstr "View" -#: main/templates/main/index.html:132 +#: main/templates/main/index.html:164 msgid "mijn conceptaanvragen;" msgstr "my draft applications;" -#: main/templates/main/index.html:135 +#: main/templates/main/index.html:167 msgid "mijn oefenaanvragen;" msgstr "my practice applications;" -#: main/templates/main/index.html:138 +#: main/templates/main/index.html:170 msgid "mijn ingediende aanvragen;" msgstr "my submitted applications;" -#: main/templates/main/index.html:141 +#: main/templates/main/index.html:173 msgid "mijn afgehandelde aanvragen;" msgstr "my processed applications;" -#: main/templates/main/index.html:144 +#: main/templates/main/index.html:176 msgid "mijn aanvragen als eindverantwoordelijke;" msgstr "my supervised applications;" -#: main/templates/main/index.html:147 +#: main/templates/main/index.html:179 msgid "al mijn aanvragen." msgstr "all my applications" -#: main/templates/main/index.html:151 +#: main/templates/main/index.html:183 msgid "FETC-GW archief" msgstr "FEtC-H archive" -#: main/templates/main/index.html:155 +#: main/templates/main/index.html:187 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:158 +#: main/templates/main/index.html:190 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:173 +#: main/templates/main/index.html:205 msgid "Reglement van de FETC-GW" msgstr "Regulations of the FEtC-H" -#: main/templates/main/index.html:180 +#: main/templates/main/index.html:212 msgid "Veelgestelde vragen m.b.t. dit portal" msgstr "Frequently asked questions relating to this portal" -#: main/templates/main/index.html:183 +#: main/templates/main/index.html:215 msgid "Feedback op dit portal geven" msgstr "Give feedback on this portal" -#: main/templates/main/index.html:193 +#: main/templates/main/index.html:225 msgid "Bannerfoto door Kim O'leary" msgstr "Cover image by Kim O'leary" @@ -1061,7 +1094,7 @@ 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:91 +#: main/templates/main/landing.html:86 main/templates/main/landing.html:93 msgid "Log in met je Solis-ID" msgstr "Log in with your Solis-ID" @@ -1076,20 +1109,20 @@ msgid "" msgstr "" "Click here to return to the start page." -#: main/templates/registration/login.html:39 +#: main/templates/registration/login.html:23 msgid "" "Gebruikersnaam of wachtwoord incorrect. Probeer het alstublieft opnieuw." msgstr "Username or password incorrect. Please try again." -#: main/templates/registration/login.html:43 +#: main/templates/registration/login.html:27 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:46 +#: main/templates/registration/login.html:30 msgid "Gebruikersnaam" msgstr "Username" -#: main/templates/registration/login.html:47 +#: main/templates/registration/login.html:31 msgid "Wachtwoord" msgstr "Password" @@ -1165,7 +1198,7 @@ msgid "" 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:682 studies/models.py:172 +#: observations/models.py:88 proposals/models.py:745 studies/models.py:172 #: studies/models.py:228 studies/models.py:358 msgid "Licht toe" msgstr "Explain" @@ -1319,7 +1352,7 @@ msgstr "Last edited" msgid "Datum ingediend bij eindverantwoordelijke" msgstr "Date sent to supervisor" -#: proposals/forms.py:42 proposals/models.py:219 +#: proposals/forms.py:42 proposals/models.py:221 msgid "" "Zijn er nog andere onderzoekers bij deze aanvraag betrokken die " "niet geaffilieerd zijn aan een van de onderzoeksinstituten " @@ -1388,11 +1421,11 @@ msgstr "" msgid "Ik maak een oefenaanvraag aan" msgstr "I am creating a practice application" -#: proposals/forms.py:276 proposals/models.py:534 +#: proposals/forms.py:276 proposals/models.py:536 msgid "Te kopiëren aanvraag" msgstr "Application to be copied" -#: proposals/forms.py:278 proposals/models.py:536 +#: proposals/forms.py:278 proposals/models.py:538 msgid "Dit veld toont enkel aanvragen waar je zelf een medeuitvoerende bent." msgstr "This field shows only applications in which you are involved." @@ -1540,49 +1573,49 @@ msgstr "New application" msgid "Bekijk alle goedgekeurde aanvragen van de Algemene Kamer" msgstr "View all approved applications of the General Chamber" -#: proposals/menus.py:94 +#: proposals/menus.py:95 msgid "Bekijk alle goedgekeurde aanvragen van de Linguïstiek Kamer" msgstr "View all approved applications of the Linguistics Chamber" -#: proposals/mixins.py:17 +#: proposals/mixins.py:20 #, python-format msgid "Aanvraag %(title)s bewerkt" msgstr "Application %(title)s edited" -#: proposals/models.py:141 +#: proposals/models.py:143 msgid "Concept" msgstr "Draft" -#: proposals/models.py:144 +#: proposals/models.py:146 msgid "Opgestuurd ter beoordeling door eindverantwoordelijke" msgstr "Sent for assessment by the researcher with final responsibility" -#: proposals/models.py:145 +#: proposals/models.py:147 msgid "Opgestuurd ter beoordeling door FETC-GW" msgstr "Sent for assessment by FEtC-H" -#: proposals/models.py:147 proposals/models.py:148 +#: proposals/models.py:149 proposals/models.py:150 msgid "Aanvraag is beoordeeld door FETC-GW" msgstr "Application has been assessed by FEtC-H" -#: proposals/models.py:154 +#: proposals/models.py:156 msgid "in het kader van een cursus" msgstr "in the context of a course" -#: proposals/models.py:155 +#: proposals/models.py:157 msgid "om de portal te exploreren" msgstr "to explore the portal" # Not actually used in the interface -#: proposals/models.py:167 +#: proposals/models.py:169 msgid "Door welke comissie dient deze aanvraag te worden beoordeeld?" msgstr "Which chamber should be reviewing this application?" -#: proposals/models.py:176 +#: proposals/models.py:178 msgid "Aan welk onderzoeksinstituut ben je verbonden?" msgstr "To which research institute are you affiliated?" -#: proposals/models.py:182 +#: proposals/models.py:184 msgid "" "Wat is de beoogde startdatum van het onderzoek waarvoor deze aanvraag wordt " "ingediend?" @@ -1590,7 +1623,7 @@ msgstr "" "What is the desired starting date of the actual research for which this " "application is being submitted?" -#: proposals/models.py:183 +#: proposals/models.py:185 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 " @@ -1600,7 +1633,7 @@ msgstr "" "has approved it cannot receive formal approval; in such cases, the FEtC-H " "only provides a post-hoc advice." -#: proposals/models.py:192 +#: proposals/models.py:194 msgid "" "Wat is de titel van je aanvraag? Deze titel zal worden gebruikt in alle " "formele correspondentie." @@ -1608,7 +1641,7 @@ msgstr "" "What is the title of your application? This title will be used in all formal " "correspondence." -#: proposals/models.py:197 +#: proposals/models.py:199 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 " @@ -1620,7 +1653,7 @@ msgstr "" "portal. The title cannot be identical to that of a study you have previously " "submitted." -#: proposals/models.py:205 +#: proposals/models.py:207 msgid "" "Geef een duidelijke, bondige beschrijving van de onderzoeksvraag of -vragen. " "Gebruik maximaal 200 woorden." @@ -1628,7 +1661,7 @@ msgstr "" "Give a clear, concise description of the research question or questions. Use " "a maximum of 200 words." -#: proposals/models.py:213 +#: proposals/models.py:215 msgid "" "Zijn er nog andere onderzoekers bij deze aanvraag betrokken die geaffilieerd " "zijn aan één van de onderzoeksinstituten ICON, OFR, OGK of ILS?" @@ -1636,11 +1669,11 @@ msgstr "" "Are there any other researchers involved affiliated with ICON, OFR, OGK or " "ILS?" -#: proposals/models.py:227 +#: proposals/models.py:229 msgid "Andere betrokkenen" msgstr "Other people involved" -#: proposals/models.py:232 +#: proposals/models.py:234 msgid "" "Worden de informed consent formulieren nog vertaald naar een andere taal dan " "Nederlands of Engels?" @@ -1648,30 +1681,30 @@ msgstr "" "Will the informed consent forms be translated in a language other than Dutch " "or English?" -#: proposals/models.py:239 +#: proposals/models.py:241 msgid "Andere talen:" msgstr "Other languages:" -#: proposals/models.py:248 +#: proposals/models.py:250 msgid "Hoe wordt dit onderzoek gefinancierd?" msgstr "How is this study funded?" -#: proposals/models.py:259 +#: proposals/models.py:261 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:263 +#: proposals/models.py:265 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:269 +#: proposals/models.py:271 msgid "Ruimte voor eventuele opmerkingen. Gebruik maximaal 1000 woorden." msgstr "Space for possible comments. Use a maximum of a 1000 words." -#: proposals/models.py:275 +#: proposals/models.py:277 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 " @@ -1694,7 +1727,7 @@ msgstr "" "> - The title of the study
    - The planned starting date
    - The " "facilities you intend to use (database, lab, Zep software)" -#: proposals/models.py:295 +#: proposals/models.py:297 msgid "" "Als de deelnemers van je onderzoek moeten worden misleid, kan je " "ervoor kiezen je applicatie pas later op te laten nemen in het " @@ -1706,16 +1739,16 @@ msgstr "" "for users of this portal. Would you like your application to be placed under " "a temporary embargo?" -#: proposals/models.py:306 +#: proposals/models.py:308 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:316 +#: proposals/models.py:318 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:324 +#: proposals/models.py:326 msgid "" "Heb je formele toestemming van een ethische toetsingcommissie, uitgezonderd " "deze FETC-GW commissie?" @@ -1723,11 +1756,11 @@ msgstr "" "Do you have formal approval from an ethics committee, other than this FEtC-H " "committee?" -#: proposals/models.py:332 +#: proposals/models.py:334 msgid "Welk instituut heeft de aanvraag goedgekeurd?" msgstr "Which institute approved the application?" -#: proposals/models.py:340 +#: proposals/models.py:342 msgid "" "Upload hier je formele toestemmingsbrief van dit instituut (in .pdf of ." "doc(x)-formaat)" @@ -1735,22 +1768,22 @@ msgstr "" "Please upload the formal approval letter from this institute here (in .pdf " "or .doc(x)-format)" -#: proposals/models.py:348 +#: proposals/models.py:350 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:353 +#: proposals/models.py:355 msgid "Ik vul de portal in om de portal te exploreren" msgstr "I am using this portal to explore the portal" -#: proposals/models.py:365 +#: proposals/models.py:367 msgid "" "Kan voor alle deelnemersgroepen dezelfde informatiebrief en " "toestemmingsverklaring gebruikt worden?" msgstr "" "Can the same informed consent documents be used for all participant groups?" -#: proposals/models.py:367 +#: proposals/models.py:369 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 " @@ -1774,11 +1807,11 @@ msgstr "" "time. However, if separate groups receive different kinds of tasks, " "they constitute separate trajectories." -#: proposals/models.py:383 +#: proposals/models.py:385 msgid "Hoeveel verschillende trajecten zijn er?" msgstr "How many different trajectories are there?" -#: proposals/models.py:401 +#: proposals/models.py:403 msgid "" "Ik heb kennis genomen van het bovenstaande en begrijp mijn " "verantwoordelijkheden ten opzichte van de AVG." @@ -1786,7 +1819,7 @@ msgstr "" "I have read the information above and have considered my responsibilities " "with regard to the AVG." -#: proposals/models.py:408 +#: proposals/models.py:410 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 " @@ -1796,23 +1829,23 @@ msgstr "" "include it here. Supplying a DMP can expedite ethical assessment of " "proposals." -#: proposals/models.py:420 reviews/models.py:180 +#: proposals/models.py:422 reviews/models.py:184 msgid "Ruimte voor eventuele opmerkingen" msgstr "Space for possible comments" -#: proposals/models.py:432 +#: proposals/models.py:434 msgid "Datum bevestigingsbrief verstuurd" msgstr "Date confirmation sent" -#: proposals/models.py:437 reviews/forms.py:108 +#: proposals/models.py:439 reviews/forms.py:108 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:442 +#: proposals/models.py:444 msgid "Leg uit" msgstr "Explain why" -#: proposals/models.py:448 +#: proposals/models.py:450 msgid "" "Wat zijn de belangrijkste ethische kwesties in dit onderzoek en beschrijf " "kort hoe ga je daarmee omgaat. Gebruik maximaal 1000 woorden." @@ -1821,23 +1854,23 @@ msgstr "" "please describe briefly how you will address them. Use a maximum of a 1000 " "words." -#: proposals/models.py:462 +#: proposals/models.py:464 msgid "In welke hoedanigheid ben je betrokken bij dit onderzoek?" msgstr "In what capacity are you involved in this application?" -#: proposals/models.py:470 +#: proposals/models.py:472 msgid "Wat is je studierichting?" msgstr "What is your course of study?" -#: proposals/models.py:477 +#: proposals/models.py:479 msgid "In welke context doe je dit onderzoek?" msgstr "In what capacity are you involved in this application?" -#: proposals/models.py:484 +#: proposals/models.py:486 msgid "Namelijk:" msgstr "Please specify:" -#: proposals/models.py:491 +#: proposals/models.py:493 msgid "" "Studenten (die mensgebonden onderzoek uitvoeren binnen hun studieprogramma) " "hoeven in principe geen aanvraag in te dienen bij de FETC-GW. Bespreek met " @@ -1851,7 +1884,7 @@ msgstr "" "do not not, you can terminate your proposal now. If you do, please explain " "what the reason is:" -#: proposals/models.py:508 +#: proposals/models.py:510 msgid "" "Uitvoerenden, inclusief uzelf. Let op! De andere onderzoekers moeten " "ten minste één keer zijn ingelogd op dit portaal om ze te kunnen selecteren." @@ -1860,13 +1893,13 @@ msgstr "" "researchers need to have logged into this portal at least once, in order to " "be selectable here." -#: proposals/models.py:515 +#: proposals/models.py:517 #: 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:518 +#: proposals/models.py:520 msgid "" "Aan het einde van de procedure kan je deze aanvraag ter\n" " verificatie naar je eindverantwoordelijke sturen. De\n" @@ -1888,53 +1921,53 @@ msgstr "" "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:543 +#: proposals/models.py:545 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:615 +#: proposals/models.py:617 msgid "Amendement" msgstr "Amendment" -#: proposals/models.py:615 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:71 #: reviews/templates/reviews/review_detail_sidebar.html:106 msgid "Revisie" msgstr "Revision" -#: proposals/models.py:621 +#: proposals/models.py:623 msgid "Normaal" msgstr "Normal" -#: proposals/models.py:626 +#: proposals/models.py:628 msgid "Voortoetsing" msgstr "Preliminary assessment" -#: proposals/models.py:628 +#: proposals/models.py:630 msgid "Oefening" msgstr "Practice" -#: proposals/models.py:630 +#: proposals/models.py:632 msgid "Extern getoetst" msgstr "External approval" -#: proposals/models.py:667 +#: proposals/models.py:730 msgid "Geen beoordeling door METC noodzakelijk" msgstr "Assessment by METC not required" -#: proposals/models.py:668 +#: proposals/models.py:731 msgid "In afwachting beslissing METC" msgstr "Pending decision by METC" -#: proposals/models.py:669 +#: proposals/models.py:732 msgid "Beslissing METC geüpload" msgstr "METC decision uploaded" -#: proposals/models.py:673 +#: proposals/models.py:736 msgid "" "Vindt de dataverzameling plaats binnen het UMC Utrecht of andere instelling " "waar toetsing door een METC verplicht is gesteld?" @@ -1942,11 +1975,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:687 +#: proposals/models.py:750 msgid "Welke instelling?" msgstr "Which institution?" -#: proposals/models.py:693 +#: proposals/models.py:756 msgid "" "Is de onderzoeksvraag medisch-wetenschappelijk van aard (zoals gedefinieerd " "door de WMO)?" @@ -1954,7 +1987,7 @@ msgstr "" "Is the nature of the research question medical (as defined by the Medical " "Research Involving Human Subjects Act (WMO))?" -#: proposals/models.py:695 +#: proposals/models.py:758 msgid "" "De definitie van medisch-wetenschappelijk onderzoek is: Medisch-" "wetenschappelijk onderzoek is onderzoek dat als doel heeft het beantwoorden " @@ -1975,7 +2008,7 @@ msgstr "" "Committee on Research Involving Human Subjects, Definition of medical " "research, 2005, ccmo.nl)" -#: proposals/models.py:711 +#: proposals/models.py:774 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?" @@ -1984,15 +2017,15 @@ msgstr "" "registered with the FEtC-H. Has an application for this project already been " "submitted to an METC?" -#: proposals/models.py:718 +#: proposals/models.py:781 msgid "Is de METC al tot een beslissing gekomen?" msgstr "Has the METC already come to a decision?" -#: proposals/models.py:723 +#: proposals/models.py:786 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:761 +#: proposals/models.py:824 #, python-brace-format msgid "WMO {title}, status {status}" msgstr "WMO {title}, status {status}" @@ -2094,10 +2127,10 @@ msgstr "" #: 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:164 -#: proposals/templates/proposals/proposal_diff.html:197 -#: proposals/templates/proposals/proposal_diff.html:230 -#: proposals/templates/proposals/proposal_diff.html:254 +#: 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" @@ -2113,10 +2146,10 @@ msgstr "Original application" #: 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:165 -#: proposals/templates/proposals/proposal_diff.html:198 -#: proposals/templates/proposals/proposal_diff.html:231 -#: proposals/templates/proposals/proposal_diff.html:255 +#: 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" @@ -2203,16 +2236,16 @@ msgstr "yes,no," #: 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:107 -#: proposals/templates/proposals/proposal_diff.html:108 -#: proposals/templates/proposals/proposal_diff.html:202 -#: proposals/templates/proposals/proposal_diff.html:203 -#: proposals/templates/proposals/proposal_diff.html:207 -#: proposals/templates/proposals/proposal_diff.html:208 -#: proposals/templates/proposals/proposal_diff.html:235 -#: proposals/templates/proposals/proposal_diff.html:236 -#: proposals/templates/proposals/proposal_diff.html:259 -#: proposals/templates/proposals/proposal_diff.html:260 +#: 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 @@ -2268,8 +2301,8 @@ msgstr "" #: 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:214 -#: proposals/templates/proposals/proposal_diff.html:218 +#: 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 @@ -2659,7 +2692,7 @@ msgstr "" #: proposals/templates/proposals/proposal_form.html:7 #: proposals/templates/proposals/proposal_form.html:92 #: proposals/templates/proposals/proposal_form_pre_approved.html:7 -#: proposals/templates/proposals/proposal_form_pre_approved.html:75 +#: proposals/templates/proposals/proposal_form_pre_approved.html:76 #: proposals/templates/proposals/proposal_pdf.html:82 #: proposals/templates/proposals/proposal_pdf_empty.html:60 #: proposals/templates/proposals/proposal_pdf_pre_approved.html:69 @@ -2672,8 +2705,8 @@ msgstr "" msgid "Algemene informatie over de aanvraag" msgstr "General information about the application" -#: proposals/templates/proposals/proposal_diff.html:119 -#: proposals/templates/proposals/proposal_diff.html:120 +#: 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 @@ -2681,7 +2714,7 @@ msgstr "General information about the application" msgid "onbekend" msgstr "unknown" -#: proposals/templates/proposals/proposal_diff.html:160 +#: 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 @@ -2692,7 +2725,7 @@ msgid "" msgstr "" "Ethical assessment by a Medical Ethical Testing Committee (METC) required?" -#: proposals/templates/proposals/proposal_diff.html:193 +#: 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 @@ -2700,7 +2733,7 @@ msgstr "" msgid "Aanmelding bij de METC" msgstr "Registration with the METC" -#: proposals/templates/proposals/proposal_diff.html:226 +#: 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 @@ -2709,13 +2742,13 @@ msgstr "Registration with the METC" msgid "Eén of meerdere trajecten?" msgstr "One or more trajectories?" -#: proposals/templates/proposals/proposal_diff.html:250 +#: 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:66 +#: proposals/templates/proposals/proposal_form_pre_approved.html:67 #: proposals/templates/proposals/proposal_submit.html:33 msgid "Aantal woorden:" msgstr "Number of words:" @@ -2747,7 +2780,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:77 +#: proposals/templates/proposals/proposal_form_pre_approved.html:78 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 " @@ -2757,7 +2790,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:91 +#: proposals/templates/proposals/proposal_form_pre_approved.html:92 #, python-format msgid "" "Dit formulier is bedoeld voor aanvragen die al goedgekeurd zijn door een " @@ -3643,11 +3676,11 @@ msgstr "Forms" msgid "Versturen" msgstr "Submit" -#: proposals/utils/proposal_utils.py:415 +#: proposals/utils/proposal_utils.py:416 msgid "FETC-GW: gereviseerde aanvraag gebruikt labfaciliteiten" msgstr "FEtC-H: A revised application uses lab facilities" -#: proposals/utils/proposal_utils.py:417 +#: proposals/utils/proposal_utils.py:418 msgid "FETC-GW: nieuwe aanvraag gebruikt labfaciliteiten" msgstr "FEtC-H: New application uses lab facilities" @@ -3696,40 +3729,40 @@ msgstr "" "You must confirm your understanding of the AVG before you can submit your " "application." -#: proposals/views/proposal_views.py:42 +#: proposals/views/proposal_views.py:43 msgid "Publiek archief" msgstr "Public archive" -#: proposals/views/proposal_views.py:43 +#: proposals/views/proposal_views.py:44 msgid "Dit overzicht toont alle goedgekeurde aanvragen." msgstr "This overview shows all approved applications." -#: proposals/views/proposal_views.py:62 +#: proposals/views/proposal_views.py:63 msgid "Mijn aanvraag" msgstr "My application" -#: proposals/views/proposal_views.py:63 +#: proposals/views/proposal_views.py:64 msgid "Dit overzicht toont al je aanvragen." msgstr "This overview shows all your applications." -#: proposals/views/proposal_views.py:76 +#: proposals/views/proposal_views.py:77 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:88 +#: proposals/views/proposal_views.py:89 msgid "Dit overzicht toont al je ingediende aanvragen." msgstr "This overview shows all the applications you have submitted." -#: proposals/views/proposal_views.py:100 +#: proposals/views/proposal_views.py:101 msgid "Dit overzicht toont al je beoordeelde aanvragen." msgstr "This overview shows all your applications that have been assessed." -#: proposals/views/proposal_views.py:113 +#: proposals/views/proposal_views.py:114 msgid "" "Dit overzicht toont alle aanvragen waarvan je eindverantwoordelijke bent." msgstr "This overview shows all your supervised applications." -#: proposals/views/proposal_views.py:126 +#: proposals/views/proposal_views.py:127 msgid "" "Dit overzicht toont alle oefenaanvragen waar je als student, onderzoeker of " "eindverantwoordelijke bij betrokken bent." @@ -3737,15 +3770,15 @@ msgstr "" "This overview shows all practice applications in which you are involved as a " "student, researcher or accountable researcher." -#: proposals/views/proposal_views.py:241 +#: proposals/views/proposal_views.py:246 msgid "Aanvraag verwijderd" msgstr "Application deleted" -#: proposals/views/proposal_views.py:379 +#: proposals/views/proposal_views.py:384 msgid "Wijzigingen opgeslagen" msgstr "Changes saved" -#: proposals/views/proposal_views.py:480 +#: proposals/views/proposal_views.py:485 msgid "Aanvraag gekopieerd" msgstr "Application copied" @@ -3794,11 +3827,11 @@ msgstr "Route" msgid "Start datum" msgstr "Start date review" -#: reviews/forms.py:12 reviews/models.py:138 +#: reviews/forms.py:12 reviews/models.py:142 msgid "korte (2-weken) route" msgstr "short (2-week) route" -#: reviews/forms.py:13 reviews/models.py:137 +#: reviews/forms.py:13 reviews/models.py:141 msgid "lange (4-weken) route" msgstr "long (4-week) route" @@ -3890,28 +3923,28 @@ msgstr "Post hoc negative advice by FETC-H" msgid "Niet verder in behandeling genomen" msgstr "Not to be assessed further" -#: reviews/models.py:51 reviews/models.py:174 +#: reviews/models.py:51 reviews/models.py:178 #: reviews/templates/reviews/review_table.html:9 msgid "Beslissing" msgstr "Decision" -#: reviews/models.py:122 +#: reviews/models.py:126 msgid "Onbekend" msgstr "Unknown" -#: reviews/models.py:139 +#: reviews/models.py:143 msgid "nog geen route" msgstr "no route assigned" -#: reviews/models.py:168 +#: reviews/models.py:172 msgid "goedgekeurd" msgstr "endorsed" -#: reviews/models.py:169 +#: reviews/models.py:173 msgid "niet goedgekeurd" msgstr "not endorsed" -#: reviews/models.py:170 +#: reviews/models.py:174 msgid "revisie noodzakelijk" msgstr "revision necessary" @@ -4590,61 +4623,61 @@ msgstr "Change date of confirmation letter" msgid "Plaats aanvraag in het archief." msgstr "Add this application to the archive" -#: reviews/utils/review_utils.py:53 +#: reviews/utils/review_utils.py:54 msgid "FETC-GW {}: bevestiging indienen concept-aanmelding" msgstr "FEtC-H {}: confirmation of draft application submission" -#: reviews/utils/review_utils.py:64 +#: reviews/utils/review_utils.py:74 msgid "FETC-GW {}: beoordelen als eindverantwoordelijke" msgstr "FEtC-H {}: assess as researcher with final responsibility" -#: reviews/utils/review_utils.py:113 +#: reviews/utils/review_utils.py:124 msgid "FETC-GW {}: aanmelding ontvangen" msgstr "FEtC-H {}: application received" -#: reviews/utils/review_utils.py:193 +#: reviews/utils/review_utils.py:218 msgid "FETC-GW {}: nieuwe aanvraag voor voortoetsing" msgstr "FEtC-H {}: new application for preliminary assessment" -#: reviews/utils/review_utils.py:207 +#: reviews/utils/review_utils.py:232 msgid "FETC-GW {}: bevestiging indienen aanvraag voor voortoetsing" msgstr "" "FEtC-H {}: confirmation of submission of application for preliminary " "assessment" -#: reviews/utils/review_utils.py:256 +#: reviews/utils/review_utils.py:281 msgid "FETC-GW {}: nieuwe aanvraag ingediend" msgstr "FEtC-H {}: new application submitted" -#: reviews/utils/review_utils.py:271 +#: reviews/utils/review_utils.py:296 msgid "FETC-GW {}: nieuwe beoordeling toegevoegd" msgstr "FEtC-H {}: new decision added" -#: reviews/utils/review_utils.py:287 +#: reviews/utils/review_utils.py:312 msgid "FETC-GW {}: eindverantwoordelijke heeft je aanvraag beoordeeld" msgstr "FEtC-H {}: a supervisor has reviewed your application" -#: reviews/utils/review_utils.py:313 +#: reviews/utils/review_utils.py:338 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:316 +#: reviews/utils/review_utils.py:341 msgid "De aanvraag bevat het gebruik van misleiding." msgstr "The application contains the use of misrepresentation." -#: reviews/utils/review_utils.py:319 +#: reviews/utils/review_utils.py:344 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:322 +#: reviews/utils/review_utils.py:347 msgid "Het onderzoek verzamelt bijzondere persoonsgegevens." msgstr "This study collects special or sensitive personal details." -#: reviews/utils/review_utils.py:325 +#: reviews/utils/review_utils.py:350 msgid "" "Het onderzoek selecteert deelnemers op bijzondere kenmerken die wellicht " "verhoogde kwetsbaarheid met zich meebrengen." @@ -4652,7 +4685,7 @@ msgstr "" "The study selects participants based on particular characteristics which " "might entail increased vulnerability." -#: reviews/utils/review_utils.py:331 +#: reviews/utils/review_utils.py:356 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 " @@ -4662,7 +4695,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:335 +#: reviews/utils/review_utils.py:360 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 " @@ -4672,7 +4705,7 @@ msgstr "" "psychological or physical harm in participating in the study are more than " "minimal." -#: reviews/utils/review_utils.py:342 +#: reviews/utils/review_utils.py:367 #, python-brace-format msgid "" "De totale duur van de taken in sessie {s}, exclusief pauzes en andere niet-" @@ -4683,14 +4716,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:359 +#: reviews/utils/review_utils.py:384 #, 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:363 +#: reviews/utils/review_utils.py:388 msgid "" "Het onderzoek observeert deelnemers in een niet-publieke ruimte en werkt met " "informed consent achteraf." @@ -4698,7 +4731,7 @@ msgstr "" "The study observes participants in a non-public space and works with " "retrospective informed consent." -#: reviews/utils/review_utils.py:365 +#: reviews/utils/review_utils.py:390 msgid "" "De onderzoeker begeeft zich \"under cover\" in een beheerde niet-publieke " "ruimte (bijv. een digitale gespreksgroep), en neemt actief aan de discussie " @@ -4708,11 +4741,11 @@ 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:370 +#: reviews/utils/review_utils.py:395 msgid "De aanvraag bevat het gebruik van {}" msgstr "The application makes use of {}" -#: reviews/utils/review_utils.py:391 +#: reviews/utils/review_utils.py:416 msgid "" "De aanvraag bevat psychofysiologische metingen bij kinderen onder de {} jaar." msgstr "" diff --git a/main/admin.py b/main/admin.py index d9b46e159..482305b6c 100644 --- a/main/admin.py +++ b/main/admin.py @@ -1,12 +1,14 @@ from django.contrib import admin -from django.contrib.auth.admin import GroupAdmin +from django.contrib.auth import get_user_model +from django.contrib.auth.admin import GroupAdmin, UserAdmin from django.contrib.auth.models import Group from django.db.models import CharField from django.forms import Textarea -from .models import Setting, SystemMessage +from .models import Setting, SystemMessage, Faculty admin.site.unregister(Group) +admin.site.unregister(get_user_model()) class UserInLine(admin.TabularInline): @@ -19,6 +21,13 @@ class GenericGroup(GroupAdmin): inlines = [UserInLine] +@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',) + + @admin.register(Setting) class SettingAdmin(admin.ModelAdmin): list_display = ('order', 'description', 'is_local', 'needs_details', 'needs_supervision', 'requires_review', 'is_school',) @@ -34,3 +43,18 @@ class SystemMessageAdmin(admin.ModelAdmin): 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" + extra = 1 + + +class CustomUserAdmin(UserAdmin): + inlines = [FacultyInline] + + +admin.site.register(get_user_model(), CustomUserAdmin) \ No newline at end of file diff --git a/main/fixtures/faculties.json b/main/fixtures/faculties.json new file mode 100644 index 000000000..63ac0f146 --- /dev/null +++ b/main/fixtures/faculties.json @@ -0,0 +1,24 @@ +[ +{ + "model": "main.faculty", + "pk": 1, + "fields": { + "name": "Faculteit Geesteswetenschappen", + "name_nl": "Faculteit Geesteswetenschappen", + "name_en": "Faculty of Humanities", + "saml_name": "Faculteit Geesteswetenschappen", + "internal_name": "humanities" + } +}, +{ + "model": "main.faculty", + "pk": 2, + "fields": { + "name": "Faculteit Sociale Wetenschappen", + "name_nl": "Faculteit Sociale Wetenschappen", + "name_en": "Faculty of Social and Behavioural Sciences", + "saml_name": "Faculteit Sociale Wetenschappen", + "internal_name": "other" + } +} +] \ No newline at end of file diff --git a/main/migrations/0009_faculty_samluserproxy.py b/main/migrations/0009_faculty_samluserproxy.py new file mode 100644 index 000000000..5b931532c --- /dev/null +++ b/main/migrations/0009_faculty_samluserproxy.py @@ -0,0 +1,42 @@ +# Generated by Django 3.2.20 on 2023-10-05 14:26 + +from django.conf import settings +import django.contrib.auth.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('main', '0008_auto_20220926_0929'), + ] + + operations = [ + migrations.CreateModel( + name='SamlUserProxy', + fields=[ + ], + options={ + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('auth.user',), + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + 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)), + ], + ), + ] diff --git a/main/migrations/0010_faculty_internal_name.py b/main/migrations/0010_faculty_internal_name.py new file mode 100644 index 000000000..868019fef --- /dev/null +++ b/main/migrations/0010_faculty_internal_name.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.20 on 2023-10-16 09:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('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), + ), + ] diff --git a/main/models.py b/main/models.py index 18d5d409a..05f9105a2 100644 --- a/main/models.py +++ b/main/models.py @@ -1,3 +1,5 @@ +from django.contrib.auth import get_user_model +from django.contrib.auth.models import User from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -98,3 +100,70 @@ def settings_contains_schools(self): def settings_requires_review(self): """If the current settings contain any that requires review""" return self.setting.filter(requires_review=True) + + +class Faculty(models.Model): + class InternalNames(models.TextChoices): + HUMANITIES = "humanities" + OTHER = "other" + + name = models.CharField(max_length=255) + + # This should be the same as the Dutch name, but we store it separately + # to allow us to edit `name` freely + saml_name = models.CharField( + max_length=255, + ) + + users = models.ManyToManyField( + get_user_model(), + related_name='faculties' + ) + + internal_name = models.CharField( + max_length=50, + choices=InternalNames.choices, + default=InternalNames.OTHER, + ) + + def __str__(self): + return self.name + + +class SamlUserProxy(User): + """This special proxy model is used to process attributes from SAML + It's not a replacement User model. It may be used elsewhere in code, but + why would you? + """ + class Meta: + proxy = True + + def process_faculties(self, faculties): + """Receives a list of faculties of the user and couples them to the + relevant Faculty. Also creates a new Faculty for not-yet-know + faculties. + """ + for faculty in faculties: + # Ignore empty values + if not faculty: + continue + + # We should manually maintain some ourselves, but this allows + # some auto-population + if not Faculty.objects.filter(saml_name=faculty).exists(): + Faculty.objects.create( + saml_name=faculty, + name_nl=faculty, # SAML gives us the Dutch names + ) + + try: + faculty_obj = Faculty.objects.get(saml_name=faculty) + + # Don't re-add. + if faculty_obj.users.filter(pk=self.pk).exists(): + continue + + faculty_obj.users.add(self) + except: + # Just ignore any errors... + continue diff --git a/main/templates/main/index.html b/main/templates/main/index.html index 4bd3af915..768af10c6 100644 --- a/main/templates/main/index.html +++ b/main/templates/main/index.html @@ -11,6 +11,38 @@

    + {% if not is_humanities %} +
    +
    +

    + {% 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 %} + Volgens onze gegevens werk/studeer je bij de + {% endblocktrans %} + {{ user.faculties.all|join:',' }}. + {% else %} + {% blocktrans trimmed %} + 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 %} +

    +

    + {% blocktrans trimmed %} + Als je vermoedt dat dit incorrect is, neem dan contact op met portalsupport.gw@uu.nl. + {% endblocktrans %} +

    +
    +
    + {% endif %}
    {% for message in systemmessage_list %} diff --git a/main/translation.py b/main/translation.py index e31abe436..12b368e84 100644 --- a/main/translation.py +++ b/main/translation.py @@ -1,6 +1,6 @@ from modeltranslation.translator import register, TranslationOptions -from .models import Setting, SystemMessage +from .models import Faculty, Setting, SystemMessage @register(Setting) @@ -11,3 +11,8 @@ class SettingTranslationOptions(TranslationOptions): @register(SystemMessage) class SystemMessageTranslationOptions(TranslationOptions): fields = ('message',) + + +@register(Faculty) +class FacultyTranslationOptions(TranslationOptions): + fields = ('name',) diff --git a/main/utils.py b/main/utils.py index c676be2f5..e1d79de76 100644 --- a/main/utils.py +++ b/main/utils.py @@ -10,6 +10,8 @@ import pdftotext from docx2txt import docx2txt +from main.models import Faculty + YES_NO = [(True, _('ja')), (False, _('nee'))] @@ -149,3 +151,11 @@ def get_document_contents(file: FieldFile) -> str: return docx2txt.process(f) return "No text found" + + +def is_member_of_faculty(user, faculty): + return user.faculties.filter(internal_name=faculty).exists() + + +def is_member_of_humanities(user): + return is_member_of_faculty(user, Faculty.InternalNames.HUMANITIES) diff --git a/main/views.py b/main/views.py index 44cbd0463..0a4a89c16 100644 --- a/main/views.py +++ b/main/views.py @@ -25,7 +25,8 @@ from django.views.generic.detail import SingleObjectMixin from interventions.models import Intervention -from main.models import SystemMessage +from main.models import Faculty, SystemMessage +from main.utils import is_member_of_humanities from observations.models import Observation from proposals.models import Proposal from reviews.models import Review @@ -65,6 +66,12 @@ def no_permissions_fail(self, request=None): 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) + + return context class LandingView(_SystemMessageView): template_name = 'main/landing.html' @@ -286,6 +293,50 @@ def form_invalid(self, form): return super(AllowErrorsOnBackbuttonMixin, self).form_invalid(form) +class FacultyRequiredMixin: + """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 " + "tuple".format(self.__class__.__name__) + ) + if not isinstance(self.faculty_required, (list, tuple)): + self.faculty_required = (self.faculty_required,) + return self.faculty_required + + def check_membership(self, faculty): + """Check required faculty(ies)""" + user_faculties = self.request.user.faculties.values_list( + "internal_name", + flat=True + ) + return set(faculty).intersection(set(user_faculties)) + + def dispatch(self, request, *args, **kwargs): + self.request = request + in_faculty = False + if request.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 + ) + + +class HumanitiesRequiredMixin(FacultyRequiredMixin): + faculty_required = Faculty.InternalNames.HUMANITIES + + class UserAllowedMixin(SingleObjectMixin): def get_object(self, queryset=None): """ diff --git a/proposals/menus.py b/proposals/menus.py index dc78be38c..020f14f31 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_secretary +from main.utils import is_member_of_humanities, is_secretary new_proposal_menu = ( MenuItem( @@ -89,10 +89,12 @@ MenuItem( _("Bekijk alle goedgekeurde aanvragen van de Algemene Kamer"), reverse("proposals:archive", args=['AK']), + check=lambda x: is_member_of_humanities(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), ), MenuItem( _("Site-export"), @@ -109,6 +111,6 @@ "#", slug='archive', # needed for sub-menu! children=archive_menu, - check=lambda x: x.user.is_authenticated, + check=lambda x: x.user.is_authenticated and is_member_of_humanities(x.user), ) ) diff --git a/proposals/migrations/0048_auto_20231016_1202.py b/proposals/migrations/0048_auto_20231016_1202.py new file mode 100644 index 000000000..d05e09b71 --- /dev/null +++ b/proposals/migrations/0048_auto_20231016_1202.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.20 on 2023-10-16 10:02 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('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.'), + ), + 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?'), + ), + ] diff --git a/proposals/views/proposal_views.py b/proposals/views/proposal_views.py index 1a3dcf6f0..67c635aa2 100644 --- a/proposals/views/proposal_views.py +++ b/proposals/views/proposal_views.py @@ -17,7 +17,7 @@ from main.utils import get_document_contents, get_secretary, is_secretary from main.views import AllowErrorsOnBackbuttonMixin, CreateView, DeleteView, \ - UpdateView, UserAllowedMixin + HumanitiesRequiredMixin, UpdateView, UserAllowedMixin from observations.models import Observation from proposals.utils.validate_proposal import get_form_errors from reviews.mixins import CommitteeMixin, UsersOrGroupsAllowedMixin @@ -135,7 +135,11 @@ def get_context_data(self, **kwargs): return context -class ProposalUsersOnlyArchiveView(CommitteeMixin, BaseProposalsView): +class ProposalUsersOnlyArchiveView( + HumanitiesRequiredMixin, + CommitteeMixin, + BaseProposalsView +): template_name = 'proposals/proposal_private_archive.html' def get_context_data(self, **kwargs):