Exemple #1
0
def notify_supervisors_of_task_submission(project, participant, task,
                                          submission_info_json):
    """
    Sends an email notification to supervisors of a data project when someone
    has submitted a task.
    """

    # Convert the comma separated string of emails into a list.
    supervisor_emails = project.project_supervisors.split(",")

    # The email subject.
    subject = 'DBMI Portal - A {project} solution was submitted.'.format(
        project=project.project_key)

    context = {
        'submission_info': submission_info_json,
        'project': project,
        'task': task,
        'submitter': participant.user.email,
        'site_url': settings.SITE_URL
    }

    try:
        email_success = email_send(
            subject=subject,
            recipients=supervisor_emails,
            email_template='email_submission_uploaded_to_supervisors',
            extra=context)
    except Exception as e:
        logger.exception(e)
Exemple #2
0
def notify_task_submitters(project, participant, task, submission_info_json):
    """
    Sends an email notification to individuals involved in a submission, which may be a single
    person or a group of people under a team.
    """

    # Send an email notification to the team or individual who submitted.
    if participant.team is not None:

        # Get the submissions for this task already submitted by the team.
        total_submissions = ChallengeTaskSubmission.objects.filter(
            challenge_task=task,
            participant__in=participant.team.participant_set.all(),
            deleted=False).count()

        # Send an email notification to team members about the submission.
        emails = [
            member.user.email
            for member in participant.team.participant_set.all()
        ]

        # The email subject.
        subject = 'DBMI Portal - {project} solution submitted by your team'.format(
            project=project.project_key)

    else:
        # Get the submissions for this task already submitted by the team.
        total_submissions = ChallengeTaskSubmission.objects.filter(
            challenge_task=task, participant=participant,
            deleted=False).count()

        # Send an email notification to team members about the submission.
        emails = [participant.user.email]

        # The email subject.
        subject = 'DBMI Portal - {project} solution submitted.'.format(
            project=project.project_key)

    context = {
        'submission_info': submission_info_json,
        'project': project,
        'task': task,
        'submitter': participant.user.email,
        'max_submissions': task.max_submissions,
        'submission_count': total_submissions
    }

    try:
        email_success = email_send(subject=subject,
                                   recipients=emails,
                                   email_template='email_submission_uploaded',
                                   extra=context)
    except Exception as e:
        logger.exception(e)
Exemple #3
0
def submit_user_permission_request(request):
    """
    An HTTP POST endpoint to handle a request by a user that wants to access a project.
    Should only be used for projects that do not require teams but do require authorization.
    """

    try:
        project_key = request.POST.get('project_key', None)
        project = DataProject.objects.get(project_key=project_key)
    except ObjectDoesNotExist:
        return HttpResponse(404)

    if project.has_teams or not project.requires_authorization:
        return HttpResponse(400)

    # Create a new participant record if one does not exist already.
    participant = Participant.objects.get_or_create(
        user=request.user,
        project=project
    )

    # Check if there are administrators to notify.
    if project.project_supervisors is None or project.project_supervisors == "":
        return HttpResponse(200)

    # Convert the comma separated string of emails into a list.
    supervisor_emails = project.project_supervisors.split(",")

    subject = "DBMI Data Portal - Access requested to dataset"

    email_context = {
        'subject': subject,
        'project': project,
        'user_email': request.user.email,
        'site_url': settings.SITE_URL
    }

    try:
        email_success = email_send(
            subject=subject,
            recipients=supervisor_emails,
            email_template='email_access_request_notification',
            extra=email_context
        )
    except Exception as e:
        logger.exception(e)

    return HttpResponse(200)
Exemple #4
0
    def email_report(self, project_key, recipient, report, *args, **options):
        """
        Sends a report of the results of the operation.
        """
        # Set context
        context = {
            "operation": self.help,
            "project": project_key,
            "message": report,
        }

        # Send it out.
        success = email_send(subject=f'DBMI Portal - Operation Report',
                             recipients=[recipient],
                             email_template='email_operation_report',
                             extra=context)
        if success:
            self.stdout.write(
                self.style.SUCCESS(f"Report sent to: {recipient}"))
        else:
            self.stdout.write(
                self.style.ERROR(f"Report failed to send to: {recipient}"))
Exemple #5
0
def finalize_team(request):
    """
    An HTTP POST endpoint for team leaders to mark their team as ready and send an email notification to contest managers.
    """

    project_key = request.POST.get("project_key")
    team = request.POST.get("team")

    project = DataProject.objects.get(project_key=project_key)
    team = Team.objects.get(team_leader__email=team, data_project=project)

    if request.user.email != team.team_leader.email:
        logger.debug(
            "User {email} is not a team leader.".format(
                email=request.user.email
            )
        )
        return HttpResponse("Error: permissions.", status=403)

    team.status = 'Ready'
    team.save()

    # Convert the comma separated string of emails into a list.
    supervisor_emails = project.project_supervisors.split(",")

    context = {'team_leader': team,
               'project': project_key,
               'site_url': settings.SITE_URL}

    email_success = email_send(
        subject='DBMI Portal - Finalized Team',
        recipients=supervisor_emails,
        email_template='email_finalized_team_notification',
        extra=context
    )

    return HttpResponse(200)
Exemple #6
0
def export_task_submissions(project_id, requester):
    """
    This method fetches all current submissions for a challenge task
    and prepares an export of all files along with associated metadata.
    :param project_id: The ID of the DataProject to export submissions for
    :type project_id: str
    :param requester: The email of the admin requesting the export
    :type requester: str
    :return: Whether the operation succeeded or not
    :rtype: bool
    """
    try:
        # Get project and challenge task
        project = DataProject.objects.get(id=project_id)

        # Get all submissions made by this team for this project.
        submissions = ChallengeTaskSubmission.objects.filter(
            challenge_task__in=project.challengetask_set.all(), deleted=False)

        # Create a temporary directory
        export_uuid = export_location = None
        with tempfile.TemporaryDirectory() as directory:

            # Create directory to put submissions in
            submissions_directory_path = os.path.join(
                directory,
                f"{project.project_key}_submissions_{datetime.now().isoformat()}"
            )

            # For each submission, create a directory for the file and its metadata file
            submission_file_response = None
            for submission in submissions:
                try:
                    # Set the name of the containing directory
                    submission_directory_path = os.path.join(
                        submissions_directory_path,
                        f"{submission.participant.user.email}_{submission.uuid}"
                    )

                    # Create a record of the user downloading the file.
                    ChallengeTaskSubmissionDownload.objects.create(
                        user=User.objects.get(email=requester),
                        submission=submission)

                    # Create a temporary directory to hold the files specific to this submission that need to be zipped together.
                    if not os.path.exists(submission_directory_path):
                        os.makedirs(submission_directory_path)

                    # Create a json file with the submission info string.
                    info_file_name = "submission_info.json"
                    with open(os.path.join(submission_directory_path,
                                           info_file_name),
                              mode="w") as f:
                        f.write(submission.submission_info)

                    # Determine filename
                    try:
                        submission_file_name = json.loads(
                            submission.submission_info).get("filename")
                        if not submission_file_name:

                            # Check fileservice
                            submission_file_name = fileservice.get_archivefile(
                                submission.uuid)["filename"]
                    except Exception as e:
                        logger.exception(
                            f"Could not determine filename for submission",
                            exc_info=True,
                            extra={
                                "submission": submission,
                                "archivefile_uuid": submission.uuid,
                                "submission_info": submission.submission_info,
                            })

                        # Use a default filename
                        submission_file_name = "submission_file.zip"

                    # Get the submission file's byte contents from S3.
                    submission_file_download_url = fileservice.get_archivefile_proxy_url(
                        uuid=submission.uuid)
                    headers = {
                        "Authorization":
                        f"{settings.FILESERVICE_AUTH_HEADER_PREFIX} {settings.FILESERVICE_SERVICE_TOKEN}"
                    }
                    with requests.get(submission_file_download_url,
                                      headers=headers,
                                      stream=True) as submission_file_response:
                        submission_file_response.raise_for_status()

                        # Write the submission file's bytes to a zip file.
                        with open(os.path.join(submission_directory_path,
                                               submission_file_name),
                                  mode="wb") as f:
                            shutil.copyfileobj(submission_file_response.raw, f)

                except requests.exceptions.HTTPError as e:
                    logger.exception(
                        f"{project.project_key}: Could not download submission '{submission.uuid}': {e}",
                        extra={
                            "submission": submission,
                            "archivefile_uuid": submission.uuid,
                            "response": submission_file_response.content,
                            "status_code": submission_file_response.status_code
                        })

                except Exception as e:
                    logger.exception(
                        f"{project.project_key}: Could not export submission '{submission.uuid}': {e}",
                        exc_info=True)

            # Set the archive name
            archive_basename = f"{project.project_key}_submissions"

            # Archive the directory
            archive_path = shutil.make_archive(archive_basename, "zip",
                                               submissions_directory_path)

            # Perform the request to upload the file
            with open(archive_path, "rb") as file:

                # Build upload request
                response = None
                files = {"file": file}
                try:
                    # Create the file in Fileservice
                    metadata = {
                        "project": project.project_key,
                        "type": "export",
                    }
                    tags = [
                        "hypatio", "export", "submissions",
                        project.project_key, requester
                    ]
                    export_uuid, upload_data = fileservice.create_archivefile_upload(
                        os.path.basename(archive_path), metadata, tags)

                    # Get the location
                    export_location = upload_data["locationid"]

                    # Upload to S3
                    response = requests.post(
                        upload_data["post"]["url"],
                        data=upload_data["post"]["fields"],
                        files=files)
                    response.raise_for_status()

                    # Mark the upload as complete
                    fileservice.uploaded_archivefile(export_uuid,
                                                     export_location)

                except KeyError as e:
                    logger.error(
                        f'{project.project_key}: Failed export post generation: {upload_data}',
                        exc_info=True)
                    raise e

                except requests.exceptions.HTTPError as e:
                    logger.exception(
                        f'{project.project_key}: Failed export upload: {upload_data}',
                        extra={
                            "response": response.content,
                            "status_code": response.status_code
                        })
                    raise e

                except Exception as e:
                    logger.exception(
                        f"{project.project_key}: Could not export submissions: {e}",
                        exc_info=True,
                    )
                    raise e

        # Create the model entry for the export
        export = ChallengeTaskSubmissionExport.objects.create(
            data_project=project,
            requester=User.objects.get(email=requester),
            uuid=export_uuid,
            location=export_location,
        )

        # Set many to many fields
        export.challenge_tasks.set(project.challengetask_set.all())
        export.challenge_task_submissions.set(submissions)
        export.save()

        # Notify requester
        email_send(subject='DBMI Portal - Challenge Task Submissions Export',
                   recipients=[requester],
                   email_template='email_submissions_export_notification',
                   extra={
                       "site_url": settings.SITE_URL,
                       "project": project
                   })

    except Exception as e:
        logger.exception(f"Export challenge task submissions error: {e}",
                         exc_info=True,
                         extra={
                             "project_id": project_id,
                             "requester": requester,
                         })
        raise e
Exemple #7
0
def delete_challengetasksubmission(request):
    """
    An HTTP POST endpoint that marks a ChallengeTaskSubmission as deleted so
    it will not be counted against their total submission count for a contest.
    """

    if request.method == 'POST':

        # Check that user has permissions to be viewing files for this project.
        user_jwt = request.COOKIES.get("DBMI_JWT", None)
        sciauthz = SciAuthZ(settings.AUTHZ_BASE, user_jwt, request.user.email)

        submission_uuid = request.POST.get('submission_uuid')
        submission = ChallengeTaskSubmission.objects.get(uuid=submission_uuid)

        project = submission.participant.project

        logger.debug(
            '[delete_challengetasksubmission] - %s is trying to delete submission %s',
            request.user.email,
            submission_uuid
        )

        user_is_submitter = submission.participant.user == request.user
        user_is_manager = sciauthz.user_has_manage_permission(project.project_key)

        if project.has_teams:
            team = submission.participant.team
            user_is_team_leader = team.team_leader == request.user.email

            # Check that the user is either the team leader, the original submitter, or a manager.
            if not user_is_submitter and not user_is_team_leader and not user_is_manager:
                logger.debug(
                    "[delete_challengetasksubmission] - No Access for user %s",
                    request.user.email
                )
                return HttpResponse("Only the original submitter, team leader, or challenge manager may delete this.", status=403)

            # Prepare the email notification to send.
            emails = [member.user.email for member in team.participant_set.all()]
            subject = 'DBMI Portal - Team Submission Deleted'

        else:
            # Check that the user is either the the original submitter or a manager.
            if not user_is_submitter and not user_is_manager:
                logger.debug(
                    "[delete_challengetasksubmission] - No Access for user %s",
                    request.user.email
                )
                return HttpResponse("Only the original submitter, team leader, or challenge manager may delete this.", status=403)

            # Prepare the email notification to send.
            emails = [submission.participant.user.email]
            subject = 'DBMI Portal - Submission Deleted'

        submission.deleted = True
        submission.save()

        # Do not give away the admin's email when notifying the team
        if user_is_manager:
            deleted_by = "an admin"
        else:
            deleted_by = request.user.email

        # Send an email notification to the team
        context = {
            'deleted_by': deleted_by,
            'project': project.project_key,
            'submission_uuid': submission_uuid
        }

        email_success = email_send(
            subject=subject,
            recipients=emails,
            email_template='email_submission_deleted_notification',
            extra=context
        )

        return HttpResponse(status=200)

    return HttpResponse(status=500)
Exemple #8
0
def join_team(request):
    """
    An HTTP POST endpoint for a user to try to join a team by entering the team leader's email.
    """

    project_key = request.POST.get("project_key", None)

    try:
        project = DataProject.objects.get(project_key=project_key)
    except ObjectDoesNotExist:
        logger.error("[HYPATIO][join_team] User {email} hit the join_team api method without a project key provided.".format(
            email=request.user.email
        ))
        return redirect('/')

    team_leader = request.POST.get("team_leader", None)

    logger.debug("[HYPATIO][join_team] User {email} is requesting to join team {team} for project {project}.".format(
        email=request.user.email,
        team=team_leader,
        project=project_key
    ))

    try:
        participant = Participant.objects.get(user=request.user, project=project)
    except ObjectDoesNotExist:
        participant = Participant(user=request.user, project=project)
        participant.save()

    try:
        # If this team leader has already created a team, add the person to the team in a pending status
        team = Team.objects.get(team_leader__email__iexact=team_leader, data_project=project)

        # Only allow a new participant to join a team that is still in a pending or ready state
        if team.status in ['Pending', 'Ready']:
            participant.team = team
            participant.team_pending = True
            participant.save()
        # Otherwise, let them know why they can't join the team
        else:
            msg = "The team you are trying to join has already been finalized and is not accepting new members. " + \
                  "If you would like to join this team, please have the team leader contact the challenge " + \
                  "administrators for help."
            messages.error(request, msg)

            return redirect('/projects/' + request.POST.get('project_key') + '/')
    except ObjectDoesNotExist:
        # If this team leader has not yet created a team, mark the person as waiting
        participant.team_wait_on_leader_email = team_leader
        participant.team_wait_on_leader = True
        participant.save()
        team = None

    # Send email to team leader informing them of a pending member
    if team is not None:
        context = {'member_email': request.user.email,
                   'project': project,
                   'site_url': settings.SITE_URL}

        email_success = email_send(subject='DBMI Portal - Pending Member',
                                   recipients=[team_leader],
                                   email_template='email_pending_member_notification',
                                   extra=context)

    # Create record to allow leader access to profile.
    sciauthz = SciAuthZ(settings.AUTHZ_BASE, request.COOKIES.get("DBMI_JWT", None), request.user.email)
    sciauthz.create_profile_permission(team_leader, project_key)

    return redirect('/projects/' + request.POST.get('project_key') + '/')
Exemple #9
0
def delete_team(request):
    """
    Delete a team and notify members.
    """

    project_key = request.POST.get("project")
    team_leader = request.POST.get("team")
    administrator_message = request.POST.get("administrator_message")

    logger.debug(
        '[HYPATIO][DEBUG][delete_team] User {email} is deleting team {team} for project {project_key}.'
        .format(email=request.user.email,
                team=team_leader,
                project_key=project_key))

    project = DataProject.objects.get(project_key=project_key)

    user = request.user
    user_jwt = request.COOKIES.get("DBMI_JWT", None)

    sciauthz = SciAuthZ(settings.AUTHZ_BASE, user_jwt, user.email)
    is_manager = sciauthz.user_has_manage_permission(project.project_key)

    if not is_manager:
        logger.debug(
            '[HYPATIO][DEBUG][delete_team] User {email} does not have MANAGE permissions for item {project_key}.'
            .format(email=user.email, project_key=project.project_key))
        return HttpResponse("Error: permissions.", status=403)

    team = Team.objects.get(team_leader__email=team_leader,
                            data_project=project)

    logger.debug(
        '[HYPATIO][delete_team] Removing all VIEW permissions for team members.'
    )

    # First revoke all VIEW permissions
    for member in team.participant_set.all():
        sciauthz = SciAuthZ(settings.AUTHZ_BASE,
                            request.COOKIES.get("DBMI_JWT", None),
                            request.user.email)
        sciauthz.remove_view_permission(project_key, member.user.email)

        # Remove permission from Participant
        member.permission = None
        member.save()

    logger.debug(
        '[HYPATIO][delete_team] Sending a notification to team members.')

    # Then send a notification to the team members
    context = {
        'administrator_message': administrator_message,
        'project': project,
        'site_url': settings.SITE_URL
    }

    emails = [member.user.email for member in team.participant_set.all()]

    email_success = email_send(
        subject='DBMI Portal - Team Deleted',
        recipients=emails,
        email_template='email_team_deleted_notification',
        extra=context)

    logger.debug('[HYPATIO][delete_team] Deleting the team from the database.')

    # Then delete the team
    team.delete()

    logger.debug('[HYPATIO][delete_team] Team ' + team_leader +
                 ' for project ' + project_key + ' successfully deleted.')

    return HttpResponse(200)
Exemple #10
0
def set_team_status(request):
    """
    An HTTP POST endpoint to set a team's status, assign the correct permissions, and notify team members.
    """

    project_key = request.POST.get("project")
    team_leader = request.POST.get("team")
    status = request.POST.get("status")

    project = DataProject.objects.get(project_key=project_key)

    user = request.user
    user_jwt = request.COOKIES.get("DBMI_JWT", None)

    sciauthz = SciAuthZ(settings.AUTHZ_BASE, user_jwt, user.email)
    is_manager = sciauthz.user_has_manage_permission(project.project_key)

    logger.debug(
        '[HYPATIO][DEBUG][set_team_status] User {email} is attempting to set team {team} to status of {status} for project {project_key}.'
        .format(email=request.user.email,
                team=team_leader,
                status=status,
                project_key=project.project_key))

    if not is_manager:
        logger.debug(
            '[HYPATIO][DEBUG][set_team_status] User {email} does not have MANAGE permissions for item {project_key}.'
            .format(email=user.email, project_key=project.project_key))
        return HttpResponse("Error: permissions.", status=403)

    team = Team.objects.get(team_leader__email=team_leader,
                            data_project=project)

    # First change the team's status
    if status == "pending":
        team.status = "Pending"
        team.save()
    elif status == "ready":
        team.status = "Ready"
        team.save()
    elif status == "active":
        team.status = "Active"
        team.save()
    elif status == "deactivated":
        team.status = "Deactivated"
        team.save()
    else:
        logger.debug('[HYPATIO][set_team_status] Given status "' + status +
                     '" not one of allowed statuses.')
        return HttpResponse(500)

    # If setting to Active, grant each team member access permissions.
    if status == "active":
        for member in team.participant_set.all():
            sciauthz = SciAuthZ(settings.AUTHZ_BASE,
                                request.COOKIES.get("DBMI_JWT", None),
                                request.user.email)
            sciauthz.create_view_permission(project_key, member.user.email)

            # Add permission to Participant
            member.permission = 'VIEW'
            member.save()

    # If setting to Deactivated, revoke each team member's permissions.
    elif status == "deactivated":
        for member in team.participant_set.all():
            sciauthz = SciAuthZ(settings.AUTHZ_BASE,
                                request.COOKIES.get("DBMI_JWT", None),
                                request.user.email)
            sciauthz.remove_view_permission(project_key, member.user.email)

            # Remove permission from Participant
            member.permission = None
            member.save()

    # Send an email notification to the team
    context = {
        'status': status,
        'project': project,
        'site_url': settings.SITE_URL
    }

    # Email list
    emails = [member.user.email for member in team.participant_set.all()]

    email_success = email_send(
        subject='DBMI Portal - Team Status Changed',
        recipients=emails,
        email_template='email_new_team_status_notification',
        extra=context)

    return HttpResponse(200)
Exemple #11
0
def change_signed_form_status(request):
    """
    An HTTP POST endpoint for changing a signed form's status and notifying the user.
    """

    status = request.POST.get("status")
    form_id = request.POST.get("form_id")
    administrator_message = request.POST.get("administrator_message")

    logger.debug('[HYPATIO][change_signed_form_status] ' + request.user.email +
                 ' try to change status for signed form ' + form_id + ' to ' +
                 status + '.')

    signed_form = get_object_or_404(SignedAgreementForm, id=form_id)
    affected_user = signed_form.user

    user = request.user
    user_jwt = request.COOKIES.get("DBMI_JWT", None)
    project = signed_form.project

    sciauthz = SciAuthZ(settings.AUTHZ_BASE, user_jwt, user.email)
    is_manager = sciauthz.user_has_manage_permission(project.project_key)

    if not is_manager:
        logger.debug(
            '[HYPATIO][DEBUG][change_signed_form_status] User {email} does not have MANAGE permissions for item {project_key}.'
            .format(email=user.email, project_key=project.project_key))
        return HttpResponse("Error: permissions.", status=403)

    # First change the team's status
    if status == "approved":
        signed_form.status = 'A'
        signed_form.save()
    elif status == "rejected":
        signed_form.status = 'R'
        signed_form.save()

        logger.debug(
            '[HYPATIO][change_signed_form_status] Emailing a rejection notification to the affected participant'
        )

        # Send an email notification to the affected person
        context = {
            'signed_form': signed_form,
            'administrator_message': administrator_message,
            'site_url': settings.SITE_URL
        }

        email_success = email_send(
            subject='DBMI Portal - Signed Form Rejected',
            recipients=[affected_user.email],
            email_template='email_signed_form_rejection_notification',
            extra=context)

        # If the user is a participant on a team, then the team status may need to be changed
        try:
            participant = Participant.objects.get(user=affected_user,
                                                  project=signed_form.project)
            team = participant.team
        except ObjectDoesNotExist:
            participant = None
            team = None

        # If the team is in an Active status, move the team status down to Ready and remove everyone's VIEW permissions
        if team is not None and team.status == "Active":
            team.status = "Ready"
            team.save()

            for member in team.participant_set.all():
                sciauthz = SciAuthZ(settings.AUTHZ_BASE,
                                    request.COOKIES.get("DBMI_JWT", None),
                                    request.user.email)
                sciauthz.remove_view_permission(
                    signed_form.project.project_key, member.user.email)

                # Remove their VIEW permission
                member.permission = None
                member.save()

            logger.debug(
                '[HYPATIO][change_signed_form_status] Emailing the whole team that their status has been moved to Ready because someone has a pending form'
            )

            # Send an email notification to the team
            context = {
                'status': "ready",
                'reason':
                'Your team has been temporarily disabled because of an issue with a team members\' forms. Challenge administrators will resolve this shortly.',
                'project': signed_form.project,
                'site_url': settings.SITE_URL
            }

            # Email list
            emails = [
                member.user.email for member in team.participant_set.all()
            ]

            email_success = email_send(
                subject='DBMI Portal - Team Status Changed',
                recipients=emails,
                email_template='email_new_team_status_notification',
                extra=context)
    else:
        logger.debug('[HYPATIO][change_signed_form_status] Given status "' +
                     status + '" not one of allowed statuses.')
        return HttpResponse(500)

    return HttpResponse(200)
Exemple #12
0
def grant_view_permission(request, project_key, user_email):
    """
    Grants a user VIEW permissions to a project in DBMI-AuthZ.
    """

    user = get_object_or_404(User, email=user_email)
    project = get_object_or_404(DataProject, project_key=project_key)

    # Check Permissions in SciAuthZ
    user_jwt = request.COOKIES.get("DBMI_JWT", None)
    sciauthz = SciAuthZ(settings.AUTHZ_BASE, user_jwt, request.user.email)
    is_manager = sciauthz.user_has_manage_permission(project_key)

    logger.debug(
        '[HYPATIO][DEBUG][grant_view_permission] User {user} is attempting to grant VIEW permissions to participant {participant} for project {project_key}.'
        .format(user=request.user.email,
                participant=user_email,
                project_key=project_key))

    if not is_manager:
        logger.error(
            '[HYPATIO][DEBUG][grant_view_permission] User {user} does not have manage permissions to project {project_key}.'
            .format(user=request.user.email, project_key=project_key))
        return HttpResponse("Access denied.", status=403)

    sciauthz.create_view_permission(project_key, user_email)

    # Add permission to their Participant row
    try:
        participant = project.participant_set.get(user__email=user_email)
        participant.permission = 'VIEW'
        participant.save()
    except Exception as e:
        logger.exception(
            '[HYPATIO][DEBUG][grant_view_permission] User {user} could not have permission added to project {project_key}: {e}'
            .format(
                user=request.user.email,
                project_key=project_key,
                e=e,
            ),
            exc_info=True,
            extra={
                'manager': request.user.email,
                'participant': user_email,
                'project': project_key
            })

    subject = "DBMI Data Portal - Access granted to dataset"

    email_context = {
        'subject': subject,
        'project': project,
        'site_url': settings.SITE_URL
    }

    try:
        email_success = email_send(
            subject=subject,
            recipients=[user_email],
            email_template='email_access_granted_notification',
            extra=email_context)
    except Exception as e:
        logger.exception(e)

    return HttpResponse("Access granted")