def add_publications(request, project_id): mapper = ProjectAllocationMapper(request) try: project = mapper.get_project(project_id) if project.source != "Chameleon" or not can_add_publications( request.user, project ): raise Http404("The requested project does not exist!") except Exception as e: logger.error(e) raise Http404("The requested project does not exist!") if request.POST: pubs_form = AddBibtexPublicationForm(request.POST) if pubs_form.is_valid(): bib_database = bibtexparser.loads(pubs_form.cleaned_data["bibtex_string"]) for entry in bib_database.entries: Publication.objects.create_from_bibtex( entry, project, request.user.username ) messages.success(request, "Publication added successfully") else: messages.error(request, "Error adding publication") pubs_form = AddBibtexPublicationForm(initial={"project_id": project.id}) return render( request, "projects/add_publications.html", { "project": project, "project_nickname": project.nickname, "is_pi": request.user.username == project.pi.username, "pubs_form": pubs_form, "form": pubs_form, }, )
def edit_nickname(request, project_id): mapper = ProjectAllocationMapper(request) project = mapper.get_project(project_id) if not project_pi_or_admin_or_superuser(request.user, project): messages.error(request, "Only the project PI can update nickname.") return EditNicknameForm() form = EditNicknameForm(request.POST) if form.is_valid(request): # try to update nickname try: nickname = form.cleaned_data["nickname"] ProjectAllocationMapper.update_project_nickname( project_id, nickname) form = EditNicknameForm() set_ks_project_nickname(project.chargeCode, nickname) messages.success( request, "Update successful! Click <a href='{}'>here</a> to reload". format(request.path), ) except: messages.error(request, "Nickname not available") else: messages.error(request, "Nickname not available") return form
def view_project(request, project_id): mapper = ProjectAllocationMapper(request) try: project = mapper.get_project(project_id) if project.source != "Chameleon": raise Http404("The requested project does not exist!") except Exception as e: logger.error(e) raise Http404("The requested project does not exist!") form = ProjectAddUserForm() nickname_form = EditNicknameForm() pubs_form = AddBibtexPublicationForm() if request.POST and project_pi_or_admin_or_superuser( request.user, project): form = ProjectAddUserForm() if "add_user" in request.POST: form = ProjectAddUserForm(request.POST) if form.is_valid(): try: add_username = form.cleaned_data["username"] if mapper.add_user_to_project(project, add_username): sync_project_memberships(request, add_username) messages.success( request, f'User "{add_username}" added to project!') form = ProjectAddUserForm() except Exception as e: logger.exception("Failed adding user") messages.error( request, ("Unable to add user. Confirm that the username is " "correct and corresponds to a current Chameleon user." ), ) else: messages.error( request, ("There were errors processing your request. " "Please see below for details."), ) elif "del_user" in request.POST: try: del_username = request.POST["username"] # Ensure that it's not possible to remove the PI if del_username == project.pi.username: raise PermissionDenied( "Removing the PI from the project is not allowed.") if mapper.remove_user_from_project(project, del_username): sync_project_memberships(request, del_username) messages.success( request, 'User "%s" removed from project' % del_username) except PermissionDenied as exc: messages.error(request, exc) except: logger.exception("Failed removing user") messages.error( request, "An unexpected error occurred while attempting " "to remove this user. Please try again", ) elif "nickname" in request.POST: nickname_form = edit_nickname(request, project_id) users = mapper.get_project_members(project) if not project_member_or_admin_or_superuser(request.user, project, users): raise PermissionDenied for a in project.allocations: if a.start and isinstance(a.start, str): a.start = datetime.strptime(a.start, "%Y-%m-%dT%H:%M:%SZ") if a.dateRequested: if isinstance(a.dateRequested, str): a.dateRequested = datetime.strptime(a.dateRequested, "%Y-%m-%dT%H:%M:%SZ") if a.dateReviewed: if isinstance(a.dateReviewed, str): a.dateReviewed = datetime.strptime(a.dateReviewed, "%Y-%m-%dT%H:%M:%SZ") if a.end: if isinstance(a.end, str): a.end = datetime.strptime(a.end, "%Y-%m-%dT%H:%M:%SZ") user_mashup = [] for u in users: user = { "username": u.username, "role": u.role, } try: portal_user = User.objects.get(username=u.username) user["email"] = portal_user.email user["first_name"] = portal_user.first_name user["last_name"] = portal_user.last_name except User.DoesNotExist: logger.info("user: "******" not found") user_mashup.append(user) return render( request, "projects/view_project.html", { "project": project, "project_nickname": project.nickname, "users": user_mashup, "is_pi": request.user.username == project.pi.username, "form": form, "nickname_form": nickname_form, "pubs_form": pubs_form, }, )
def create_allocation(request, project_id, allocation_id=-1): mapper = ProjectAllocationMapper(request) user = mapper.get_user(request.user.username) if user["piEligibility"].lower() != "eligible": messages.error( request, "Only PI Eligible users can request allocations. If you would " "like to request PI Eligibility, please " '<a href="/user/profile/edit/">submit a PI Eligibility ' "request</a>.", ) return HttpResponseRedirect(reverse("projects:user_projects")) project = mapper.get_project(project_id) allocation = None allocation_id = int(allocation_id) if allocation_id > 0: for a in project.allocations: if a.id == allocation_id: allocation = a # goofiness that we should clean up later; requires data cleansing abstract = project.description if "--- Supplemental details ---" in abstract: additional = abstract.split("\n\n--- Supplemental details ---\n\n") abstract = additional[0] additional = additional[1].split("\n\n--- Funding source(s) ---\n\n") justification = additional[0] if len(additional) > 1: funding_source = additional[1] else: funding_source = "" elif allocation: justification = allocation.justification if "--- Funding source(s) ---" in justification: parts = justification.split("\n\n--- Funding source(s) ---\n\n") justification = parts[0] funding_source = parts[1] else: funding_source = "" else: justification = "" funding_source = "" if request.POST: form = AllocationCreateForm( request.POST, initial={ "description": abstract, "supplemental_details": justification, "funding_source": funding_source, }, ) if form.is_valid(): allocation = form.cleaned_data.copy() allocation["computeRequested"] = 20000 # Also update the project project.description = allocation.pop("description", None) supplemental_details = allocation.pop("supplemental_details", None) logger.error(supplemental_details) funding_source = allocation.pop("funding_source", None) # if supplemental_details == None: # raise forms.ValidationError("Justifcation is required") # This is required if not supplemental_details: supplemental_details = "(none)" logger.error(supplemental_details) if funding_source: allocation[ "justification"] = "%s\n\n--- Funding source(s) ---\n\n%s" % ( supplemental_details, funding_source, ) else: allocation["justification"] = supplemental_details allocation["projectId"] = project_id allocation["requestorId"] = mapper.get_portal_user_id( request.user.username) allocation["resourceId"] = "39" if allocation_id > 0: allocation["id"] = allocation_id try: logger.info( "Submitting allocation request for project %s: %s" % (project.id, allocation)) updated_project = mapper.save_project(project.as_dict()) mapper.save_allocation(allocation, project.chargeCode, request.get_host()) messages.success( request, "Your allocation request has been submitted!") return HttpResponseRedirect( reverse("projects:view_project", args=[updated_project["id"]])) except: logger.exception("Error creating allocation") form.add_error( "__all__", "An unexpected error occurred. Please try again") else: form.add_error( "__all__", "There were errors processing your request. " "Please see below for details.", ) else: form = AllocationCreateForm( initial={ "description": abstract, "supplemental_details": justification, "funding_source": funding_source, }) context = { "form": form, "project": project, "alloc_id": allocation_id, "alloc": allocation, } return render(request, "projects/create_allocation.html", context)
def create_allocation(request, project_id, allocation_id=-1): mapper = ProjectAllocationMapper(request) user = mapper.get_user(request.user.username) if user["piEligibility"].lower() != "eligible": messages.error( request, "Only PI Eligible users can request allocations. If you would " "like to request PI Eligibility, please " '<a href="/user/profile/edit/">submit a PI Eligibility ' "request</a>.", ) return HttpResponseRedirect(reverse("projects:user_projects")) project = mapper.get_project(project_id) allocation = None allocation_id = int(allocation_id) if allocation_id > 0: for a in project.allocations: if a.id == allocation_id: allocation = a abstract = project.description if allocation: justification = allocation.justification else: justification = "" funding_source = [ model_to_dict(f) for f in Funding.objects.filter(project__id=project_id, is_active=True) ] # add extra form funding_source.append({}) if request.POST: form = AllocationCreateForm( request.POST, initial={ "description": abstract, "justification": justification, }, ) formset = FundingFormset( request.POST, initial=funding_source, ) consent_form = ConsentForm(request.POST) if form.is_valid() and formset.is_valid() and consent_form.is_valid(): allocation = form.cleaned_data.copy() allocation["computeRequested"] = 20000 # Also update the project and fundings project.description = allocation.pop("description", None) justification = allocation.pop("justification", None) allocation["projectId"] = project_id allocation["requestorId"] = mapper.get_portal_user_id( request.user.username) allocation["resourceId"] = "39" allocation["justification"] = justification if allocation_id > 0: allocation["id"] = allocation_id try: logger.info( "Submitting allocation request for project %s: %s" % (project.id, allocation)) with transaction.atomic(): updated_project = mapper.save_project(project.as_dict()) mapper.save_allocation(allocation, project.chargeCode, request.get_host()) new_funding_source = _save_fundings(formset, project_id) _remove_fundings(funding_source, new_funding_source) messages.success( request, "Your allocation request has been submitted!") return HttpResponseRedirect( reverse("projects:view_project", args=[updated_project["id"]])) except: logger.exception("Error creating allocation") form.add_error( "__all__", "An unexpected error occurred. Please try again") else: form.add_error( "__all__", "There were errors processing your request. " "Please see below for details.", ) else: form = AllocationCreateForm(initial={ "description": abstract, "justification": justification, }) formset = FundingFormset(initial=funding_source) consent_form = ConsentForm() context = { "form": form, "funding_formset": formset, "consent_form": consent_form, "project": project, "alloc_id": allocation_id, "alloc": allocation, } return render(request, "projects/create_allocation.html", context)
def view_project(request, project_id): mapper = ProjectAllocationMapper(request) keycloak_client = KeycloakClient() try: project = mapper.get_project(project_id) if project.source != "Chameleon": raise Http404("The requested project does not exist!") except Exception as e: logger.error(e) raise Http404("The requested project does not exist!") form = ProjectAddUserForm() nickname_form = EditNicknameForm() type_form_args = {"request": request} type_form = EditTypeForm(**type_form_args) pubs_form = AddBibtexPublicationForm() can_manage_project_membership, can_manage_project = get_user_permissions( keycloak_client, request.user.username, project) if (request.POST and can_manage_project_membership or is_admin_or_superuser(request.user)): form = ProjectAddUserForm() if "add_user" in request.POST: form = ProjectAddUserForm(request.POST) if form.is_valid(): try: add_username = form.cleaned_data["user_ref"] user = User.objects.get(username=add_username) if mapper.add_user_to_project(project, add_username): messages.success( request, f'User "{add_username}" added to project!') form = ProjectAddUserForm() except User.DoesNotExist: # Try sending an invite email_address = form.cleaned_data["user_ref"] try: validate_email(email_address) if email_exists_on_project(project, email_address): messages.error( request, "That email is tied to a user already on the " "project!", ) else: add_project_invitation( project_id, email_address, request.user, request, None, ) messages.success(request, "Invite sent!") except ValidationError: messages.error( request, ("Unable to add user. Confirm that the username " "is correct and corresponds to a current " "Chameleon user. You can also send an invite " "to an email address if the user does not yet " "have an account."), ) except Exception: messages.error( request, "Problem sending invite, please try again.") except Exception: logger.exception("Failed adding user") messages.error(request, "Unable to add user. Please try again.") else: messages.error( request, ("There were errors processing your request. " "Please see below for details."), ) elif "del_user" in request.POST: try: del_username = request.POST["user_ref"] # Ensure that it's not possible to remove the PI if del_username in [project.pi.username, project.pi.email]: raise PermissionDenied( "Removing the PI from the project is not allowed.") if mapper.remove_user_from_project(project, del_username): messages.success( request, 'User "%s" removed from project' % del_username) user = User.objects.get(username=del_username) daypass = get_daypass(user.id, project_id) if daypass: daypass.delete() except PermissionDenied as exc: messages.error(request, exc) except Exception: logger.exception("Failed removing user") messages.error( request, "An unexpected error occurred while attempting " "to remove this user. Please try again", ) elif "change_role" in request.POST: try: role_username = request.POST["user_ref"] role_name = request.POST["user_role"].lower() keycloak_client.set_user_project_role(role_username, get_charge_code(project), role_name) except Exception: logger.exception("Failed to change user role") messages.error( request, "An unexpected error occurred while attempting " "to change role for this user. Please try again", ) elif "del_invite" in request.POST: try: invite_id = request.POST["invite_id"] remove_invitation(invite_id) messages.success(request, "Invitation removed") except Exception: logger.exception("Failed to delete invitation") messages.error( request, "An unexpected error occurred while attempting " "to remove this invitation. Please try again", ) elif "resend_invite" in request.POST: try: invite_id = request.POST["invite_id"] resend_invitation(invite_id, request.user, request) messages.success(request, "Invitation resent") except Exception: logger.exception("Failed to resend invitation") messages.error( request, "An unexpected error occurred while attempting " "to resend this invitation. Please try again") elif "nickname" in request.POST: nickname_form = edit_nickname(request, project_id) elif "typeId" in request.POST: type_form = edit_type(request, project_id) for a in project.allocations: if a.start and isinstance(a.start, str): a.start = datetime.strptime(a.start, "%Y-%m-%dT%H:%M:%SZ") if a.dateRequested: if isinstance(a.dateRequested, str): a.dateRequested = datetime.strptime(a.dateRequested, "%Y-%m-%dT%H:%M:%SZ") if a.dateReviewed: if isinstance(a.dateReviewed, str): a.dateReviewed = datetime.strptime(a.dateReviewed, "%Y-%m-%dT%H:%M:%SZ") if a.end: if isinstance(a.end, str): a.end = datetime.strptime(a.end, "%Y-%m-%dT%H:%M:%SZ") users = get_project_members(project) if not project_member_or_admin_or_superuser(request.user, project, users): raise PermissionDenied user_roles = keycloak_client.get_roles_for_all_project_members( get_charge_code(project)) users_mashup = [] for u in users: if u.username == project.pi.username: continue u_role = user_roles.get(u.username, "member") user = { "id": u.id, "username": u.username, "role": u_role.title(), } try: portal_user = User.objects.get(username=u.username) user["email"] = portal_user.email user["first_name"] = portal_user.first_name user["last_name"] = portal_user.last_name # Add if the user is on a daypass existing_daypass = get_daypass(portal_user.id, project_id) if existing_daypass: user["daypass"] = format_timedelta( existing_daypass.date_exceeds_duration() - timezone.now()) except User.DoesNotExist: logger.info("user: "******" not found") users_mashup.append(user) invitations = Invitation.objects.filter(project=project_id) invitations = [i for i in invitations if i.can_accept()] clean_invitations = [] for i in invitations: new_item = {} new_item["email_address"] = i.email_address new_item["id"] = i.id new_item["status"] = i.status.title() if i.duration: new_item["duration"] = i.duration clean_invitations.append(new_item) is_on_daypass = get_daypass(request.user.id, project_id) is not None return render( request, "projects/view_project.html", { "project": project, "project_nickname": project.nickname, "project_type": project.type, "users": users_mashup, "invitations": clean_invitations, "can_manage_project_membership": can_manage_project_membership, "can_manage_project": can_manage_project, "is_admin": request.user.is_superuser, "is_on_daypass": is_on_daypass, "form": form, "nickname_form": nickname_form, "type_form": type_form, "pubs_form": pubs_form, "roles": ROLES, "host": request.get_host(), }, )