Beispiel #1
0
def by_id(request, sample_id, path_suffix):
    """Pure re-direct view in case a sample is accessed by ID instead of by
    name.  It redirects to the URL with the name.  The query string, if given,
    is passed, too.

    :param request: the current HTTP Request object
    :param sample_id: the numeric ID of the sample
    :param path_suffix: the trailing path, e.g. ``"/split/"``; if you just view
        a sample, it is empty (or only the query string)

    :type request: HttpRequest
    :type sample_id: unicode
    :type path_suffix: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = get_object_or_404(models.Sample, pk=utils.convert_id_to_int(sample_id))
    if is_json_requested(request):
        # No redirect for the remote client.  This also makes a POST request
        # possible.
        if path_suffix == "/edit/":
            return edit(request, sample.name)
        else:  # FixMe: More path_suffixes should be tested
            return show(request, sample.name)
    # Necessary so that the sample's name isn't exposed through the URL
    permissions.get_sample_clearance(request.user, sample)
    query_string = request.META["QUERY_STRING"] or ""
    return HttpResponseSeeOther(
        django.core.urlresolvers.reverse("show_sample_by_name", kwargs={"sample_name": sample.name}) + path_suffix +
        ("?" + query_string if query_string else ""))
Beispiel #2
0
def show_stack(request, sample_id, thumbnail):
    """Shows a particular informal layer stack.  Although its response is a bitmap
    rather than an HTML file, it is served by Django in order to enforce user
    permissions.

    :param request: the current HTTP Request object
    :param sample_id: the database ID of the sample
    :param thumbnail: whether we should deliver a thumbnail version

    :type request: HttpRequest
    :type process_id: unicode
    :type thumbnail: bool

    :return:
      the HTTP response object with the image

    :rtype: HttpResponse
    """
    sample_details = get_object_or_404(models.SampleDetails,
                                       pk=utils.convert_id_to_int(sample_id))
    sample = sample_details.sample
    permissions.get_sample_clearance(request.user, sample)
    if not sample_details.has_producible_stack_diagram():
        raise Http404("No stack diagram available.")
    locations = sample_details.get_stack_diagram_locations()
    filepath = locations["thumbnail_file" if thumbnail else "diagram_file"]
    content = jb_common.utils.base.get_cached_file_content(
        filepath,
        partial(generate_stack, thumbnail, locations, sample, sample_details),
        timestamps=[sample.last_modified])
    return jb_common.utils.base.static_response(
        content, None if thumbnail else "{0}_stack.pdf".format(
            defaultfilters.slugify(six.text_type(sample))),
        "image/png" if thumbnail else "application/pdf")
Beispiel #3
0
def show_stack(request, sample_id, thumbnail):
    """Shows a particular informal layer stack.  Although its response is a bitmap
    rather than an HTML file, it is served by Django in order to enforce user
    permissions.

    :param request: the current HTTP Request object
    :param sample_id: the database ID of the sample
    :param thumbnail: whether we should deliver a thumbnail version

    :type request: HttpRequest
    :type process_id: unicode
    :type thumbnail: bool

    :return:
      the HTTP response object with the image

    :rtype: HttpResponse
    """
    sample_details = get_object_or_404(models.SampleDetails, pk=utils.convert_id_to_int(sample_id))
    sample = sample_details.sample
    permissions.get_sample_clearance(request.user, sample)
    if not sample_details.has_producible_stack_diagram():
        raise Http404("No stack diagram available.")
    locations = sample_details.get_stack_diagram_locations()
    filepath = locations["thumbnail_file" if thumbnail else "diagram_file"]
    content = jb_common.utils.base.get_cached_file_content(
        filepath, partial(generate_stack, thumbnail, locations, sample, sample_details), timestamps=[sample.last_modified])
    return jb_common.utils.base.static_response(
        content, None if thumbnail else "{0}_stack.pdf".format(defaultfilters.slugify(six.text_type(sample))),
        "image/png" if thumbnail else "application/pdf")
Beispiel #4
0
def show_stack(request, sample_id, thumbnail):
    """Shows a particular informal layer stack.  Although its response is a bitmap
    rather than an HTML file, it is served by Django in order to enforce user
    permissions.

    :param request: the current HTTP Request object
    :param sample_id: the database ID of the sample
    :param thumbnail: whether we should deliver a thumbnail version

    :type request: HttpRequest
    :type process_id: unicode
    :type thumbnail: bool

    :return:
      the HTTP response object with the image

    :rtype: HttpResponse
    """
    sample_details = get_object_or_404(models.SampleDetails,
                                       pk=utils.convert_id_to_int(sample_id))
    sample = sample_details.sample
    permissions.get_sample_clearance(request.user, sample)
    if not sample_details.has_producible_stack_diagram():
        raise Http404("No stack diagram available.")
    locations = sample_details.get_stack_diagram_locations()
    filepath = locations["thumbnail_file" if thumbnail else "diagram_file"]
    if jb_common.utils.base.is_update_necessary(
            filepath, timestamps=[sample.last_modified]):
        jb_common.utils.base.mkdirs(filepath)
        if not thumbnail or jb_common.utils.base.is_update_necessary(
                locations["diagram_file"], timestamps=[sample.last_modified]):
            jb_common.utils.base.mkdirs(locations["diagram_file"])
            informal_stacks.generate_diagram(
                locations["diagram_file"], [
                    informal_stacks.Layer(layer)
                    for layer in sample_details.informal_layers.all()
                ], six.text_type(sample),
                _("Layer stack of {0}").format(sample))
        if thumbnail:
            subprocess.call([
                "gs", "-q", "-dNOPAUSE", "-dBATCH", "-sDEVICE=pngalpha",
                "-r100", "-dEPSCrop",
                "-sOutputFile=" + locations["thumbnail_file"],
                locations["diagram_file"]
            ])
        storage_changed.send(models.SampleDetails)
    return jb_common.utils.base.static_file_response(
        filepath, None if thumbnail else "{0}_stack.pdf".format(
            defaultfilters.slugify(six.text_type(sample))))
Beispiel #5
0
def show_stack(request, sample_id, thumbnail):
    """Shows a particular informal layer stack.  Although its response is a bitmap
    rather than an HTML file, it is served by Django in order to enforce user
    permissions.

    :param request: the current HTTP Request object
    :param sample_id: the database ID of the sample
    :param thumbnail: whether we should deliver a thumbnail version

    :type request: HttpRequest
    :type process_id: unicode
    :type thumbnail: bool

    :return:
      the HTTP response object with the image

    :rtype: HttpResponse
    """
    sample_details = get_object_or_404(models.SampleDetails, pk=utils.convert_id_to_int(sample_id))
    sample = sample_details.sample
    permissions.get_sample_clearance(request.user, sample)
    if not sample_details.has_producible_stack_diagram():
        raise Http404("No stack diagram available.")
    locations = sample_details.get_stack_diagram_locations()
    filepath = locations["thumbnail_file" if thumbnail else "diagram_file"]
    if jb_common.utils.base.is_update_necessary(filepath, timestamps=[sample.last_modified]):
        jb_common.utils.base.mkdirs(filepath)
        if not thumbnail or jb_common.utils.base.is_update_necessary(locations["diagram_file"], timestamps=[sample.last_modified]):
            jb_common.utils.base.mkdirs(locations["diagram_file"])
            informal_stacks.generate_diagram(
                locations["diagram_file"], [informal_stacks.Layer(layer) for layer in sample_details.informal_layers.all()],
                six.text_type(sample), _("Layer stack of {0}").format(sample))
        if thumbnail:
            subprocess.call(["gs", "-q", "-dNOPAUSE", "-dBATCH", "-sDEVICE=pngalpha", "-r100", "-dEPSCrop",
                             "-sOutputFile=" + locations["thumbnail_file"], locations["diagram_file"]])
        storage_changed.send(models.SampleDetails)
    return jb_common.utils.base.static_file_response(
        filepath, None if thumbnail else "{0}_stack.pdf".format(defaultfilters.slugify(six.text_type(sample))))
Beispiel #6
0
def printer_label(request, sample_id):
    """Generates a PDF for the label printer in 9×45 mm² format.  It contains
    the name and the QR code of a sample.

    :param request: the current HTTP Request object
    :param sample_id: the ID of the sample

    :type request: HttpRequest
    :type sample_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = get_object_or_404(models.Sample, pk=utils.convert_id_to_int(sample_id))
    permissions.get_sample_clearance(request.user, sample)
    pdf_output = printer_labels.printer_label(sample)
    response = HttpResponse()
    response.write(pdf_output)
    response["Content-Type"] = "application/pdf"
    response["Content-Length"] = len(pdf_output)
    return response
Beispiel #7
0
def printer_label(request, sample_id):
    """Generates a PDF for the label printer in 9×45 mm² format.  It contains
    the name and the QR code of a sample.

    :param request: the current HTTP Request object
    :param sample_id: the ID of the sample

    :type request: HttpRequest
    :type sample_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = get_object_or_404(models.Sample,
                               pk=utils.convert_id_to_int(sample_id))
    permissions.get_sample_clearance(request.user, sample)
    pdf_output = printer_labels.printer_label(sample)
    response = HttpResponse()
    response.write(pdf_output)
    response["Content-Type"] = "application/pdf"
    response["Content-Length"] = len(pdf_output)
    return response
Beispiel #8
0
def lookup_sample(sample_name, user, with_clearance=False):
    """Looks up the ``sample_name`` in the database (also among the aliases),
    and returns that sample if it was found *and* the current user is allowed
    to view it.  Shortened provisional names like “\*2” are also found.  If
    nothing is found or the permissions are not sufficient, it raises an
    exception.

    :param sample_name: name of the sample
    :param user: the currently logged-in user
    :param with_clearance: whether also clearances should be serached for and
        returned

    :type sample_name: unicode
    :type user: django.contrib.auth.models.User
    :type with_clearance: bool

    :return:
      the single found sample; or the sample and the clearance instance if this
      is necessary to view the sample and ``with_clearance=True``

    :rtype: `samples.models.Sample` or `samples.models.Sample`,
      `samples.models.Clearance`

    :raises Http404: if the sample name could not be found
    :raises AmbiguityException: if more than one matching alias was found
    :raises samples.permissions.PermissionError: if the user is not allowed to
      view the sample
    """
    name_format, match = sample_name_format(sample_name,
                                            with_match_object=True)
    if name_format == "provisional":
        sample_name = "*{0:05}".format(int(match.group("id")))
    sample = get_sample(sample_name)
    if not sample:
        raise Http404(
            "Sample {name} could not be found (neither as an alias).".format(
                name=sample_name))
    if isinstance(sample, list):
        raise AmbiguityException(sample_name, sample)
    if with_clearance:
        clearance = permissions.get_sample_clearance(user, sample)
        return sample, clearance
    else:
        permissions.assert_can_fully_view_sample(user, sample)
        return sample
Beispiel #9
0
def lookup_sample(sample_name, user, with_clearance=False):
    """Looks up the ``sample_name`` in the database (also among the aliases),
    and returns that sample if it was found *and* the current user is allowed
    to view it.  Shortened provisional names like “\*2” are also found.  If
    nothing is found or the permissions are not sufficient, it raises an
    exception.

    :param sample_name: name of the sample
    :param user: the currently logged-in user
    :param with_clearance: whether also clearances should be serached for and
        returned

    :type sample_name: unicode
    :type user: django.contrib.auth.models.User
    :type with_clearance: bool

    :return:
      the single found sample; or the sample and the clearance instance if this
      is necessary to view the sample and ``with_clearance=True``

    :rtype: `samples.models.Sample` or `samples.models.Sample`,
      `samples.models.Clearance`

    :raises Http404: if the sample name could not be found
    :raises AmbiguityException: if more than one matching alias was found
    :raises samples.permissions.PermissionError: if the user is not allowed to
      view the sample
    """
    name_format, match = sample_names.sample_name_format(sample_name, with_match_object=True)
    if name_format == "provisional":
        sample_name = "*{0:05}".format(int(match.group("id")))
    sample = sample_names.get_sample(sample_name)
    if not sample:
        raise Http404("Sample {name} could not be found (neither as an alias).".format(name=sample_name))
    if isinstance(sample, list):
        raise AmbiguityException(sample_name, sample)
    if with_clearance:
        clearance = permissions.get_sample_clearance(user, sample)
        return sample, clearance
    else:
        permissions.assert_can_fully_view_sample(user, sample)
        return sample
Beispiel #10
0
def is_referentially_valid(current_user, my_samples_form, action_form):
    """Test whether all forms are consistent with each other and with the
    database.  For example, you must not change data for samples for which
    you're not the currently responsible person.

    :param current_user: the currently logged-in user
    :param my_samples_form: the form with the selected “My Samples”
    :param action_form: the form with the things to be done with the selected
        samples.

    :type current_user: django.contrib.auth.models.User
    :type my_samples_form: `MySamplesForm`
    :type action_form: `ActionForm`

    :return:
      whether all forms are consistent with each other and the database

    :rtype: bool
    """
    referentially_valid = True
    if my_samples_form.is_valid() and action_form.is_valid():
        action_data = action_form.cleaned_data
        if not current_user.is_superuser:
            if action_data["new_currently_responsible_person"] or action_data["new_topic"] or \
                        action_data["new_current_location"]:
                try:
                    for sample in my_samples_form.cleaned_data["samples"]:
                        permissions.assert_can_edit_sample(
                            current_user, sample)
                except permissions.PermissionError:
                    action_form.add_error(
                        None,
                        ValidationError(_(
                            "You must be the currently responsible person for samples you'd like to change "
                            "or the topic manager of the samples topics."),
                                        code="forbidden"))
                    referentially_valid = False
        if action_data["clearance"] is None and action_data["copy_to_user"]:
            try:
                action_data["copy_to_user"] = list(action_data["copy_to_user"])
                action_data["copy_to_user"].remove(
                    action_data["new_currently_responsible_person"])
            except ValueError:
                pass
            try:
                for sample in my_samples_form.cleaned_data["samples"]:
                    for user in action_data["copy_to_user"]:
                        permissions.assert_can_fully_view_sample(user, sample)
            except permissions.PermissionError:
                action_form.add_error(
                    "clearance",
                    ValidationError(_(
                        "If you copy samples over to another person who cannot fully view one of the "
                        "samples, you must select a clearance option."),
                                    code="required"))
                referentially_valid = False
        if action_data.get("clearance") is not None:
            failed_samples = []
            for sample in my_samples_form.cleaned_data["samples"]:
                try:
                    permissions.get_sample_clearance(current_user, sample)
                except permissions.PermissionError:
                    failed_samples.append(sample)
            if failed_samples:
                my_samples_form.add_error(
                    "samples",
                    ValidationError(_(
                        "You cannot grant clearances for the following samples: %(failed_samples)s"
                    ),
                                    params={
                                        "failed_samples":
                                        format_enumeration(failed_samples)
                                    },
                                    code="forbidden"))
                referentially_valid = False
    return referentially_valid
Beispiel #11
0
def is_referentially_valid(current_user, my_samples_form, action_form):
    """Test whether all forms are consistent with each other and with the
    database.  For example, you must not change data for samples for which
    you're not the currently responsible person.

    :param current_user: the currently logged-in user
    :param my_samples_form: the form with the selected “My Samples”
    :param action_form: the form with the things to be done with the selected
        samples.

    :type current_user: django.contrib.auth.models.User
    :type my_samples_form: `MySamplesForm`
    :type action_form: `ActionForm`

    :return:
      whether all forms are consistent with each other and the database

    :rtype: bool
    """
    referentially_valid = True
    if my_samples_form.is_valid() and action_form.is_valid():
        action_data = action_form.cleaned_data
        if not current_user.is_superuser:
            if action_data["new_currently_responsible_person"] or action_data["new_topic"] or \
                        action_data["new_current_location"]:
                try:
                    for sample in my_samples_form.cleaned_data["samples"]:
                        permissions.assert_can_edit_sample(current_user, sample)
                except permissions.PermissionError:
                    action_form.add_error(None, ValidationError(
                        _("You must be the currently responsible person for samples you'd like to change "
                          "or the topic manager of the samples topics."), code="forbidden"))
                    referentially_valid = False
        if action_data["clearance"] is None and action_data["copy_to_user"]:
            try:
                action_data["copy_to_user"] = list(action_data["copy_to_user"])
                action_data["copy_to_user"].remove(action_data["new_currently_responsible_person"])
            except ValueError:
                pass
            try:
                for sample in my_samples_form.cleaned_data["samples"]:
                    for user in action_data["copy_to_user"]:
                        permissions.assert_can_fully_view_sample(user, sample)
            except permissions.PermissionError:
                action_form.add_error("clearance", ValidationError(
                    _("If you copy samples over to another person who cannot fully view one of the "
                      "samples, you must select a clearance option."), code="required"))
                referentially_valid = False
        if action_data.get("clearance") is not None:
            failed_samples = []
            for sample in my_samples_form.cleaned_data["samples"]:
                try:
                    permissions.get_sample_clearance(current_user, sample)
                except permissions.PermissionError:
                    failed_samples.append(sample)
            if failed_samples:
                my_samples_form.add_error("samples", ValidationError(
                    _("You cannot grant clearances for the following samples: %(failed_samples)s"),
                    params={"failed_samples": format_enumeration(failed_samples)}, code="forbidden"))
                referentially_valid = False
    return referentially_valid