def dashboard(request, template_name="dashboard/dashboard.html"): job_applications_counter = 0 prescriber_authorization_status_not_set = None prescriber_is_orienter = False if request.user.is_siae_staff: siae = get_current_siae_or_404(request) job_applications_counter = siae.job_applications_received.filter( state=JobApplicationWorkflow.STATE_NEW).count() # See template for display message while authorized organization is being validated (prescriber path) if request.user.is_prescriber_with_org: prescriber_organization = get_current_org_or_404(request) prescriber_authorization_status_not_set = ( prescriber_organization.authorization_status == PrescriberOrganization.AuthorizationStatus.NOT_SET) # This is to hide the "secret code", except for orienter orgs prescriber_is_orienter = ( prescriber_organization.authorization_status == PrescriberOrganization.AuthorizationStatus.NOT_REQUIRED) context = { "job_applications_counter": job_applications_counter, "prescriber_authorization_status_not_set": prescriber_authorization_status_not_set, "prescriber_is_orienter": prescriber_is_orienter, } return render(request, template_name, context)
def assert_invitation_is_accepted(self, response, user, invitation): self.assertRedirects(response, DASHBOARD_URL) user.refresh_from_db() invitation.refresh_from_db() self.assertTrue(user.is_prescriber) self.assertTrue(invitation.accepted) self.assertTrue(invitation.accepted_at) self.assertEqual(self.organization.members.count(), 3) # Make sure there's a welcome message. self.assertContains( response, escape(f"Vous êtes désormais membre de l'organisation {self.organization.display_name}.") ) # A confirmation e-mail is sent to the invitation sender. self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox[0].to), 1) self.assertEqual(invitation.sender.email, mail.outbox[0].to[0]) # Assert the user sees his new organization dashboard. current_org = get_current_org_or_404(response.wsgi_request) # A user can be member of one or more organizations self.assertTrue(current_org in user.prescriberorganization_set.all())
def list_accredited_organizations( request, template_name="prescribers/list_accredited_organizations.html"): """ List organizations accredited by a departmental council ("Conseil Départemental"). """ prescriber_org = get_current_org_or_404(request) required_permissions = [ prescriber_org.is_authorized, prescriber_org.kind == prescriber_org.Kind.DEPT, prescriber_org.has_admin(request.user), ] if not all(required_permissions): raise PermissionDenied accredited_orgs = PrescriberOrganization.objects.get_accredited_orgs_for( prescriber_org).prefetch_active_memberships() context = { "prescriber_org": prescriber_org, "accredited_orgs": accredited_orgs } return render(request, template_name, context)
def members(request, template_name="prescribers/members.html"): """ List members of a prescriber organization. """ organization = get_current_org_or_404(request) members = organization.prescribermembership_set.select_related("user").all().order_by("joined_at") context = {"organization": organization, "members": members} return render(request, template_name, context)
def edit_organization(request, template_name="prescribers/edit_organization.html"): """ Edit a prescriber organization. """ organization = get_current_org_or_404(request) form = EditPrescriberOrganizationForm(instance=organization, data=request.POST or None) if request.method == "POST" and form.is_valid(): form.save() messages.success(request, _("Mise à jour effectuée !")) return HttpResponseRedirect(reverse_lazy("dashboard:index")) context = {"form": form, "organization": organization} return render(request, template_name, context)
def deactivate_member(request, user_id, template_name="prescribers/deactivate_member.html"): organization = get_current_org_or_404(request) target_member = User.objects.get(pk=user_id) if deactivate_org_member(request=request, target_member=target_member, organization=organization): return HttpResponseRedirect(reverse_lazy("prescribers_views:members")) context = { "structure": organization, "target_member": target_member, } return render(request, template_name, context)
def member_list(request, template_name="prescribers/members.html"): """ List members of a prescriber organization. """ organization = get_current_org_or_404(request) members = (organization.prescribermembership_set.filter( is_active=True).select_related("user").all().order_by( "-is_admin", "joined_at")) pending_invitations = organization.invitations.pending() context = { "organization": organization, "members": members, "pending_invitations": pending_invitations, } return render(request, template_name, context)
def stats_cd(request, template_name=_STATS_HTML_TEMPLATE): """ CD ("Conseil Départemental") stats shown to relevant members. They can only view data for their own departement. """ current_org = get_current_org_or_404(request) if not request.user.can_view_stats_cd(current_org=current_org): raise PermissionDenied department = request.user.get_stats_cd_department(current_org=current_org) params = { DEPARTMENT_FILTER_KEY: DEPARTMENTS[department], REGION_FILTER_KEY: DEPARTMENT_TO_REGION[department], } context = { "iframeurl": metabase_embedded_url(settings.CD_STATS_DASHBOARD_ID, params=params), "page_title": f"Données de mon département : {DEPARTMENTS[department]}", "stats_base_url": settings.METABASE_SITE_URL, } return render(request, template_name, context)
def get_user_info(request): """ Return a namedtuple containing information about the current logged user. """ kind = None siae = None prescriber_organization = None if request.user.is_job_seeker: kind = KIND_JOB_SEEKER if request.user.is_siae_staff: kind = KIND_SIAE_STAFF siae = get_current_siae_or_404(request) if request.user.is_prescriber: kind = KIND_PRESCRIBER if request.user.is_prescriber_with_org: prescriber_organization = get_current_org_or_404(request) is_authorized_prescriber = prescriber_organization.is_authorized if prescriber_organization else False return UserInfo(request.user, kind, prescriber_organization, is_authorized_prescriber, siae)
def dashboard(request, template_name="dashboard/dashboard.html"): can_show_financial_annexes = False can_show_employee_records = False job_applications_categories = [] # `current_org` can be a Siae, a PrescriberOrganization or an Institution. current_org = None if request.user.is_siae_staff: current_org = get_current_siae_or_404(request) can_show_financial_annexes = current_org.convention_can_be_accessed_by(request.user) can_show_employee_records = current_org.can_use_employee_record job_applications_categories = [ { "name": "Candidatures à traiter", "states": [JobApplicationWorkflow.STATE_NEW, JobApplicationWorkflow.STATE_PROCESSING], "icon": "user-plus", "badge": "badge-danger", }, { "name": "Candidatures acceptées ou mises en liste d'attente", "states": [JobApplicationWorkflow.STATE_ACCEPTED, JobApplicationWorkflow.STATE_POSTPONED], "icon": "user-check", "badge": "badge-secondary", }, { "name": "Candidatures refusées/annulées", "states": [ JobApplicationWorkflow.STATE_REFUSED, JobApplicationWorkflow.STATE_CANCELLED, JobApplicationWorkflow.STATE_OBSOLETE, ], "icon": "user-x", "badge": "badge-secondary", }, ] job_applications = current_org.job_applications_received.values("state").all() for category in job_applications_categories: category["counter"] = len([ja for ja in job_applications if ja["state"] in category["states"]]) category[ "url" ] = f"{reverse('apply:list_for_siae')}?{'&'.join([f'states={c}' for c in category['states']])}" if request.user.is_prescriber: try: current_org = get_current_org_or_404(request) except Http404: pass if request.user.is_labor_inspector: current_org = get_current_institution_or_404(request) context = { "lemarche_regions": settings.LEMARCHE_OPEN_REGIONS, "job_applications_categories": job_applications_categories, "can_create_siae_antenna": request.user.can_create_siae_antenna(parent_siae=current_org), "can_show_financial_annexes": can_show_financial_annexes, "can_show_employee_records": can_show_employee_records, "can_view_stats_dashboard_widget": request.user.can_view_stats_dashboard_widget(current_org=current_org), "can_view_stats_siae": request.user.can_view_stats_siae(current_org=current_org), "can_view_stats_cd": request.user.can_view_stats_cd(current_org=current_org), "can_view_stats_ddets": request.user.can_view_stats_ddets(current_org=current_org), "can_view_stats_dreets": request.user.can_view_stats_dreets(current_org=current_org), "can_view_stats_dgefp": request.user.can_view_stats_dgefp(current_org=current_org), } return render(request, template_name, context)
def invite_prescriber_with_org(request, template_name="invitations_views/create.html"): organization = get_current_org_or_404(request) form_kwargs = {"sender": request.user, "organization": organization} # Initial data can be passed by GET params to ease invitation of new members request_invitation_form = signup_forms.PrescriberRequestInvitationForm( data=request.GET) if request_invitation_form.is_valid(): # The prescriber has accepted the request for an invitation of an external user. # The form will be pre-filled with the new user information. initial_data = [{ "first_name": request_invitation_form.cleaned_data.get("first_name"), "last_name": request_invitation_form.cleaned_data.get("last_name"), "email": request_invitation_form.cleaned_data.get("email"), }] else: initial_data = None formset = PrescriberWithOrgInvitationFormSet(data=request.POST or None, initial=initial_data, form_kwargs=form_kwargs) if request.POST: if formset.is_valid(): # We don't need atomicity here (invitations are independent) invitations = formset.save() for invitation in invitations: invitation.send() count = len(formset.forms) if count == 1: message = ( "Votre invitation a été envoyée par courriel.<br>" "Pour rejoindre votre organisation, il suffira simplement à votre invité(e) " "de cliquer sur le lien de validation contenu dans le courriel.<br>" ) else: message = ( "Vos invitations ont été envoyées par courriel.<br>" "Pour rejoindre votre organisation, il suffira simplement à vos invités " "de cliquer sur le lien de validation contenu dans le courriel.<br>" ) expiration_date = formats.date_format( invitations[0].expiration_date) message += f"Le lien de validation est valable jusqu'au {expiration_date}." message = safestring.mark_safe(message) messages.success(request, message) return redirect(request.path) form_post_url = reverse("invitations_views:invite_prescriber_with_org") back_url = reverse("prescribers_views:members") context = { "back_url": back_url, "form_post_url": form_post_url, "formset": formset } return render(request, template_name, context)