def compound_datatype_detail(request, id): """ View or modify the CDT's details (name, description, permissions). """ four_oh_four = False try: cdt = CompoundDatatype.objects.get(pk=id) if not cdt.can_be_accessed(request.user) and not admin_check( request.user): four_oh_four = True except CompoundDatatype.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} cannot be accessed".format(id)) addable_users, addable_groups = cdt.other_users_groups() for cdtm in cdt.members.all(): addable_users, addable_groups = cdtm.datatype.intersect_permissions( users_qs=addable_users, groups_qs=addable_groups) if request.method == "POST": # We are going to try and update this CompoundDatatype. cdt_form = CompoundDatatypeForm(request.POST, users_allowed=addable_users, groups_allowed=addable_groups, instance=cdt) try: if cdt_form.is_valid(): with transaction.atomic(): cdt.grant_from_json(cdt_form.cleaned_data["permissions"]) cdt.name = cdt_form.cleaned_data["name"] # If this was blanked out, we add the default name (i.e. the CDT's string # representation. cdt.set_name() cdt.save() return HttpResponseRedirect("/compound_datatypes") except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) cdt_form.add_error(None, e) else: # A blank form which we can use to make submission and editing easier. cdt_form = CompoundDatatypeForm(initial={"name": cdt.name}, users_allowed=addable_users, groups_allowed=addable_groups) t = loader.get_template('metadata/compound_datatype_detail.html') c = { "cdt": cdt, "members": cdt.members.order_by("column_idx"), "cdt_form": cdt_form, "is_owner": request.user == cdt.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def pipelines(request, id): """ Display a list of all Pipelines within a given PipelineFamily. """ four_oh_four = False try: family = PipelineFamily.objects.get(pk=id) if not family.can_be_accessed(request.user) and not admin_check( request.user): four_oh_four = True except MethodFamily.DoesNotExist: four_oh_four = True if four_oh_four: # Redirect back to the resources page. raise Http404("ID {} cannot be accessed".format(id)) addable_users, addable_groups = family.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResource's metadata/permissions. pf_form = PipelineFamilyDetailsForm(request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=family) if pf_form.is_valid(): try: family.name = pf_form.cleaned_data["name"] family.description = pf_form.cleaned_data["description"] family.save() family.grant_from_json(pf_form.cleaned_data["permissions"]) family.clean() # Success -- go back to the resources page. return HttpResponseRedirect('/pipeline_families') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) pf_form.add_error(None, e) else: pf_form = PipelineFamilyDetailsForm(addable_users=addable_users, addable_groups=addable_groups, initial={ "name": family.name, "description": family.description }) t = loader.get_template('pipeline/pipelines.html') c = { "family": family, "family_form": pf_form, "is_admin": admin_check(request.user), "is_owner": request.user == family.user } return HttpResponse(t.render(c, request))
def pipelines(request, id): """ Display a list of all Pipelines within a given PipelineFamily. """ four_oh_four = False try: family = PipelineFamily.objects.get(pk=id) if not family.can_be_accessed(request.user) and not admin_check(request.user): four_oh_four = True except MethodFamily.DoesNotExist: four_oh_four = True if four_oh_four: # Redirect back to the resources page. raise Http404("ID {} cannot be accessed".format(id)) addable_users, addable_groups = family.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResource's metadata/permissions. pf_form = PipelineFamilyDetailsForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=family ) if pf_form.is_valid(): try: family.name = pf_form.cleaned_data["name"] family.description = pf_form.cleaned_data["description"] family.save() family.grant_from_json(pf_form.cleaned_data["permissions"]) family.clean() # Success -- go back to the resources page. return HttpResponseRedirect('/pipeline_families') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) pf_form.add_error(None, e) else: pf_form = PipelineFamilyDetailsForm( addable_users=addable_users, addable_groups=addable_groups, initial={"name": family.name, "description": family.description} ) t = loader.get_template('pipeline/pipelines.html') c = { "family": family, "family_form": pf_form, "is_admin": admin_check(request.user), "is_owner": request.user == family.user } return HttpResponse(t.render(c, request))
def datatype_detail(request, id): # retrieve the Datatype object from database by PK four_oh_four = False try: dt = Datatype.objects.get(pk=id) if not dt.can_be_accessed(request.user) and not admin_check( request.user): four_oh_four = True except Datatype.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} cannot be accessed".format(id)) addable_users, addable_groups = dt.other_users_groups() if request.method == "POST": # We are going to try and update this Datatype. datatype_form = DatatypeDetailsForm(request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=dt) try: if datatype_form.is_valid(): dt.name = datatype_form.cleaned_data["name"] dt.description = datatype_form.cleaned_data["description"] dt.clean() dt.save() dt.grant_from_json(datatype_form.cleaned_data["permissions"]) return HttpResponseRedirect("/datatypes") except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) datatype_form.add_error(None, e) else: # A blank form which we can use to make submission and editing easier. datatype_form = DatatypeDetailsForm(addable_users=addable_users, addable_groups=addable_groups, initial={ "name": dt.name, "description": dt.description }) t = loader.get_template('metadata/datatype_detail.html') c = { "datatype": dt, "constraints": dt.basic_constraints.all(), "datatype_form": datatype_form, "is_owner": request.user == dt.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def datatypes(request): """ Render table and form on user request for datatypes.html """ t = loader.get_template('metadata/datatypes.html') c = {"is_user_admin": admin_check(request.user)} return HttpResponse(t.render(c, request))
def has_permission(self, request, view): if admin_check(request.user): return True if request.method in permissions.SAFE_METHODS: return True return developer_check( request.user) and request.method in ("POST", "PATCH")
def docker_image_view(request, image_id): image = DockerImage.check_accessible(image_id, request.user) addable_users, addable_groups = image.other_users_groups() image_form = DockerImageForm( request.POST if request.method == 'POST' else None, addable_users=addable_users, addable_groups=addable_groups, instance=image) for field in ('name', 'tag', 'git'): image_form.fields[field].disabled = True if request.method == 'POST': try: image_form.save() image.grant_from_json(image_form.cleaned_data["permissions"]) return HttpResponseRedirect('/docker_images') except ValueError: # Form has errors attached. pass t = loader.get_template("method/docker_image_view.html") c = { "docker_image": image, "docker_image_form": image_form, "is_owner": image.user == request.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def docker_image_view(request, image_id): image = DockerImage.check_accessible(image_id, request.user) addable_users, addable_groups = image.other_users_groups() image_form = DockerImageForm( request.POST if request.method == 'POST' else None, addable_users=addable_users, addable_groups=addable_groups, instance=image) for field in ('name', 'tag', 'git'): image_form.fields[field].disabled = True if request.method == 'POST': try: image_form.save() image.grant_from_json(image_form.cleaned_data["permissions"]) return HttpResponseRedirect('/docker_images') except ValueError: # Form has errors attached. pass t = loader.get_template("method/docker_image_view.html") c = { "docker_image": image, "docker_image_form": image_form, "is_owner": image.user == request.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def method_families(request): """ Display a list of all MethodFamily objects in database. """ t = loader.get_template("method/method_families.html") c = {"is_user_admin": admin_check(request.user)} return HttpResponse(t.render(c, request))
def compound_datatypes(request): """ Render list of all CompoundDatatypes """ t = loader.get_template('metadata/compound_datatypes.html') c = {'is_user_admin': admin_check(request.user)} return HttpResponse(t.render(c, request))
def runs(request): """Display all active runs for this user.""" context = { "user": request.user, "is_user_admin": admin_check(request.user) } template = loader.get_template("sandbox/runs.html") return HttpResponse(template.render(context, request))
def datasets(request): """ Display a list of all Datasets in database """ t = loader.get_template('librarian/datasets.html') c = {'is_user_admin': admin_check(request.user)} return HttpResponse(t.render(c, request))
def pipeline_families(request): """ Display existing pipeline families, represented by the root members (without parent). """ t = loader.get_template('pipeline/pipeline_families.html') c = {"is_user_admin": admin_check(request.user)} return HttpResponse(t.render(c, request))
def datasets(request): """ Display a list of all Datasets in database """ t = loader.get_template('librarian/datasets.html') c = {'is_user_admin': admin_check(request.user)} return HttpResponse(t.render(c, request))
def has_object_permission(self, request, view, obj): if admin_check(request.user): return True if not obj.can_be_accessed(request.user): return False if request.method == "PATCH": return obj.user == request.user return request.method in permissions.SAFE_METHODS
def has_object_permission(self, request, view, obj): if admin_check(request.user): return True if not obj.can_be_accessed(request.user): return False if request.method == "PATCH": return obj.user == request.user return request.method in permissions.SAFE_METHODS
def runs(request): """Display all active runs for this user.""" context = { "user": request.user, "is_user_admin": admin_check(request.user) } template = loader.get_template("sandbox/runs.html") return HttpResponse(template.render(context, request))
def resources(request): """ Display a list of all code resources (parents) in database """ t = loader.get_template('method/resources.html') c = {"is_user_admin": admin_check(request.user)} return HttpResponse(t.render(c, request))
def method_families(request): """ Display a list of all MethodFamily objects in database. """ t = loader.get_template("method/method_families.html") c = { "is_user_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def get_queryset(self): if self.request.query_params.get('is_granted') == 'true': is_admin = False else: is_admin = admin_check(self.request.user) base_queryset = super(GrantedModelMixin, self).get_queryset() if is_admin: return base_queryset return self.filter_granted(base_queryset)
def resources(request): """ Display a list of all code resources (parents) in database """ t = loader.get_template('method/resources.html') c = { "is_user_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def pipeline_families(request): """ Display existing pipeline families, represented by the root members (without parent). """ t = loader.get_template('pipeline/pipeline_families.html') c = { "is_user_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def has_object_permission(self, request, view, obj): # noinspection PyUnresolvedReferences if admin_check(request.user): return True # noinspection PyUnresolvedReferences if not obj.can_be_accessed(request.user): return False if request.method == "PATCH": # noinspection PyUnresolvedReferences return obj.user == request.user return request.method in permissions.SAFE_METHODS
def has_object_permission(self, request, view, obj): # noinspection PyUnresolvedReferences if admin_check(request.user): return True # noinspection PyUnresolvedReferences if not obj.can_be_accessed(request.user): return False if request.method == "PATCH": # noinspection PyUnresolvedReferences return obj.user == request.user return request.method in permissions.SAFE_METHODS
def dataset_download(request, dataset_id): """ Retrieve the file associated with the dataset for client download. """ try: is_admin = admin_check(request.user) dataset = librarian.models.Dataset.filter_by_user( request.user, is_admin=is_admin).get(pk=dataset_id) except ObjectDoesNotExist: raise Http404("ID {} cannot be accessed".format(dataset_id)) return build_download_response(dataset.dataset_file)
def methods(self, request, pk=None): if self.request.query_params.get('is_granted') == 'true': is_admin = False else: is_admin = admin_check(self.request.user) member_methods = AccessControl.filter_by_user( request.user, is_admin=is_admin, queryset=Method.objects.filter(family_id=pk)) member_serializer = MethodSerializer( member_methods, many=True, context={"request": request}) return Response(member_serializer.data)
def revisions(self, request, pk=None): if self.request.query_params.get('is_granted') == 'true': is_admin = False else: is_admin = admin_check(self.request.user) revisions = AccessControl.filter_by_user( request.user, is_admin=is_admin, queryset=CodeResourceRevision.objects.filter(coderesource_id=pk)) return Response( CodeResourceRevisionSerializer(revisions, many=True, context={"request": request}).data )
def containers(self, request, pk=None): if self.request.query_params.get('is_granted') == 'true': is_admin = False else: is_admin = admin_check(self.request.user) family_members = AccessControl.filter_by_user( request.user, is_admin=is_admin, queryset=Container.objects.filter(family_id=pk)) return Response( ContainerSerializer(family_members, many=True, context={"request": request}).data)
def partial_update(self, request, pk=None): """ Add PATCH functionality to this view. This is used for stopping runs. """ is_stop_requested = request.data.get("is_stop_requested", False) if is_stop_requested: run = self.get_object() if request.user != run.user and not admin_check(request.user): raise PermissionDenied run.request_stop(request.user) return self.patch_object(request, pk)
def partial_update(self, request, pk=None): """ Add PATCH functionality to this view. This is used for stopping runs. """ is_stop_requested = request.data.get("is_stop_requested", False) if is_stop_requested: run = self.get_object() if request.user != run.user and not admin_check(request.user): raise PermissionDenied run.request_stop(request.user) return self.patch_object(request, pk)
def resource_revision_view(request, pk): revision = CodeResourceRevision.check_accessible(pk, request.user) addable_users, addable_groups = revision.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResourceRevision's metadata/permissions. revision_form = CodeResourceRevisionDetailsForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=revision) if revision_form.is_valid(): try: revision.revision_name = revision_form.cleaned_data[ "revision_name"] revision.revision_desc = revision_form.cleaned_data[ "revision_desc"] revision.save() revision.grant_from_json( revision_form.cleaned_data["permissions"]) revision.clean() # Success -- go back to the CodeResource page. return HttpResponseRedirect('/resource_revisions/{}'.format( revision.coderesource.pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) revision_form.add_error(None, e) else: revision_form = CodeResourceRevisionDetailsForm( addable_users=addable_users, addable_groups=addable_groups, initial={ "revision_name": revision.revision_name, "revision_desc": revision.revision_desc }) t = loader.get_template("method/resource_revision_view.html") c = { "revision": revision, "revision_form": revision_form, "is_owner": revision.user == request.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def resource_revision_view(request, pk): revision = CodeResourceRevision.check_accessible(pk, request.user) addable_users, addable_groups = revision.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResourceRevision's metadata/permissions. revision_form = CodeResourceRevisionDetailsForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=revision ) if revision_form.is_valid(): try: revision.revision_name = revision_form.cleaned_data["revision_name"] revision.revision_desc = revision_form.cleaned_data["revision_desc"] revision.save() revision.grant_from_json(revision_form.cleaned_data["permissions"]) revision.clean() # Success -- go back to the CodeResource page. return HttpResponseRedirect('/resource_revisions/{}'.format(revision.coderesource.pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) revision_form.add_error(None, e) else: revision_form = CodeResourceRevisionDetailsForm( addable_users=addable_users, addable_groups=addable_groups, initial={ "revision_name": revision.revision_name, "revision_desc": revision.revision_desc } ) t = loader.get_template("method/resource_revision_view.html") c = { "revision": revision, "revision_form": revision_form, "is_owner": revision.user == request.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def methods(request, pk): """ Display a list of all Methods within a given MethodFamily. """ family = MethodFamily.check_accessible(pk, request.user) addable_users, addable_groups = family.other_users_groups() if request.method == 'POST': # We are attempting to update the MethodFamily's metadata/permissions. mf_form = MethodFamilyForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=family ) if mf_form.is_valid(): try: family.name = mf_form.cleaned_data["name"] family.description = mf_form.cleaned_data["description"] family.save() family.grant_from_json(mf_form.cleaned_data["permissions"]) family.clean() # Success -- go back to the resources page. return HttpResponseRedirect('/method_families') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) mf_form.add_error(None, e) else: mf_form = MethodFamilyForm( addable_users=addable_users, addable_groups=addable_groups, initial={"name": family.name, "description": family.description} ) t = loader.get_template('method/methods.html') c = { "family": family, "family_form": mf_form, "is_admin": admin_check(request.user), "is_owner": request.user == family.user } return HttpResponse(t.render(c, request))
def partial_update(self, request, pk=None): """ Add PATCH functionality to this view. This is used for stopping runs. """ is_stop_requested = request.data.get("is_stop_requested", False) if is_stop_requested: run = self.get_object() if request.user == run.user or admin_check(request.user): with transaction.atomic(): run.stopped_by = request.user run.save() else: raise PermissionDenied return self.patch_object(request, pk)
def partial_update(self, request, pk=None): """ Add PATCH functionality to this view. This is used for stopping runs. """ is_stop_requested = request.data.get("is_stop_requested", False) if is_stop_requested: run = self.get_object() if request.user == run.user or admin_check(request.user): with transaction.atomic(): run.stopped_by = request.user run.save() else: raise PermissionDenied return self.patch_object(request, pk)
def methods(request, pk): """ Display a list of all Methods within a given MethodFamily. """ family = MethodFamily.check_accessible(pk, request.user) addable_users, addable_groups = family.other_users_groups() if request.method == 'POST': # We are attempting to update the MethodFamily's metadata/permissions. mf_form = MethodFamilyForm(request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=family) if mf_form.is_valid(): try: family.name = mf_form.cleaned_data["name"] family.description = mf_form.cleaned_data["description"] family.save() family.grant_from_json(mf_form.cleaned_data["permissions"]) family.clean() # Success -- go back to the resources page. return HttpResponseRedirect('/method_families') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) mf_form.add_error(None, e) else: mf_form = MethodFamilyForm(addable_users=addable_users, addable_groups=addable_groups, initial={ "name": family.name, "description": family.description }) t = loader.get_template('method/methods.html') c = { "family": family, "family_form": mf_form, "is_admin": admin_check(request.user), "is_owner": request.user == family.user } return HttpResponse(t.render(c, request))
def filter_by_user(cls, user, is_admin=False, queryset=None): """ Retrieve a QuerySet of all records of this class that are visible to the specified user. @param user: user that must be able to see the records @param is_admin: override the filter, and just return all records. @param queryset: add the filter to an existing queryset instead of cls.objects.all() @raise StandardError: if is_admin is true, but user is not in the administrator group. """ if queryset is None: queryset = cls.objects.all() if is_admin: if not admin_check(user): raise Exception('User is not an administrator.') else: user_plus = KiveUser.kiveify(user) allowed_items = queryset.filter(user_plus.access_query()) queryset = queryset.filter(pk__in=allowed_items) return queryset
def resource_revisions(request, pk): """ Display a list of all revisions of a specific Code Resource in database. """ coderesource = CodeResource.check_accessible(pk, request.user) addable_users, addable_groups = coderesource.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResource's metadata/permissions. resource_form = CodeResourceDetailsForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=coderesource ) if resource_form.is_valid(): try: coderesource.name = resource_form.cleaned_data["name"] coderesource.description = resource_form.cleaned_data["description"] coderesource.clean() coderesource.save() coderesource.grant_from_json(resource_form.cleaned_data["permissions"]) # Success -- go back to the resources page. return HttpResponseRedirect('/resources') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) resource_form.add_error(None, e) else: resource_form = CodeResourceDetailsForm( addable_users=addable_users, addable_groups=addable_groups, initial={"name": coderesource.name, "description": coderesource.description} ) revisions = CodeResourceRevision.filter_by_user( request.user, queryset=coderesource.revisions.all()).order_by('-revision_number') if len(revisions) == 0: # Go to the resource_revision_add page to create a first revision. t = loader.get_template('method/resource_revision_add.html') crv_form = CodeResourceRevisionForm() c = { 'revision_form': crv_form, 'parent_revision': None, 'coderesource': coderesource, } return HttpResponse(t.render(c, request)) # Load template, setup context t = loader.get_template('method/resource_revisions.html') c = { 'coderesource': coderesource, "resource_form": resource_form, 'revisions': revisions, 'is_admin': admin_check(request.user), "is_owner": request.user == coderesource.user } return HttpResponse(t.render(c, request))
def view_results(request, run_id): """View outputs from a pipeline run.""" go_back_to_view = request.GET.get('back_to_view', None) == 'true' four_oh_four = False try: # If we're going to change the permissions, this will make it faster. # FIXME punch this up so it gets the top-level runs of the ExecRecords it reuses run = Run.objects.prefetch_related( "runsteps__RSICs__outputs__integrity_checks__usurper", "runsteps__outputs__integrity_checks__usurper", "runoutputcables__outputs__integrity_checks__usurper", "runsteps__execrecord__generator__record__runstep__run", "runsteps__RSICs__execrecord__generator__record__runsic__runstep__run", "runoutputcables__execrecord__generator__record__runoutputcable__run" ).get(pk=run_id) if run.is_subrun(): four_oh_four = True if not run.can_be_accessed(request.user) and not admin_check(request.user): four_oh_four = True except Run.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} does not exist or is not accessible".format(run_id)) with transaction.atomic(): run_complete = run.is_complete() if request.method == "POST": # We don't allow changing anything until after the Run is finished. if not run_complete: # A form which we can use to make submission and editing easier. run_form = RunDetailsForm( users_allowed=User.objects.none(), groups_allowed=Group.objects.none(), initial={"name": run.name, "description": run.description} ) run_form.add_error(None, "This run cannot be modified until it is complete.") else: # We are going to try and update this Run. We don't bother restricting the # PermissionsField here; instead we will catch errors at the model validation # step. run_form = RunDetailsForm( request.POST, instance=run ) try: if run_form.is_valid(): with transaction.atomic(): run.name = run_form.cleaned_data["name"] run.description = run_form.cleaned_data["description"] run.save() run.increase_permissions_from_json(run_form.cleaned_data["permissions"]) run.clean() if go_back_to_view: return HttpResponseRedirect("/view_run/{}".format(run_id)) else: return HttpResponseRedirect("/runs") except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) run_form.add_error(None, e) else: # A form which we can use to make submission and editing easier. run_form = RunDetailsForm( users_allowed=User.objects.none(), groups_allowed=Group.objects.none(), initial={"name": run.name, "description": run.description} ) template = loader.get_template("sandbox/view_results.html") context = { "run": run, "outputs": JSONRenderer().render(RunOutputsSerializer(run, context={'request': request}).data), "run_form": run_form, "is_complete": run_complete, "is_owner": run.user == request.user, "is_user_admin": admin_check(request.user), "is_user_developer": developer_check(request.user), "back_to_view": go_back_to_view } return HttpResponse(template.render(context, request))
def method_view(request, pk): """ View a Method or edit its metadata/permissions. """ method = Method.check_accessible(pk, request.user) addable_users, addable_groups = method.other_users_groups() addable_users, addable_groups = method.family.intersect_permissions( addable_users, addable_groups) if method.revision_parent is not None: addable_users, addable_groups = ( method.revision_parent.intersect_permissions(addable_users, addable_groups)) if method.driver is not None: addable_users, addable_groups = method.driver.intersect_permissions( addable_users, addable_groups) if method.docker_image is not None: addable_users, addable_groups = ( method.docker_image.intersect_permissions(addable_users, addable_groups)) for dep in method.dependencies.all(): addable_users, addable_groups = dep.requirement.intersect_permissions(addable_users, addable_groups) for xput in itertools.chain(method.inputs.all(), method.outputs.all()): xput_cdt = xput.get_cdt() if xput_cdt is not None: addable_users, addable_groups = xput_cdt.intersect_permissions(addable_users, addable_groups) if request.method == 'POST': # We are attempting to update the Method's metadata/permissions. method_form = MethodDetailsForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=method ) if method_form.is_valid(): try: method.revision_name = method_form.cleaned_data["revision_name"] method.revision_desc = method_form.cleaned_data["revision_desc"] method.save() method.grant_from_json(method_form.cleaned_data["permissions"]) method.clean() # Success -- go back to the CodeResource page. return HttpResponseRedirect('/methods/{}'.format(method.family.pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) method_form.add_error(None, e) else: method_form = MethodDetailsForm( addable_users=addable_users, addable_groups=addable_groups, initial={ "revision_name": method.revision_name, "revision_desc": method.revision_desc } ) t = loader.get_template("method/method_view.html") c = { "method": method, "method_form": method_form, "is_owner": method.user == request.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def runbatch(request, runbatch_pk): """Display the specified RunBatch, allowing changes to metadata.""" four_oh_four = False try: rb = RunBatch.objects.get(pk=runbatch_pk) if not rb.can_be_accessed(request.user) and not admin_check(request.user): four_oh_four = True # If we're going to change the permissions, this will make it faster. # FIXME punch this up so it gets the top-level runs of the ExecRecords it reuses batch_runs = Run.objects.prefetch_related( "runsteps__RSICs__outputs__integrity_checks__usurper", "runsteps__outputs__integrity_checks__usurper", "runoutputcables__outputs__integrity_checks__usurper", "runsteps__execrecord__generator__record__runstep__run", "runsteps__RSICs__execrecord__generator__record__runsic__runstep__run", "runoutputcables__execrecord__generator__record__runoutputcable__run" ).filter(runbatch=rb) except RunBatch.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} does not exist or is not accessible".format(runbatch_pk)) with transaction.atomic(): all_runs_complete = not batch_runs.exclude(_runstate__pk__in=runstates.COMPLETE_STATE_PKS).exists() if not request.method == "POST": # A form which we can use to make editing easier. rb_form = RunBatchDetailsForm( users_allowed=User.objects.none(), groups_allowed=Group.objects.none(), initial={"name": rb.name, "description": rb.description} ) else: # We are going to try and update this RunBatch. We don't bother restricting the # PermissionsField here; instead we will catch errors at the model validation # step. rb_form = RunBatchDetailsForm( request.POST, instance=rb ) try: if rb_form.is_valid(): with transaction.atomic(): all_runs_complete = batch_runs.filter(_runstate__pk__in=runstates.COMPLETE_STATE_PKS) rb.name = rb_form.cleaned_data["name"] rb.description = rb_form.cleaned_data["description"] rb.save() permissions = json.loads(rb_form.cleaned_data["permissions"]) if len(permissions[0]) > 0 or len(permissions[1]) > 0: if not all_runs_complete: raise ValueError("Permissions cannot be modified until all runs are complete") rb.grant_from_json(rb_form.cleaned_data["permissions"]) for run in batch_runs: run.increase_permissions_from_json(rb_form.cleaned_data["permissions"]) Run.validate_permissions(run) # FIXME this could be slow rb.clean() return HttpResponseRedirect("/runbatch/{}".format(runbatch_pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) rb_form.add_error(None, e) template = loader.get_template("sandbox/runbatch.html") context = { "runbatch": rb, "runbatch_form": rb_form, "all_runs_complete": all_runs_complete, "is_owner": rb.user == request.user, "user": request.user, "is_user_admin": admin_check(request.user) } return HttpResponse(template.render(context, request))
def has_permission(self, request, view): return (admin_check(request.user) or request.method in permissions.SAFE_METHODS or request.method == "POST")
def dataset_view(request, dataset_id): """ Display the file associated with the dataset in the browser, or update its name/description. """ return_to_run = request.GET.get('run_id', None) is_view_results = "view_results" in request.GET is_view_run = "view_run" in request.GET return_url = reverse("datasets") if return_to_run is not None: if is_view_run: return_url = reverse('view_run', kwargs={'run_id': return_to_run}) elif is_view_results: return_url = reverse('view_results', kwargs={'run_id': return_to_run}) try: if admin_check(request.user): accessible_datasets = Dataset.objects else: accessible_datasets = Dataset.filter_by_user(request.user) dataset = accessible_datasets.prefetch_related( 'structure', 'structure__compounddatatype', 'structure__compounddatatype__members', 'structure__compounddatatype__members__datatype', 'structure__compounddatatype__members__datatype__basic_constraints' ).get(pk=dataset_id) except ObjectDoesNotExist: raise Http404("ID {} cannot be accessed".format(dataset_id)) # Figure out which users and groups could be given access to this Dataset. # If the Dataset is uploaded, it's anyone who doesn't already have access; # if it was generated, it's anyone who had access to the generating run. addable_users, addable_groups = dataset.other_users_groups() if dataset.file_source is None: generating_run = None else: generating_run = dataset.file_source.top_level_run container_dataset = dataset.containers.filter(argument__type='O').first() # Output from which runs? if container_dataset is None: container_run = None else: container_run = container_dataset.run inputs_count = dataset.containers.filter( argument__type='I').values('run_id').distinct().count() if request.method == "POST": # We are going to try and update this Dataset. dataset_form = DatasetDetailsForm( request.POST, access_limits=dataset.get_access_limits(), instance=dataset ) try: if dataset_form.is_valid(): dataset.name = dataset_form.cleaned_data["name"] dataset.description = dataset_form.cleaned_data["description"] dataset.clean() dataset.save() with transaction.atomic(): dataset.grant_from_json(dataset_form.cleaned_data["permissions"]) dataset.validate_restrict_access(dataset.get_access_limits()) return HttpResponseRedirect(return_url) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) dataset_form.add_error(None, e) else: # A DatasetForm which we can use to make submission and editing easier. dataset_form = DatasetDetailsForm( access_limits=dataset.get_access_limits(), initial={"name": dataset.name, "description": dataset.description} ) c = { "is_admin": admin_check(request.user), "is_owner": dataset.user == request.user, "dataset": dataset, "return": return_url, "dataset_form": dataset_form, "generating_run": generating_run, "inputs_count": inputs_count, "container_run": container_run } if not dataset.has_data(): t = loader.get_template("librarian/missing_dataset_view.html") if dataset.external_path: c["missing_data_message"] = "This dataset's external file is missing or has "\ "been modified (MD5 mismatch). " \ "Please consult your system administrator if this is unexpected." elif dataset.is_redacted(): c["missing_data_message"] = "Data has been redacted." else: c["missing_data_message"] = "Data was not retained or has been purged." rendered_response = t.render(c, request) elif dataset.is_raw(): t = loader.get_template("librarian/raw_dataset_view.html") # Test whether this is a binary file or not. # Read 1000 characters. data_handle = dataset.get_open_file_handle('r') if data_handle is None: c["missing_data_message"] = "Data has been removed or renamed." else: with data_handle: sample_content = data_handle.read(1000) c.update({"sample_content": sample_content}) c["is_binary"] = False try: rendered_response = t.render(c, request) except DjangoUnicodeDecodeError as e: c["is_binary"] = True del c["sample_content"] rendered_response = t.render(c, request) else: extra_errors = [] # If we have a mismatched output, we do an alignment # over the columns. if dataset.content_matches_header: col_matching, processed_rows = None, dataset.rows( True, limit=settings.DATASET_DISPLAY_MAX, extra_errors=extra_errors) else: col_matching, insert = dataset.column_alignment() processed_rows = dataset.rows(data_check=True, insert_at=insert, limit=settings.DATASET_DISPLAY_MAX, extra_errors=extra_errors) t = loader.get_template("librarian/csv_dataset_view.html") processed_rows = list(processed_rows) c.update( { 'column_matching': col_matching, 'processed_rows': processed_rows, 'extra_errors': extra_errors, "are_rows_truncated": len(processed_rows) >= settings.DATASET_DISPLAY_MAX } ) rendered_response = t.render(c, request) return HttpResponse(rendered_response)
def has_object_permission(self, request, view, obj): if admin_check(request.user): return True return obj.can_be_accessed(request.user)
def has_permission(self, request, view): # noinspection PyUnresolvedReferences return (request.method in permissions.SAFE_METHODS or request.method == "POST" or request.method == "PATCH" or admin_check(request.user))
def pipeline_view(request, id): """ View a Pipeline or edit its metadata/permissions. """ four_oh_four = False try: pipeline = Pipeline.objects.get(pk=id) if not pipeline.can_be_accessed(request.user): four_oh_four = True except Pipeline.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} is not accessible".format(id)) addable_users, addable_groups = pipeline.other_users_groups() addable_users, addable_groups = pipeline.family.intersect_permissions( addable_users, addable_groups) if pipeline.revision_parent is not None: addable_users, addable_groups = pipeline.revision_parent.intersect_permissions( addable_users, addable_groups) atomic_steps, psics, pocs = pipeline.get_all_atomic_steps_cables() for step in atomic_steps: for step_input in step.transformation.inputs.all(): step_input_cdt = step_input.get_cdt() if step_input_cdt is not None: addable_users, addable_groups = step_input_cdt.intersect_permissions( addable_users, addable_groups) for psic in psics: cable_in_cdt = psic.source.get_cdt() if cable_in_cdt is not None: addable_users, addable_groups = cable_in_cdt.intersect_permissions( addable_users, addable_groups) for poc in pocs: if poc.output_cdt is not None: addable_users, addable_groups = poc.output_cdt.intersect_permissions( addable_users, addable_groups) if request.method == 'POST': # We are attempting to update the Pipeline's metadata/permissions. pipeline_form = PipelineDetailsForm(request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=pipeline) if pipeline_form.is_valid(): try: pipeline.revision_name = pipeline_form.cleaned_data[ "revision_name"] pipeline.revision_desc = pipeline_form.cleaned_data[ "revision_desc"] pipeline.save() pipeline.grant_from_json( pipeline_form.cleaned_data["permissions"]) pipeline.clean() # Success -- go back to the CodeResource page. return HttpResponseRedirect('/pipelines/{}'.format( pipeline.family.pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) pipeline_form.add_error(None, e) else: pipeline_form = PipelineDetailsForm(addable_users=addable_users, addable_groups=addable_groups, initial={ "revision_name": pipeline.revision_name, "revision_desc": pipeline.revision_desc }) t = loader.get_template("pipeline/pipeline_view.html") c = { "pipeline": pipeline, "pipeline_form": pipeline_form, "pipeline_dict": json.dumps( PipelineSerializer(pipeline, context={ "request": request }).data), "is_owner": pipeline.user == request.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def resource_revisions(request, pk): """ Display a list of all revisions of a specific Code Resource in database. """ coderesource = CodeResource.check_accessible(pk, request.user) addable_users, addable_groups = coderesource.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResource's metadata/permissions. resource_form = CodeResourceDetailsForm(request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=coderesource) if resource_form.is_valid(): try: coderesource.name = resource_form.cleaned_data["name"] coderesource.description = resource_form.cleaned_data[ "description"] coderesource.clean() coderesource.save() coderesource.grant_from_json( resource_form.cleaned_data["permissions"]) # Success -- go back to the resources page. return HttpResponseRedirect('/resources') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) resource_form.add_error(None, e) else: resource_form = CodeResourceDetailsForm(addable_users=addable_users, addable_groups=addable_groups, initial={ "name": coderesource.name, "description": coderesource.description }) revisions = CodeResourceRevision.filter_by_user( request.user, queryset=coderesource.revisions.all()).order_by('-revision_number') if len(revisions) == 0: # Go to the resource_revision_add page to create a first revision. t = loader.get_template('method/resource_revision_add.html') crv_form = CodeResourceRevisionForm() c = { 'revision_form': crv_form, 'parent_revision': None, 'coderesource': coderesource, } return HttpResponse(t.render(c, request)) # Load template, setup context t = loader.get_template('method/resource_revisions.html') c = { 'coderesource': coderesource, "resource_form": resource_form, 'revisions': revisions, 'is_admin': admin_check(request.user), "is_owner": request.user == coderesource.user } return HttpResponse(t.render(c, request))
def method_view(request, pk): """ View a Method or edit its metadata/permissions. """ method = Method.check_accessible(pk, request.user) addable_users, addable_groups = method.other_users_groups() addable_users, addable_groups = method.family.intersect_permissions( addable_users, addable_groups) if method.revision_parent is not None: addable_users, addable_groups = ( method.revision_parent.intersect_permissions( addable_users, addable_groups)) if method.driver is not None: addable_users, addable_groups = method.driver.intersect_permissions( addable_users, addable_groups) if method.docker_image is not None: addable_users, addable_groups = ( method.docker_image.intersect_permissions(addable_users, addable_groups)) for dep in method.dependencies.all(): addable_users, addable_groups = dep.requirement.intersect_permissions( addable_users, addable_groups) for xput in itertools.chain(method.inputs.all(), method.outputs.all()): xput_cdt = xput.get_cdt() if xput_cdt is not None: addable_users, addable_groups = xput_cdt.intersect_permissions( addable_users, addable_groups) if request.method == 'POST': # We are attempting to update the Method's metadata/permissions. method_form = MethodDetailsForm(request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=method) if method_form.is_valid(): try: method.revision_name = method_form.cleaned_data[ "revision_name"] method.revision_desc = method_form.cleaned_data[ "revision_desc"] method.save() method.grant_from_json(method_form.cleaned_data["permissions"]) method.clean() # Success -- go back to the CodeResource page. return HttpResponseRedirect('/methods/{}'.format( method.family.pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) method_form.add_error(None, e) else: method_form = MethodDetailsForm(addable_users=addable_users, addable_groups=addable_groups, initial={ "revision_name": method.revision_name, "revision_desc": method.revision_desc }) t = loader.get_template("method/method_view.html") c = { "method": method, "method_form": method_form, "is_owner": method.user == request.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def has_permission(self, request, view): return (request.method in permissions.SAFE_METHODS or request.method == "POST" or request.method == "PATCH" or admin_check(request.user))
def pipeline_view(request, id): """ View a Pipeline or edit its metadata/permissions. """ four_oh_four = False try: pipeline = Pipeline.objects.get(pk=id) if not pipeline.can_be_accessed(request.user): four_oh_four = True except Pipeline.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} is not accessible".format(id)) addable_users, addable_groups = pipeline.other_users_groups() addable_users, addable_groups = pipeline.family.intersect_permissions(addable_users, addable_groups) if pipeline.revision_parent is not None: addable_users, addable_groups = pipeline.revision_parent.intersect_permissions(addable_users, addable_groups) atomic_steps, psics, pocs = pipeline.get_all_atomic_steps_cables() for step in atomic_steps: for step_input in step.transformation.inputs.all(): step_input_cdt = step_input.get_cdt() if step_input_cdt is not None: addable_users, addable_groups = step_input_cdt.intersect_permissions(addable_users, addable_groups) for psic in psics: cable_in_cdt = psic.source.get_cdt() if cable_in_cdt is not None: addable_users, addable_groups = cable_in_cdt.intersect_permissions(addable_users, addable_groups) for poc in pocs: if poc.output_cdt is not None: addable_users, addable_groups = poc.output_cdt.intersect_permissions(addable_users, addable_groups) if request.method == 'POST': # We are attempting to update the Pipeline's metadata/permissions. pipeline_form = PipelineDetailsForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=pipeline ) if pipeline_form.is_valid(): try: pipeline.revision_name = pipeline_form.cleaned_data["revision_name"] pipeline.revision_desc = pipeline_form.cleaned_data["revision_desc"] pipeline.save() pipeline.grant_from_json(pipeline_form.cleaned_data["permissions"]) pipeline.clean() # Success -- go back to the CodeResource page. return HttpResponseRedirect('/pipelines/{}'.format(pipeline.family.pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) pipeline_form.add_error(None, e) else: pipeline_form = PipelineDetailsForm( addable_users=addable_users, addable_groups=addable_groups, initial={ "revision_name": pipeline.revision_name, "revision_desc": pipeline.revision_desc } ) t = loader.get_template("pipeline/pipeline_view.html") c = { "pipeline": pipeline, "pipeline_form": pipeline_form, "pipeline_dict": json.dumps(PipelineSerializer( pipeline, context={"request": request} ).data), "is_owner": pipeline.user == request.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
def view_results(request, run_id): """View outputs from a pipeline run.""" go_back_to_view = request.GET.get('back_to_view', None) == 'true' four_oh_four = False try: # If we're going to change the permissions, this will make it faster. # FIXME punch this up so it gets the top-level runs of the ExecRecords it reuses run = Run.objects.prefetch_related( "runsteps__RSICs__outputs__integrity_checks__usurper", "runsteps__outputs__integrity_checks__usurper", "runoutputcables__outputs__integrity_checks__usurper", "runsteps__execrecord__generator__record__runstep__run", "runsteps__RSICs__execrecord__generator__record__runsic__runstep__run", "runoutputcables__execrecord__generator__record__runoutputcable__run" ).get(pk=run_id) if run.is_subrun(): four_oh_four = True if not run.can_be_accessed(request.user) and not admin_check( request.user): four_oh_four = True except Run.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404( "ID {} does not exist or is not accessible".format(run_id)) with transaction.atomic(): run_complete = run.is_complete() if request.method == "POST": # We don't allow changing anything until after the Run is finished. if not run_complete: # A form which we can use to make submission and editing easier. run_form = RunDetailsForm(users_allowed=User.objects.none(), groups_allowed=Group.objects.none(), initial={ "name": run.name, "description": run.description }) run_form.add_error( None, "This run cannot be modified until it is complete.") else: # We are going to try and update this Run. We don't bother restricting the # PermissionsField here; instead we will catch errors at the model validation # step. run_form = RunDetailsForm(request.POST, instance=run) try: if run_form.is_valid(): with transaction.atomic(): run.name = run_form.cleaned_data["name"] run.description = run_form.cleaned_data["description"] run.save() run.increase_permissions_from_json( run_form.cleaned_data["permissions"]) run.clean() if go_back_to_view: return HttpResponseRedirect( "/view_run/{}".format(run_id)) else: return HttpResponseRedirect("/runs") except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) run_form.add_error(None, e) else: # A form which we can use to make submission and editing easier. run_form = RunDetailsForm(users_allowed=User.objects.none(), groups_allowed=Group.objects.none(), initial={ "name": run.name, "description": run.description }) template = loader.get_template("sandbox/view_results.html") context = { "run": run, "outputs": JSONRenderer().render( RunOutputsSerializer(run, context={ 'request': request }).data), "run_form": run_form, "is_complete": run_complete, "is_owner": run.user == request.user, "is_user_admin": admin_check(request.user), "is_user_developer": developer_check(request.user), "back_to_view": go_back_to_view } return HttpResponse(template.render(context, request))
def runbatch(request, runbatch_pk): """Display the specified RunBatch, allowing changes to metadata.""" four_oh_four = False try: rb = RunBatch.objects.get(pk=runbatch_pk) if not rb.can_be_accessed(request.user) and not admin_check( request.user): four_oh_four = True # If we're going to change the permissions, this will make it faster. # FIXME punch this up so it gets the top-level runs of the ExecRecords it reuses batch_runs = Run.objects.prefetch_related( "runsteps__RSICs__outputs__integrity_checks__usurper", "runsteps__outputs__integrity_checks__usurper", "runoutputcables__outputs__integrity_checks__usurper", "runsteps__execrecord__generator__record__runstep__run", "runsteps__RSICs__execrecord__generator__record__runsic__runstep__run", "runoutputcables__execrecord__generator__record__runoutputcable__run" ).filter(runbatch=rb) except RunBatch.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404( "ID {} does not exist or is not accessible".format(runbatch_pk)) with transaction.atomic(): all_runs_complete = not batch_runs.exclude( _runstate__pk__in=runstates.COMPLETE_STATE_PKS).exists() if not request.method == "POST": # A form which we can use to make editing easier. rb_form = RunBatchDetailsForm(users_allowed=User.objects.none(), groups_allowed=Group.objects.none(), initial={ "name": rb.name, "description": rb.description }) else: # We are going to try and update this RunBatch. We don't bother restricting the # PermissionsField here; instead we will catch errors at the model validation # step. rb_form = RunBatchDetailsForm(request.POST, instance=rb) try: if rb_form.is_valid(): with transaction.atomic(): all_runs_complete = batch_runs.filter( _runstate__pk__in=runstates.COMPLETE_STATE_PKS) rb.name = rb_form.cleaned_data["name"] rb.description = rb_form.cleaned_data["description"] rb.save() permissions = json.loads( rb_form.cleaned_data["permissions"]) if len(permissions[0]) > 0 or len(permissions[1]) > 0: if not all_runs_complete: raise ValueError( "Permissions cannot be modified until all runs are complete" ) rb.grant_from_json(rb_form.cleaned_data["permissions"]) for run in batch_runs: run.increase_permissions_from_json( rb_form.cleaned_data["permissions"]) Run.validate_permissions( run) # FIXME this could be slow rb.clean() return HttpResponseRedirect("/runbatch/{}".format(runbatch_pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) rb_form.add_error(None, e) template = loader.get_template("sandbox/runbatch.html") context = { "runbatch": rb, "runbatch_form": rb_form, "all_runs_complete": all_runs_complete, "is_owner": rb.user == request.user, "user": request.user, "is_user_admin": admin_check(request.user) } return HttpResponse(template.render(context, request))