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)
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 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)
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)
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)
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
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)
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")
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
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)
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)
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
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
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)
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)
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)
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)
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)
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
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
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)
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
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)
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)
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")
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)
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') + '/')
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)
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)
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)