Example #1
0
def save_team_comment(request):
    """
    An HTTP POST endpoint for saving a comment made about a team by a challenge administrator.
    """

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

    logger.debug('[HYPATIO][save_team_comment] ' + request.user.email +
                 ' entered a comment about team ' + team_leader + '.')

    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][save_team_comment] 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)

    new_comment = TeamComment(user=request.user, team=team, text=comment)
    new_comment.save()

    return HttpResponse(200)
Example #2
0
    def dispatch(self, request, *args, **kwargs):
        """
        Sets up the instance.
        """

        # Get the project key from the URL.
        project_key = self.kwargs['project_key']

        try:
            self.project = DataProject.objects.get(project_key=project_key)
        except ObjectDoesNotExist:
            error_message = "The project you searched for does not exist."
            return render(request, '404.html', {'error_message': error_message})

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

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

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

        return super(DataProjectManageView, self).dispatch(request, *args, **kwargs)
Example #3
0
def export_submissions(request, project_key):
    """
    An HTTP GET endpoint that allows a user to download a ChallengeTaskSubmission's
    file from AWS/fileservice.
    """

    if request.method == "GET":

        # 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)

        if not is_manager:
            logger.debug("[download_team_submissions] - No Access for user " +
                         request.user.email)
            return HttpResponse(
                "You do not have access to download this file.", status=403)

        project = get_object_or_404(DataProject, project_key=project_key)

        # Run the task
        async_task('manage.tasks.export_task_submissions', project.id,
                   request.user.email)

        # Prepare the zip file to be served.
        return HttpResponse(status=201)
Example #4
0
def get_signed_form_status(request):
    """
    An HTTP POST endpoint for fetching a signed form's status.
    """
    form_id = request.POST.get("form_id")

    logger.debug(f'[get_signed_form_status] {request.user.email} -> {form_id}')

    # Get the form
    signed_form = get_object_or_404(SignedAgreementForm, id=form_id)

    # Confirm permissions on project form was signed for
    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)

    return HttpResponse(signed_form.status, status=200)
Example #5
0
def get_hosted_file_logs(request):
    """
    An HTTP GET endpoint for requests to get logs of an existing HostedFile.
    """

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

    project_key = request.GET.get("project-key")
    project = get_object_or_404(DataProject, project_key=project_key)

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

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

    hosted_file_uuid = request.GET.get("hosted-file-uuid")

    try:
        hosted_file = HostedFile.objects.get(project=project,
                                             uuid=hosted_file_uuid)
    except ObjectDoesNotExist:
        logger.debug(
            '[HYPATIO][DEBUG][get_hosted_file_logs] User {email} does not have MANAGE permissions for item {project_key}.'
            .format(email=user.email, project_key=project_key))
        return HttpResponse("Error: file not found.", status=404)
    except Exception as e:
        logger.exception(
            '[HYPATIO][EXCEPTION][get_hosted_file_logs] Could not perform fetch for '
            'file download logs: {e}.'.format(e=e),
            exc_info=True,
            extra={
                'user': user.email,
                'project': project_key,
                'hosted_file': hosted_file_uuid
            })
        return HttpResponse("Error: fetch failed with error", status=500)

    response_html = render_to_string(
        'manage/hosted-file-logs.html',
        context={
            'downloads': [
                HostedFileDownloadSerializer(downloads).data
                for downloads in hosted_file.hostedfiledownload_set.all().
                order_by('download_date')
            ],
            'file':
            HostedFileSerializer(hosted_file).data,
        },
        request=request)
    return HttpResponse(response_html)
Example #6
0
def download_signed_form(request):
    """
    An HTTP GET endpoint that returns a text file to the user containing the signed form's content.
    """

    form_id = request.GET.get("form_id")

    logger.debug('[HYPATIO][download_signed_form] ' + request.user.email +
                 ' is trying to download signed form ' + form_id + '.')

    signed_form = get_object_or_404(SignedAgreementForm, id=form_id)

    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][download_signed_form] 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)

    # Set details of the file download
    affected_user = signed_form.user
    date_as_string = datetime.strftime(signed_form.date_signed, "%Y%m%d-%H%M")

    # Check type
    if signed_form.agreement_form.type == AGREEMENT_FORM_TYPE_FILE:

        # Download the file
        file = signed_form.upload.open(mode="rb").read()

        # Determine MIME
        mime = magic.from_buffer(file, mime=True)

        # Get the signed URL for the file in S3
        filename = signed_form.upload.name
        response = HttpResponse(file, content_type=mime)
        response['Content-Disposition'] = f'attachment; filename={filename}'

    else:

        filename = affected_user.email + '-' + signed_form.agreement_form.short_name + '-' + date_as_string + '.txt'
        response = HttpResponse(signed_form.agreement_text,
                                content_type='text/plain')
        response['Content-Disposition'] = f'attachment; filename={filename}'

    return response
Example #7
0
def set_dataproject_details(request):
    """
    An HTTP POST endpoint for setting some details about a DataProject.
    """

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

    project_key = request.POST.get("project_key")
    project = get_object_or_404(DataProject, project_key=project_key)

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

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

    name = request.POST.get("name", "")
    short_description = request.POST.get("short-description", "")
    description = request.POST.get("description", "")

    if name == "":
        return HttpResponse("Error: project name required.", status=400)
    if short_description == "":
        return HttpResponse("Error: project short description required.",
                            status=400)
    if description == "":
        return HttpResponse("Error: project description required.", status=400)

    project.name = name
    project.short_description = short_description
    project.description = description

    try:
        project.save()
    except Exception as ex:
        return HttpResponse("Error: project details failed to save.",
                            status=400)

    response_html = render_to_string('manage/project-details.html',
                                     context={
                                         'project': project,
                                         'message': "Changes saved!"
                                     })

    return HttpResponse(response_html)
Example #8
0
def remove_view_permission(request, project_key, user_email):
    """
    Removes a user's VIEW permission 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][remove_view_permission] User {user} is attempting to remove VIEW permissions from 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][remove_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.remove_view_permission(project_key, user_email)

    # Remove permission from their Participant
    try:
        participant = project.participant_set.get(user__email=user_email)
        participant.permission = None
        participant.save()
    except Exception as e:
        logger.exception(
            '[HYPATIO][ERROR][grant_view_permission] User {user} could not have permission remove from 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
            })

    return HttpResponse("Access removed")
Example #9
0
    def get_context_data(self, **kwargs):
        """
        Dynamically builds the context for rendering the view based on information
        about the user and the DataProject.
        """

        # Get super's context. This is the dictionary of variables for the base template being rendered.
        context = super(DataProjectListManageView, self).get_context_data(**kwargs)

        user_jwt = self.request.COOKIES.get("DBMI_JWT", None)
        sciauthz = SciAuthZ(settings.AUTHZ_BASE, user_jwt, self.request.user.email)
        projects_managed = sciauthz.get_projects_managed_by_user()

        context['projects'] = projects_managed

        return context
Example #10
0
def get_static_agreement_form_html(request):
    """
    An HTTP GET endpoint for Intercooler.js requests to get the HTML contents of an
    agreement form file and return them as HTML.
    """

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

    project_key = request.GET.get("project-key")
    project = get_object_or_404(DataProject, project_key=project_key)

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

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

    agreement_form_id = request.GET.get('form-id', "")

    try:
        agreement_form = project.agreement_forms.get(id=agreement_form_id)
    except ObjectDoesNotExist:
        return HttpResponse("Error: form not found.", status=404)

    if agreement_form.type == AGREEMENT_FORM_TYPE_MODEL:
        if agreement_form.content is None or agreement_form.content == "":
            return HttpResponse("Error: form content is missing.", status=400)

        form_contents = agreement_form.content
    elif agreement_form.type == AGREEMENT_FORM_TYPE_FILE:
        if agreement_form.content is None or agreement_form.content == "":
            return HttpResponse("Error: form content is missing.", status=400)

        form_contents = agreement_form.upload
    else:
        if agreement_form.form_file_path is None or agreement_form.form_file_path == "":
            return HttpResponse("Error: form file path is missing.",
                                status=400)

        form_contents = projects_extras.get_html_form_file_contents(
            agreement_form.form_file_path)

    return HttpResponse(form_contents)
Example #11
0
def signed_agreement_form(request):

    project_key = request.GET['project_key']
    signed_agreement_form_id = request.GET['signed_form_id']

    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)

    project = get_object_or_404(DataProject, project_key=project_key)
    signed_form = get_object_or_404(SignedAgreementForm,
                                    id=signed_agreement_form_id,
                                    project=project)

    try:
        participant = Participant.objects.get(project=project,
                                              user=signed_form.user)
    except ObjectDoesNotExist:
        participant = None

    # Get fields, if applicable. It sucks that these are hard-coded but until we
    # find a better solution and have more time, this is it.
    signed_agreement_form_fields = {}

    if is_manager or signed_form.user == request.user:
        template_name = "projects/participate/view-signed-agreement-form.html"
        filled_out_signed_form = None

        return render(
            request, template_name, {
                "user": request.user,
                "ssl_setting": settings.SSL_SETTING,
                "is_manager": is_manager,
                "signed_form": signed_form,
                "filled_out_signed_form": filled_out_signed_form,
                "signed_agreement_form_fields": signed_agreement_form_fields,
                "participant": participant
            })
    else:
        return HttpResponse(403)
Example #12
0
def download_submission(request, fileservice_uuid):
    """
    An HTTP GET endpoint that allows a user to download a ChallengeTaskSubmission's
    file from AWS/fileservice.
    """

    if request.method == "GET":

        submission = get_object_or_404(ChallengeTaskSubmission,
                                       uuid=fileservice_uuid)
        project = submission.challenge_task.data_project

        # 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.project_key)

        if not is_manager:
            logger.debug("[download_submission] - No Access for user " +
                         request.user.email)
            return HttpResponse(
                "You do not have access to download this file.", status=403)

        # Download the submission file from fileservice and zip it up with the info json.
        zip_file_path = zip_submission_file(submission, request.user.email,
                                            request)
        zip_file_name = os.path.basename(zip_file_path)

        # Prepare the zip file to be served.
        final_zip_file = open(zip_file_path, 'rb')
        response = HttpResponse(final_zip_file,
                                content_type='application/force-download')
        response[
            'Content-Disposition'] = 'attachment; filename="%s"' % zip_file_name

        # Delete the directory containing the zip file.
        shutil.rmtree(os.path.dirname(os.path.realpath((zip_file_path))))

        return response
Example #13
0
def download_submissions_export(request, project_key, fileservice_uuid):
    """
    An HTTP GET endpoint that allows a user to download a ChallengeTask's
    submissions export file from AWS/fileservice.
    """
    if request.method == "GET":

        # 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)

        if not is_manager:
            logger.debug(
                "[download_submissions_export] - No Access for user " +
                request.user.email)
            return HttpResponse(
                "You do not have access to download this file.", status=403)

        # Get filename
        filename = f"{project_key}_export_{fileservice_uuid}.zip"

        # Get the url
        url = fileservice.get_archivefile_download_url(fileservice_uuid)

        # Prepare the parts
        protocol = urlparse(url).scheme
        path = urllib.parse.quote_plus(url.replace(protocol + '://', ''))

        # Let NGINX handle it
        response = HttpResponse()
        response['X-Accel-Redirect'] = '/proxy/' + protocol + '/' + path
        response['Content-Disposition'] = 'attachment; filename="{}"'.format(
            filename)

        logger.debug(
            f'Sending user to S3 proxy: {response["X-Accel-Redirect"]}')

        return response
Example #14
0
def get_hosted_file_edit_form(request):
    """
    An HTTP GET endpoint for requests to get an HTML form for editing an
    existing HostedFile.
    """

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

    project_key = request.GET.get("project-key")
    project = get_object_or_404(DataProject, project_key=project_key)

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

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

    hosted_file_uuid = request.GET.get("hosted-file-uuid")

    try:
        hosted_file = HostedFile.objects.get(project=project,
                                             uuid=hosted_file_uuid)
    except ObjectDoesNotExist:
        return HttpResponse("Error: file not found.", status=404)

    edit_hosted_file_form = EditHostedFileForm(instance=hosted_file)

    response_html = render_to_string('manage/edit-hosted-file-form.html',
                                     context={
                                         'form': edit_hosted_file_form,
                                         'file': hosted_file
                                     },
                                     request=request)
    return HttpResponse(response_html)
Example #15
0
def set_dataproject_visible_status(request):
    """
    An HTTP POST endpoint for making a DataProject publicly visible or not.
    """

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

    project_key = request.POST.get("project_key")
    project = get_object_or_404(DataProject, project_key=project_key)

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

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

    visibile_status = request.POST.get("visible_status")

    if visibile_status == "visible":
        project.visible = True
    elif visibile_status == "invisible":
        project.visible = False
    else:
        return HttpResponse("Error: Invalid status.", status=400)

    project.save()

    response_html = render_to_string('manage/visible-status.html',
                                     context={
                                         'project': project,
                                     })

    return HttpResponse(response_html)
Example #16
0
def sync_view_permissions(request, project_key):
    """
    Pulls all permissions from DBMI-AuthZ and syncs those with VIEW permission to the Participant model
    """
    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 sync VIEW permissions for project {project_key}.'
        .format(user=request.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)

    # Get the emails of all those currently containing VIEW permissions in AuthZ for this project
    permitted_emails = sciauthz.get_all_view_permissions_for_project(
        project=project_key)

    # Iterate participants
    for participant in project.participant_set.all():

        # Check if they have permission
        if participant.user.email.lower(
        ) in permitted_emails and participant.permission != 'VIEW':

            # Set it
            participant.permission = 'VIEW'
            participant.save()

    return HttpResponse(status=200)
Example #17
0
def set_dataproject_registration_status(request):
    """
    An HTTP POST endpoint for opening or closing registration to a DataProject.
    """

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

    project_key = request.POST.get("project_key")
    project = get_object_or_404(DataProject, project_key=project_key)

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

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

    registration_status = request.POST.get("registration_status")

    if registration_status == "open":
        project.registration_open = True
    elif registration_status == "close":
        project.registration_open = False
    else:
        return HttpResponse("Error: invalid status.", status=400)

    project.save()

    response_html = render_to_string('manage/registration-status.html',
                                     context={
                                         'project': project,
                                     })

    return HttpResponse(response_html)
Example #18
0
def process_hosted_file_edit_form_submission(request):
    """
    An HTTP POST endpoint for processing a submitted form for editing a hosted file.
    """

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

    file_uuid = request.POST.get("file-uuid")
    project_id = request.POST.get("project")
    project = get_object_or_404(DataProject, id=project_id)

    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][get_static_agreement_form_html] 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)

    hosted_file = HostedFile.objects.get(project=project, uuid=file_uuid)
    edit_hosted_file_form = EditHostedFileForm(request.POST,
                                               instance=hosted_file)

    # TODO show error messages
    if not edit_hosted_file_form.is_valid():
        return HttpResponse(edit_hosted_file_form.errors.as_json(), status=400)

    try:
        edit_hosted_file_form.save()
    except Exception:
        # TODO do something on failure
        return HttpResponse("Error: failed to save object", status=500)

    return HttpResponse("File updated.", status=200)
Example #19
0
class DataProjectManageView(TemplateView):
    """
    Builds and renders the screen for special users to manage a DataProject.
    """

    project = None
    template_name = 'manage/project-base.html'
    sciauthz = None

    def dispatch(self, request, *args, **kwargs):
        """
        Sets up the instance.
        """

        # Get the project key from the URL.
        project_key = self.kwargs['project_key']

        try:
            self.project = DataProject.objects.get(project_key=project_key)
        except ObjectDoesNotExist:
            error_message = "The project you searched for does not exist."
            return render(request, '404.html', {'error_message': error_message})

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

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

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

        return super(DataProjectManageView, self).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        """
        Dynamically builds the context for rendering the view based on information
        about the user and the DataProject.
        """

        # Get super's context. This is the dictionary of variables for the base template being rendered.
        context = super(DataProjectManageView, self).get_context_data(**kwargs)

        context['project'] = self.project

        # Collect all user information from SciReg.
        # TODO ...

        # Get counts of downloads by isolating which files this project has, grouping by user email, and counting on those emails.
        user_download_counts = HostedFileDownload.objects\
            .filter(hosted_file__project=self.project)\
            .values('user__email')\
            .annotate(user_downloads=Count('user__email'))

        # Convert the download count queryset into a simple dictionary for quicker access later.
        user_download_counts_dict = {}
        for user in user_download_counts:
            user_download_counts_dict[user['user__email']] = user['user_downloads']

        # Get how many challengetasks a user has submitted for this project.
        user_upload_counts = ChallengeTaskSubmission.objects\
            .filter(challenge_task__data_project=self.project)\
            .values('participant__user__email')\
            .annotate(user_uploads=Count('participant__user__email'))

        # If there are teams, calculate downloads and uploads by team members.
        if self.project.has_teams:

            teams = []
            for team in self.project.team_set.all():

                # Allow hiding of teams
                team_hidden = False

                team_downloads = 0
                team_uploads = 0

                for participant in team.participant_set.all():
                    try:
                        team_downloads += user_download_counts_dict[participant.user.email]
                    except KeyError:
                        team_downloads += 0

                    try:
                        team_uploads += user_upload_counts.get(participant__user__email=participant.user.email)['user_uploads']
                    except ObjectDoesNotExist:
                        team_uploads += 0

                    # If this is a project that is using shared teams, determine if this team should be hidden or not
                    # This is required since shared teams don't implicitly have all forms completed.
                    if self.project.hide_incomplete_teams and self.project.teams_source and not team_hidden:

                        # Get all related signed agreement forms
                        signed_agreement_forms = SignedAgreementForm.objects.filter(
                            Q(user=participant.user, agreement_form__in=self.project.agreement_forms.all()) &
                            (Q(project=self.project) | Q(project__shares_agreement_forms=True))
                        )

                        # Compare number of agreement forms
                        if len(signed_agreement_forms) < len(self.project.agreement_forms.all()):
                            logger.debug(f"{self.project.project_key}/{team.id}/{participant.user.email}: {len(signed_agreement_forms)} SignedAgreementForms: HIDDEN")
                            team_hidden = True

                if not team_hidden:
                    teams.append({
                        'team_leader': team.team_leader.email,
                        'member_count': team.participant_set.all().count(),
                        'status': team.status,
                        'downloads': team_downloads,
                        'submissions': team_uploads,
                    })

            context['teams'] = teams

            approved_teams = list(filter(lambda team: team['status']=='Active', teams))
            approved_participants = Participant.objects.filter(team__in=self.project.team_set.filter(status='Active'))
            all_submissions = ChallengeTaskSubmission.objects.filter(
                participant__in=approved_participants,
                deleted=False
            )
            teams_with_any_submission = all_submissions.values('participant__team').distinct()
            user_jwt = self.request.COOKIES.get("DBMI_JWT", None)
            countries = get_distinct_countries_participating(user_jwt, approved_participants, self.project.project_key)

            context["approved_teams"] = approved_teams
            context["approved_participants"] = approved_participants
            context["total_submissions"] = all_submissions
            context["teams_with_any_submission"] = teams_with_any_submission
            context["participating_countries"] = countries


        # Collect all submissions made for tasks related to this project.
        context['submissions'] = ChallengeTaskSubmission.objects.filter(
            challenge_task__in=self.project.challengetask_set.all(),
            deleted=False
        )

        # Collect all submissions made for tasks related to this project.
        for export in ChallengeTaskSubmissionExport.objects.filter(
            data_project=self.project,
        ).order_by("-request_date"):
            export.download_url = fileservice.get_archivefile_proxy_url(uuid=export.uuid)

            # Add it to context
            context.setdefault('submissions_exports', []).append(export)

        context['num_required_forms'] = self.project.agreement_forms.count()

        # Get information about what files there are for this project.
        context['file_groups'] = []

        for file_set in self.project.hostedfileset_set.all().order_by(F('order').asc(nulls_last=True)):
            context['file_groups'].append({
                'group_name': file_set.title,
                'files': file_set.hostedfile_set.all().order_by(F('order').asc(nulls_last=True))
            })

        # Add another panel for files that do not belong to a HostedFileSet
        files_without_a_set = HostedFile.objects.filter(
            project=self.project,
            hostedfileset=None
        )

        if files_without_a_set.count() > 0:
            # If there are no other groups, then make the group title less confusing.
            group_name = 'Files' if not context['file_groups'] else 'Other files'

            context['file_groups'].append({
                'group_name': group_name,
                'files': files_without_a_set.order_by(F('order').asc(nulls_last=True))
            })

        return context
Example #20
0
def download_team_submissions(request, project_key, team_leader_email):
    """
    An HTTP GET endpoint that handles downloads of participant submission files. Checks
    that the requesting user has proper permissions to access this file. Downloads all
    of the team's submissions into one zip file, with each submission in it's own zip
    file containing a json file with metadata about the upload.
    """
    logger.debug('download_team_submissions: {}'.format(request.method))

    if request.method == "GET":

        # 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)

        if not is_manager:
            logger.debug("[download_team_submissions] - No Access for user " +
                         request.user.email)
            return HttpResponse(
                "You do not have access to download this file.", status=403)

        project = get_object_or_404(DataProject, project_key=project_key)
        team = get_object_or_404(Team,
                                 data_project=project,
                                 team_leader__email=team_leader_email)

        # A list of file paths to each submission's zip file.
        zipped_submissions_paths = []

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

        # For each submission, create a zip file and add the path to the list of zip files.
        for submission in submissions:
            zip_file_path = zip_submission_file(submission, request.user.email,
                                                request)
            zipped_submissions_paths.append(zip_file_path)

        # Create a directory to store the final encompassing zip file.
        final_zip_file_directory = "/tmp/" + str(uuid.uuid4())
        if not os.path.exists(final_zip_file_directory):
            os.makedirs(final_zip_file_directory)

        # Combine all the zipped tasks into one file zip file.
        final_zip_file_name = project_key + "__team-submissions__" + team_leader_email + ".zip"
        final_zip_file_path = os.path.join(final_zip_file_directory,
                                           final_zip_file_name)
        with zipfile.ZipFile(final_zip_file_path, mode="w") as zf:
            for zip_file in zipped_submissions_paths:
                zf.write(zip_file, arcname=os.path.basename(zip_file))

        # Prepare the zip file to be served.
        final_zip_file = open(final_zip_file_path, 'rb')
        response = HttpResponse(final_zip_file,
                                content_type='application/force-download')
        response[
            'Content-Disposition'] = 'attachment; filename="%s"' % final_zip_file_name

        # Delete all the directories holding the zip files.
        for path in zipped_submissions_paths:
            shutil.rmtree(os.path.dirname(os.path.realpath((path))))

        # Delete the final zip file.
        shutil.rmtree(final_zip_file_directory)

        return response
Example #21
0
def upload_challengetasksubmission_file(request):
    """
    On a POST, send metadata about the user's file to fileservice to get back an S3 upload link.
    On a PATCH, check to see that the file successfully was uploaded to S3 and then create a new
    ChallengeTaskSubmission record.
    """

    if request.method == 'POST':
        logger.debug('post')

        # Assembles the form and runs validation.
        filename = request.POST.get('filename')
        project_key = request.POST.get('project_key')
        task_id = request.POST.get('task_id')

        if not filename or not project_key or not task_id:
            logger.error('No filename, project, or task!')
            return HttpResponse('Filename, project, task are required', status=400)

        project = get_object_or_404(DataProject, project_key=project_key)

        # If the project requires authorization to access, check for permissions before allowing submission
        if project.requires_authorization:

            # Get their permission for this project
            has_permission = False
            try:
                participant = Participant.objects.get(user=request.user, project=project)
                has_permission = participant.permission == "VIEW"
                if not has_permission:
                    logger.debug(f"[{project_key}][{request.user.email}] No  VIEW access for user")
            except ObjectDoesNotExist as e:
                logger.exception(f"Participant does not exist", exc_info=False, extra={
                    "request": request, "project": project_key, "user": request.user,
                })

            # Check AuthZ
            if not has_permission:
                logger.warning(
                    f"[{project_key}][{request.user.email}] Local permission "
                    f"does not exist, checking DBMI AuthZ for "
                )

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

                if not sciauthz.user_has_single_permission(project_key, "VIEW", request.user.email):
                    logger.warning(f"[{project_key}][{request.user.email}] No Access")
                    return HttpResponse("You do not have access to upload this file.", status=403)

        if filename.split(".")[-1] != "zip":
            logger.error('Not a zip file.')
            return HttpResponse("Only .zip files are accepted", status=400)

        try:
            task = ChallengeTask.objects.get(id=task_id)
        except exceptions.ObjectDoesNotExist:
            logger.error('Task not found with id {id}'.format(id=task_id))
            return HttpResponse('Task not found', status=400)

        # Only allow a submission if the task is still open.
        if not projects_extras.is_challengetask_currently_enabled(task):
            logger.error("[upload_challengetasksubmission_file] - User " + request.user.email + " is trying to submit task " + task.title + " after close time.")
            return HttpResponse("This task is no longer open for submissions", status=400)

        # Prepare the metadata.
        metadata = {
            'project': project_key,
            'task': task.title,
            'uploader': request.user.email,
            'type': 'project_submission',
            'app': 'hypatio',
        }

        # Create a new record in fileservice for this file and get back information on where it should live in S3.
        uuid, response = fileservice.create_file(request, filename, metadata)
        post = response['post']
        location = response['locationid']

        # Form the data for the File object.
        file = {'uuid': uuid, 'location': location, 'filename': filename}
        logger.debug('File: {}'.format(file))

        response = {
            'post': post,
            'file': file,
        }
        logger.debug('Response: {}'.format(post))

        return JsonResponse(data=response)

    elif request.method == 'PATCH':
        logger.debug('patch')

        # Get the data.
        data = QueryDict(request.body)
        logger.debug('Data: {}'.format(data))

        try:
            # Prepare a json that holds information about the file and the original submission form.
            # This is used later as included metadata when downloading the participant's submission.
            submission_info = copy(data)

            # Get the participant.
            project = get_object_or_404(DataProject, project_key=submission_info['project_key'])
            participant = get_object_or_404(Participant, user=request.user, project=project)
            task = get_object_or_404(ChallengeTask, id=submission_info['task_id'])

            # Get the team, although it could be None for projects with no teams.
            team = participant.team

            # Remove a few unnecessary fields.
            del submission_info['csrfmiddlewaretoken']
            del submission_info['location']

            # Add some more fields
            submission_info['submitted_by'] = request.user.email

            if participant.team is not None:
                submission_info['team_leader'] = participant.team.team_leader.email

            submission_info['task'] = task.title
            submission_info['submitted_on'] = datetime.strftime(datetime.now(), "%Y%m%d_%H%M") + " (UTC)"

            submission_info_json = json.dumps(submission_info, indent=4)

            # Create the object and save UUID and location for future downloads.
            ChallengeTaskSubmission.objects.create(
                challenge_task=task,
                participant=participant,
                uuid=data['uuid'],
                location=data['location'],
                submission_info=submission_info_json
            )

            # Send an email notification to the submitters.
            notify_task_submitters(project, participant, task, submission_info_json)

            # If the task is configured to send notifications to supervisors, do so.
            if task.notify_supervisors_of_submissions:
                notify_supervisors_of_task_submission(project, participant, task, submission_info_json)

            # Make the request to FileService.
            if not fileservice.uploaded_file(request, data['uuid'], data['location']):
                logger.error('[participants][FilesView][post] FileService uploadCompleted failed!')
            else:
                logger.debug('FileService updated of file upload')

            return HttpResponse(status=200)

        except exceptions.ObjectDoesNotExist as e:
            logger.exception(e)
            return HttpResponse(status=404)
        except Exception as e:
            logger.exception(e)
            return HttpResponse(status=500)
    else:
        return HttpResponse("Invalid method", status=403)
Example #22
0
def download_email_list(request):
    """
    Downloads a text file containing the email addresses of participants of a given project
    with filters accepted as GET parameters. Accepted filters include: team, team status,
    agreement form ID, and agreement form status.
    """

    logger.debug(
        "[views_manage][download_email_list] - Attempting file download.")

    project_key = request.GET.get("project")
    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)

    if not is_manager:
        logger.debug(
            "[views_manage][download_email_list] - No Access for user " +
            request.user.email)
        return HttpResponse("You do not have access to download this file.",
                            status=403)

    # Filters used to determine the list of participants
    filter_team = request.GET.get("team-id", None)
    filter_team_status = request.GET.get("team-status", None)
    filter_signed_agreement_form = request.GET.get("agreement-form-id", None)
    filter_signed_agreement_form_status = request.GET.get(
        "agreement-form-status", None)

    # Apply filters that narrow the scope of teams
    teams = Team.objects.filter(data_project=project)

    if filter_team:
        teams = teams.filter(id=filter_team)
    if filter_team_status:
        teams = teams.filter(status=filter_team_status)

    # Apply filters that narrow the list of participants
    participants = Participant.objects.filter(team__in=teams)

    if filter_signed_agreement_form:
        agreement_form = AgreementForm.objects.get(
            id=filter_signed_agreement_form)

        # Find all signed instances of this form
        signed_forms = SignedAgreementForm.objects.filter(
            agreement_form=agreement_form)
        if filter_signed_agreement_form_status:
            signed_forms = signed_forms.filter(
                status=filter_signed_agreement_form_status)

        # Narrow down the participant list with just those who have these signed forms
        signed_forms_users = signed_forms.values_list('user', flat=True)
        participants = participants.filter(user__in=signed_forms_users)

    # Query SciReg to get a dictionary of first and last names for each participant
    names = json.loads(get_names(user_jwt, participants, project_key))

    # Build a string that will be the contents of the file
    file_contents = ""
    for participant in participants:

        first_name = ""
        last_name = ""

        # Look in our dictionary of names from SciReg for this participant
        try:
            name = names[participant.user.email]
            first_name = name['first_name']
            last_name = name['last_name']
        except (KeyError, IndexError):
            pass

        file_contents += participant.user.email + " " + first_name + " " + last_name + "\n"

    response = HttpResponse(file_contents, content_type='text/plain')
    response[
        'Content-Disposition'] = 'attachment; filename="%s"' % 'pending_participants.txt'

    return response
Example #23
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)
Example #24
0
def manage_team(request, project_key, team_leader, template_name='manage/team.html'):
    """
    Populates the team management screen.
    """

    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_key)

    if not is_manager:
        logger.debug('User {email} does not have MANAGE permissions for item {project_key}.'.format(
            email=user.email,
            project_key=project_key
        ))
        return HttpResponse(403)

    try:
        project = DataProject.objects.get(project_key=project_key)
        team = Team.objects.get(data_project=project, team_leader__email=team_leader)
    except ObjectDoesNotExist:
        return render(request, '404.html')

    num_required_forms = project.agreement_forms.count()

    # Collect all the team member information needed.
    team_member_details = []
    team_participants = team.participant_set.all()
    team_accepted_forms = 0

    for member in team_participants:
        email = member.user.email

        # Make a request to DBMIReg to get this person's user information.
        user_info_json = get_user_profile(user_jwt, email, project_key)

        if user_info_json['count'] != 0:
            user_info = user_info_json["results"][0]
        else:
            user_info = None

        # Check if this participant has access
        access_granted = member.permission == "VIEW"

        signed_agreement_forms = []
        signed_accepted_agreement_forms = 0

        # For each of the available agreement forms for this project, display only latest version completed by the user
        for agreement_form in project.agreement_forms.all():

            # If this project accepts agreement forms from other projects, check those
            if project.shares_agreement_forms:

                # Fetch without a specific project
                signed_form = SignedAgreementForm.objects.filter(
                    user__email=email,
                    agreement_form=agreement_form,
                ).last()

            else:
                # Fetch only for the current project
                signed_form = SignedAgreementForm.objects.filter(
                    user__email=email,
                    project=project,
                    agreement_form=agreement_form
                ).last()

            if signed_form is not None:
                signed_agreement_forms.append(signed_form)

                if signed_form.status == 'A':
                    team_accepted_forms += 1
                    signed_accepted_agreement_forms += 1

        team_member_details.append({
            'email': email,
            'user_info': user_info,
            'signed_agreement_forms': signed_agreement_forms,
            'signed_accepted_agreement_forms': signed_accepted_agreement_forms,
            'participant': member,
            'access_granted': access_granted,
        })

    # Check whether this team has completed all the necessary forms and they have been accepted by challenge admins
    total_required_forms_for_team = project.agreement_forms.count() * team_participants.count()
    team_has_all_forms_complete = total_required_forms_for_team == team_accepted_forms

    institution = project.institution

    # Get the comments made about this team by challenge administrators
    comments = TeamComment.objects.filter(team=team)

    # Get a history of files downloaded and uploaded by members of this team
    files = HostedFile.objects.filter(project=project)
    team_users = User.objects.filter(participant__in=team_participants)
    downloads = HostedFileDownload.objects.filter(hosted_file__in=files, user__in=team_users)
    uploads = team.get_submissions()

    context = {
        "user": user,
        "ssl_setting": settings.SSL_SETTING,
        "project": project,
        "team": team,
        "team_members": team_member_details,
        "num_required_forms": num_required_forms,
        "team_has_all_forms_complete": team_has_all_forms_complete,
        "institution": institution,
        "comments": comments,
        "downloads": downloads,
        "uploads": uploads
    }

    return render(request, template_name, context=context)
Example #25
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")
Example #26
0
def host_submission(request, fileservice_uuid):
    """
    An HTTP POST endpoint that allows a user to host a ChallengeTaskSubmission's
    file from AWS/fileservice as a HostedFile.
    """
    if request.method == "GET":
        logger.debug('host-submission: GET')

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

        submission = get_object_or_404(ChallengeTaskSubmission,
                                       uuid=fileservice_uuid)
        project = submission.challenge_task.data_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][get_static_agreement_form_html] 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)

        # Parse submission info
        try:
            if submission.submission_info:
                file_name = json.loads(
                    submission.submission_info).get('filename')
            else:
                file_name = None
        except Exception as e:
            logger.exception('Submission info error: {e}',
                             exc_info=True,
                             extra={
                                 'file_uuid': fileservice_uuid,
                                 'submission': submission,
                                 'submission_info': submission.submission_info
                             })

        # Initialize some fields
        initial = {
            'project': project.id,
            'file_name': file_name,
            'file_location': project.project_key.replace('-', '/')
        }

        host_hosted_file_form = HostSubmissionForm(initial=initial)

        response_html = render_to_string('manage/host-submission-form.html',
                                         context={
                                             'form': host_hosted_file_form,
                                             'submission': submission,
                                             'fileservice_uuid':
                                             fileservice_uuid,
                                         },
                                         request=request)
        return HttpResponse(response_html)

    elif request.method == "POST":
        logger.debug('host-submission: POST')

        submission = get_object_or_404(ChallengeTaskSubmission,
                                       uuid=fileservice_uuid)
        project = submission.challenge_task.data_project

        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][get_static_agreement_form_html] 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)

        host_submission_form = HostSubmissionForm(request.POST)

        # TODO show error messages
        if not host_submission_form.is_valid():
            return HttpResponse(host_submission_form.errors.as_json(),
                                status=400)

        try:
            # Do the copy
            logger.debug(
                f'[HYPATIO][DEBUG][host_submission] Copying submission "{submission}" '
                f'to hosted location "{host_submission_form.cleaned_data["file_location"]}/'
                f'{host_submission_form.cleaned_data["file_name"]}"')

            if host_file(
                    request=request,
                    file_uuid=fileservice_uuid,
                    file_location=host_submission_form.
                    cleaned_data['file_location'],
                    file_name=host_submission_form.cleaned_data['file_name']):
                logger.debug(
                    f'[HYPATIO][DEBUG][host_submission] File was copied successfully'
                )
                host_submission_form.save()

            else:
                logger.debug(
                    f'[HYPATIO][DEBUG][host_submission] File failed to copy')
                return HttpResponse(
                    {
                        'form': [{
                            'message': 'File could not be copied',
                            'code': 'copy_error'
                        }]
                    },
                    status=500)

        except Exception:
            # TODO do something on failure
            return HttpResponse("Error: failed to save object", status=500)

        return HttpResponse("File updated.", status=200)
Example #27
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') + '/')
Example #28
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)
Example #29
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)
Example #30
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)