コード例 #1
0
ファイル: json_client.py プロジェクト: msincan/juliabase
def get_folded_processes(request, sample_id):
    """Get all the IDs from the processes, who have to be folded.

    :param request: The current HTTP Request object.  It must contain all the process
        IDs of the processes from the selected sample.
    :param sample_id: The sample ID represent the data sheet the user wants to see.

    :type request: HttpRequest
    :type sample_id: unicode

    :return:
     The process IDs of the processes, who have to be folded on the samples data sheet.

    :rtype: HttpResponse
    """
    try:
        process_ids = [utils.convert_id_to_int(id_) for id_ in request.GET["process_ids"].split(",")]
    except KeyError:
        raise JSONRequestException(3, '"process_ids" missing')
    utils.convert_id_to_int(sample_id)
    folded_process_classes = ContentType.objects.filter(dont_show_to_user=request.user.samples_user_details)
    exceptional_processes_by_sample_id = json.loads(request.user.samples_user_details.folded_processes).get(sample_id, [])
    folded_process_ids = []
    for process_id in process_ids:
        if _is_folded(process_id, folded_process_classes, exceptional_processes_by_sample_id, switch=False):
            folded_process_ids.append(process_id)
    return respond_in_json(folded_process_ids)
コード例 #2
0
ファイル: layout.py プロジェクト: muescha/juliabase
def show_layout(request, process_id, sample_id):
    sample = get_object_or_404(models.Sample, pk=utils.convert_id_to_int(sample_id))
    process = get_object_or_404(models.Process, pk=utils.convert_id_to_int(process_id)).actual_instance
    png_filename = os.path.join("layouts", "{0}-{1}.png".format(process.id, sample.id))
    content = jb_common.utils.base.get_cached_file_content(
        png_filename, partial(generate_layout, sample, process), timestamps=[sample.last_modified, process.last_modified])
    return jb_common.utils.base.static_response(content, png_filename)
コード例 #3
0
ファイル: json_client.py プロジェクト: Midnighter/juliabase
def get_folded_processes(request, sample_id):
    """Get all the IDs from the processes, who have to be folded.

    :param request: The current HTTP Request object.  It must contain all the process
        IDs of the processes from the selected sample.
    :param sample_id: The sample ID represent the data sheet the user wants to see.

    :type request: HttpRequest
    :type sample_id: unicode

    :return:
     The process IDs of the processes, who have to be folded on the samples data sheet.

    :rtype: HttpResponse
    """
    try:
        process_ids = [
            utils.convert_id_to_int(id_)
            for id_ in request.GET["process_ids"].split(",")
        ]
    except KeyError:
        raise JSONRequestException(3, '"process_ids" missing')
    utils.convert_id_to_int(sample_id)
    folded_process_classes = ContentType.objects.filter(
        dont_show_to_user=request.user.samples_user_details)
    exceptional_processes_by_sample_id = json.loads(
        request.user.samples_user_details.folded_processes).get(sample_id, [])
    folded_process_ids = []
    for process_id in process_ids:
        if _is_folded(process_id,
                      folded_process_classes,
                      exceptional_processes_by_sample_id,
                      switch=False):
            folded_process_ids.append(process_id)
    return respond_in_json(folded_process_ids)
コード例 #4
0
ファイル: json_client.py プロジェクト: msincan/juliabase
def add_sample(request):
    """Adds a new sample to the database.  It is added without processes.  This
    view can only be used by admin accounts.

    :param request: the current HTTP Request object; it must contain the sample
        data in the POST data.

    :return:
      The primary key of the created sample.  ``False`` if something went
      wrong.  It may return a 404 if the topic or the currently responsible
      person wasn't found.

    :rtype: HttpResponse
    """
    try:
        name = request.POST["name"]
        current_location = request.POST["current_location"]
        currently_responsible_person = request.POST["currently_responsible_person"]
        purpose = request.POST.get("purpose", "")
        tags = request.POST.get("tags", "")
        topic = request.POST.get("topic")
    except KeyError as error:
        raise JSONRequestException(3, "'{}' parameter missing.".format(error.args[0]))
    if len(name) > 30:
        raise JSONRequestException(5, "The sample name is too long.")
    name_format = utils.sample_name_format(name)
    if name_format is None or \
       not request.user.is_superuser and \
       name_format not in settings.SAMPLE_NAME_FORMATS["provisional"].get("possible_renames", set()):
        raise JSONRequestException(5, "The sample name is invalid.")
    eligible_users = django.contrib.auth.models.User.objects.filter(is_active=True, jb_user_details__department__isnull=False)
    try:
        currently_responsible_person = eligible_users.get(pk=utils.convert_id_to_int(currently_responsible_person))
    except django.contrib.auth.models.User.DoesNotExist:
        raise Http404("Currently reponsible user not found.")
    if topic:
        all_topics = Topic.objects.all() if request.user.is_superuser else \
                     Topic.objects.filter(Q(confidential=False) | Q(members=request.user))
        try:
            topic = all_topics.get(pk=utils.convert_id_to_int(topic))
        except Topic.DoesNotExist:
            raise Http404("Topic not found")
    try:
        sample = models.Sample.objects.create(name=name, current_location=current_location,
                                              currently_responsible_person=currently_responsible_person, purpose=purpose,
                                              tags=tags, topic=topic)
        # They will be shadowed anyway.  Nevertheless, this action is an
        # emergency measure.  Probably the samples the aliases point to should
        # be merged with the sample but this can't be decided automatically.
        models.SampleAlias.objects.filter(name=name).delete()
    except IntegrityError as error:
        error_message = "The sample with this data could not be added."
        if request.user.is_superuser:
            error_message += " {}".format(error)
        raise JSONRequestException(5, error_message)
    sample.watchers.add(request.user)
    return respond_in_json(sample.pk)
コード例 #5
0
def show_layout(request, process_id, sample_id):
    sample = get_object_or_404(models.Sample,
                               pk=utils.convert_id_to_int(sample_id))
    process = get_object_or_404(
        models.Process, pk=utils.convert_id_to_int(process_id)).actual_instance
    png_filename = os.path.join("layouts",
                                "{0}-{1}.png".format(process.id, sample.id))
    content = jb_common.utils.base.get_cached_file_content(
        png_filename,
        partial(generate_layout, sample, process),
        timestamps=[sample.last_modified, process.last_modified])
    return jb_common.utils.base.static_response(content, png_filename)
コード例 #6
0
ファイル: json_client.py プロジェクト: msincan/juliabase
def add_alias(request):
    """Adds a new sample alias name to the database.  This view can only be
    used by admin accounts.

    :param request: the current HTTP Request object; it must contain the
        sample's primary key and the alias name in the POST data.

    :type request: HttpRequest

    :return:
      ``True`` if it worked, ``False`` if something went wrong.  It returns a
      404 if the sample wasn't found.

    :rtype: HttpResponse
    """
    if not request.user.is_superuser:
        return respond_in_json(False)
    try:
        sample_pk = request.POST["sample"]
        alias = request.POST["alias"]
    except KeyError:
        return respond_in_json(False)
    sample = get_object_or_404(models.Sample, pk=utils.convert_id_to_int(sample_pk))
    try:
        models.models.SampleAlias.create(name=alias, sample=sample)
    except IntegrityError:
        # Alias already present
        return respond_in_json(False)
    return respond_in_json(True)
コード例 #7
0
def show_thumbnail(request, process_id):
    """Shows the thumnail of a particular result image.  Although its response
    is an image rather than an HTML file, it is served by Django in order to
    enforce user permissions.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object with the thumbnail image

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result,
                               pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    image_locations = result.get_image_locations()
    image_file = image_locations["image_file"]
    thumbnail_file = image_locations["thumbnail_file"]
    if is_update_necessary(thumbnail_file, [image_file]):
        mkdirs(thumbnail_file)
        subprocess.check_call([
            "convert",
            image_file + ("[0]" if result.image_type == "pdf" else ""),
            "-resize", "{0}x{0}".format(settings.THUMBNAIL_WIDTH),
            thumbnail_file
        ])
        storage_changed.send(models.Result)
    return static_file_response(thumbnail_file)
コード例 #8
0
ファイル: stack.py プロジェクト: colima/juliabase
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")
コード例 #9
0
ファイル: stack.py プロジェクト: muescha/juliabase
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")
コード例 #10
0
ファイル: sample.py プロジェクト: muescha/juliabase
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 ""))
コード例 #11
0
ファイル: status.py プロジェクト: Midnighter/juliabase
def withdraw(request, id_):
    """This function withdraws a status message for good.  Note that it
    withdraws it for all its connected process types.  It is idempotent.

    :param request: the current HTTP Request object
    :param id_: the id of the message to be withdrawn

    :type request: HttpRequest
    :type id_: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    status_message = get_object_or_404(models.StatusMessage,
                                       withdrawn=False,
                                       pk=utils.convert_id_to_int(id_))
    if request.user != status_message.operator:
        raise PermissionError(
            request.user,
            "You cannot withdraw status messages of another user.")
    status_message.withdrawn = True
    status_message.save()
    for process_class in status_message.process_classes.all():
        utils.Reporter(request.user).report_withdrawn_status_message(
            process_class, status_message)
    return utils.successful_response(
        request, _("The status message was successfully withdrawn."), show)
コード例 #12
0
ファイル: result.py プロジェクト: msincan/juliabase
def show_thumbnail(request, process_id):
    """Shows the thumnail of a particular result image.  Although its response
    is an image rather than an HTML file, it is served by Django in order to
    enforce user permissions.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object with the thumbnail image

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    image_locations = result.get_image_locations()
    image_file = image_locations["image_file"]
    thumbnail_file = image_locations["thumbnail_file"]
    if is_update_necessary(thumbnail_file, [image_file]):
        mkdirs(thumbnail_file)
        subprocess.check_call(["convert", image_file + ("[0]" if result.image_type == "pdf" else ""),
                               "-resize", "{0}x{0}".format(settings.THUMBNAIL_WIDTH), thumbnail_file])
        storage_changed.send(models.Result)
    return static_file_response(thumbnail_file)
コード例 #13
0
def show(request, process_id):
    """Shows a particular result process.  The main purpose of this view is to
    be able to visit a result directly from a feed entry about a new/edited
    result.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result,
                               pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    if jb_common.utils.base.is_json_requested(request):
        return jb_common.utils.base.respond_in_json(result.get_data())
    template_context = {
        "title": _("Result “{title}”").format(title=result.title),
        "result": result,
        "samples": result.samples.all(),
        "sample_series": result.sample_series.all()
    }
    template_context.update(utils.digest_process(result, request.user))
    return render(request, "samples/show_single_result.html", template_context)
コード例 #14
0
def edit(request, external_operator_id):
    """View for editing existing external operators.  You can also give the
    operator initials here.

    :param request: the current HTTP Request object
    :param external_operator_id: the database ID for the external operator

    :type request: HttpRequest
    :type external_operator_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    external_operator = get_object_or_404(models.ExternalOperator, pk=utils.convert_id_to_int(external_operator_id))
    permissions.assert_can_edit_external_operator(request.user, external_operator)
    if request.method == "POST":
        external_operator_form = EditExternalOperatorForm(request.user, request.POST, instance=external_operator)
        if external_operator_form.is_valid():
            external_operator = external_operator_form.save()
            return utils.successful_response(
                request,
                _("The external operator “{operator}” was successfully changed.").format(operator=external_operator.name))
    else:
        external_operator_form = EditExternalOperatorForm(request.user, instance=external_operator)
    initials_form = utils.InitialsForm(external_operator, initials_mandatory=True)
    return render(request, "samples/edit_external_operator.html",
                  {"title": _("Edit external operator “{operator}”").format(operator=external_operator.name),
                   "external_operator": external_operator_form,
                   "initials": initials_form})
コード例 #15
0
ファイル: result.py プロジェクト: muescha/juliabase
def export(request, process_id):
    """View for exporting result process data in CSV or JSON format.  Thus,
    the return value is not an HTML response.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    data = result.get_data_for_table_export()
    # Translators: In a table
    result = utils.table_export(request, data, _("row"))
    if isinstance(result, tuple):
        column_groups_form, columns_form, table, switch_row_forms, old_data_form = result
    elif isinstance(result, HttpResponse):
        return result
    title = _("Table export for “{name}”").format(name=data.descriptive_name)
    return render(request, "samples/table_export.html", {"title": title, "column_groups": column_groups_form,
                                                         "columns": columns_form,
                                                         "rows": list(zip(table, switch_row_forms)) if table else None,
                                                         "old_data": old_data_form,
                                                         "backlink": request.GET.get("next", "")})
コード例 #16
0
def show(request, external_operator_id):
    """View for displaying existing external operators.  Only users who are
    allowed to see all samples, and the current contact person are allowed to
    see it.

    :param request: the current HTTP Request object
    :param external_operator_id: the database ID for the external operator

    :type request: HttpRequest
    :type external_operator_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    external_operator = get_object_or_404(models.ExternalOperator, pk=utils.convert_id_to_int(external_operator_id))
    contact_persons = external_operator.contact_persons.all()
    if permissions.has_permission_to_view_external_operator(request.user, external_operator):
        try:
            initials = external_operator.initials
        except models.Initials.DoesNotExist:
            initials = None
        title = _("External operator “{name}”").format(name=external_operator.name)
    else:
        title = _("Confidential operator #{number}").format(number=external_operator.pk)
        external_operator = None
        initials = None
    return render(request, "samples/show_external_operator.html",
                  {"title": title,
                   "external_operator": external_operator, "initials": initials,
                   "contact_persons" : contact_persons,
                   "can_edit": request.user in contact_persons})
コード例 #17
0
ファイル: result.py プロジェクト: colima/juliabase
def export(request, process_id):
    """View for exporting result process data in CSV or JSON format.  Thus,
    the return value is not an HTML response.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    data = result.get_data_for_table_export()
    # Translators: In a table
    result = utils.table_export(request, data, _("row"))
    if isinstance(result, tuple):
        column_groups_form, columns_form, table, switch_row_forms, old_data_form = result
    elif isinstance(result, HttpResponse):
        return result
    title = _("Table export for “{name}”").format(name=data.descriptive_name)
    return render(request, "samples/table_export.html", {"title": title, "column_groups": column_groups_form,
                                                         "columns": columns_form,
                                                         "rows": list(zip(table, switch_row_forms)) if table else None,
                                                         "old_data": old_data_form,
                                                         "backlink": request.GET.get("next", "")})
コード例 #18
0
ファイル: json_client.py プロジェクト: Midnighter/juliabase
def add_alias(request):
    """Adds a new sample alias name to the database.  This view can only be
    used by admin accounts.

    :param request: the current HTTP Request object; it must contain the
        sample's primary key and the alias name in the POST data.

    :type request: HttpRequest

    :return:
      ``True`` if it worked, ``False`` if something went wrong.  It returns a
      404 if the sample wasn't found.

    :rtype: HttpResponse
    """
    if not request.user.is_staff:
        return respond_in_json(False)
    try:
        sample_pk = request.POST["sample"]
        alias = request.POST["alias"]
    except KeyError:
        return respond_in_json(False)
    sample = get_object_or_404(models.Sample,
                               pk=utils.convert_id_to_int(sample_pk))
    try:
        models.models.SampleAlias.create(name=alias, sample=sample)
    except IntegrityError:
        # Alias already present
        return respond_in_json(False)
    return respond_in_json(True)
コード例 #19
0
ファイル: layout.py プロジェクト: msincan/juliabase
def show_layout(request, process_id, sample_id):
    sample = get_object_or_404(models.Sample, pk=utils.convert_id_to_int(sample_id))
    process = get_object_or_404(models.Process, pk=utils.convert_id_to_int(process_id)).actual_instance

    pdf_filename = "/tmp/layouts_{0}_{1}.pdf".format(process.id, sample.id)
    jb_common.utils.base.mkdirs(pdf_filename)
    layout = layouts.get_layout(sample, process)
    if not layout:
        raise Http404("error")
    layout.generate_pdf(pdf_filename)

    png_filename = os.path.join(settings.CACHE_ROOT, "layouts", "{0}-{1}.png".format(process.id, sample.id))
    jb_common.utils.base.mkdirs(png_filename)
    resolution = settings.THUMBNAIL_WIDTH / (layout.width / 72)
    subprocess.check_call(["gs", "-q", "-dNOPAUSE", "-dBATCH", "-sDEVICE=pngalpha", "-r{0}".format(resolution), "-dEPSCrop",
                             "-sOutputFile=" + png_filename, pdf_filename])
    return jb_common.utils.base.static_file_response(png_filename)
コード例 #20
0
ファイル: split_and_rename.py プロジェクト: msincan/juliabase
def split_and_rename(request, parent_name=None, old_split_id=None):
    """Both splitting of a sample and re-split of an already existing split
    are handled here.  *Either* ``parent_name`` *or* ``old_split`` are unequal
    to ``None``.

    :param request: the current HTTP Request object
    :param parent_name: if given, the name of the sample to be split
    :param old_split_id: if given the process ID of the split to be modified

    :type request: HttpRequest
    :type parent_name: unicode or NoneType
    :type old_split_id: int or NoneType

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    assert (parent_name or old_split_id) and not (parent_name and old_split_id)
    if parent_name:
        old_split = None
        parent = utils.lookup_sample(parent_name, request.user)
    else:
        old_split = get_object_or_404(models.SampleSplit, pk=utils.convert_id_to_int(old_split_id))
        parent = old_split.parent
        permissions.assert_can_edit_sample(request.user, parent)
        if parent.last_process_if_split() != old_split:
            raise Http404("This split is not the last one in the sample's process list.")
    number_of_old_pieces = old_split.pieces.count() if old_split else 0
    automatic_split_form = AutomaticSplitForm(request.POST)
    if request.method == "POST":
        new_name_forms, global_data_form, automatic_split_form, structure_changed, next_prefix = \
            forms_from_post_data(request.POST, parent, request.user)
        all_valid = is_all_valid(new_name_forms, global_data_form, automatic_split_form)
        referentially_valid = is_referentially_valid(new_name_forms, global_data_form, number_of_old_pieces)
        if all_valid and referentially_valid and not structure_changed:
            sample_split, new_pieces = save_to_database(new_name_forms, global_data_form, parent, old_split, request.user)
            utils.Reporter(request.user).report_sample_split(
                sample_split, global_data_form.cleaned_data["sample_completely_split"])
            return utils.successful_response(
                request, _("Sample “{sample}” was successfully split.").format(sample=parent),
                "show_sample_by_name", {"sample_name": parent.name}, json_response=new_pieces)
    else:
        new_name_forms, global_data_form, automatic_split_form = forms_from_database(parent, request.user)
        next_prefix = "0"
    new_name_forms.append(NewNameForm(request.user, parent.name,
                                      initial={"new_name": parent.name, "new_purpose": parent.purpose},
                                      prefix=next_prefix))
    return render(request, "samples/split_and_rename.html",
                  {"title": _("Split sample “{sample}”").format(sample=parent),
                   "new_names": list(zip(range(number_of_old_pieces + 1,
                                               number_of_old_pieces + 1 + len(new_name_forms)),
                                         new_name_forms)),
                   "automatic_split": automatic_split_form,
                   "global_data": global_data_form,
                   "old_split": old_split})
コード例 #21
0
ファイル: result.py プロジェクト: colima/juliabase
    def __init__(self, request, process_id):
        """Class constructor.

        :param request: the current HTTP Request object
        :param process_id: the ID of the result to be edited; ``None`` if we
            create a new one

        :type request: HttpRequest
        :type process_id: unicode or NoneType
        """
        self.result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id)) if process_id else None
        self.user = request.user
        self.query_string_dict = request.GET if not self.result else None
コード例 #22
0
ファイル: result.py プロジェクト: muescha/juliabase
    def __init__(self, request, process_id):
        """Class constructor.

        :param request: the current HTTP Request object
        :param process_id: the ID of the result to be edited; ``None`` if we
            create a new one

        :type request: HttpRequest
        :type process_id: unicode or NoneType
        """
        self.result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id)) if process_id else None
        self.user = request.user
        self.query_string_dict = request.GET if not self.result else None
コード例 #23
0
ファイル: layout.py プロジェクト: Midnighter/juliabase
def show_layout(request, process_id, sample_id):
    sample = get_object_or_404(models.Sample,
                               pk=utils.convert_id_to_int(sample_id))
    process = get_object_or_404(
        models.Process, pk=utils.convert_id_to_int(process_id)).actual_instance

    pdf_filename = "/tmp/layouts_{0}_{1}.pdf".format(process.id, sample.id)
    jb_common.utils.base.mkdirs(pdf_filename)
    layout = layouts.get_layout(sample, process)
    if not layout:
        raise Http404("error")
    layout.generate_pdf(pdf_filename)

    png_filename = os.path.join(settings.CACHE_ROOT, "layouts",
                                "{0}-{1}.png".format(process.id, sample.id))
    jb_common.utils.base.mkdirs(png_filename)
    resolution = settings.THUMBNAIL_WIDTH / (layout.width / 72)
    subprocess.check_call([
        "gs", "-q", "-dNOPAUSE", "-dBATCH", "-sDEVICE=pngalpha",
        "-r{0}".format(resolution), "-dEPSCrop",
        "-sOutputFile=" + png_filename, pdf_filename
    ])
    return jb_common.utils.base.static_file_response(png_filename)
コード例 #24
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))))
コード例 #25
0
ファイル: plots.py プロジェクト: colima/juliabase
def show_plot(request, process_id, plot_id, thumbnail):
    """Shows a particular plot.  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 process_id: the database ID of the process to show
    :param plot_id: the plot_id of the image.  This is mostly ``u""`` because
        most measurement models have only one graphics.
    :param thumbnail: whether we serve a thumbnail instead of a real PDF plot

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

    :return:
      the HTTP response object with the image

    :rtype: HttpResponse
    """
    process = get_object_or_404(models.Process,
                                pk=utils.convert_id_to_int(process_id))
    process = process.actual_instance
    permissions.assert_can_view_physical_process(request.user, process)
    plot_filepath = process.calculate_plot_locations(
        plot_id)["thumbnail_file" if thumbnail else "plot_file"]
    datafile_name = process.get_datafile_name(plot_id)
    if datafile_name is None:
        raise Http404("No such plot available.")
    timestamps = [] if thumbnail else [
        sample.last_modified for sample in process.samples.all()
    ]
    timestamps.append(process.last_modified)
    datafile_names = datafile_name if isinstance(datafile_name,
                                                 list) else [datafile_name]
    if not all(os.path.exists(filename) for filename in datafile_names):
        raise Http404("One of the raw datafiles was not found.")
    content = get_cached_file_content(
        plot_filepath,
        partial(generate_plot, process, plot_id, thumbnail, datafile_name),
        datafile_names, timestamps)
    return static_response(
        content,
        None if thumbnail else process.get_plotfile_basename(plot_id) + ".pdf",
        mimetypes.guess_type(plot_filepath))
コード例 #26
0
ファイル: task_lists.py プロジェクト: muescha/juliabase
def remove(request, task_id):
    """Deletes a task from the database.

    :Paramerters:
    :param request: the current HTTP Request object
    :param task_id: the id from the task, which has to be deleted

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    task = get_object_or_404(Task, id=utils.convert_id_to_int(task_id))
    if task.customer != request.user:
        raise permissions.PermissionError(request.user, _("You are not the customer of this task."))
    utils.Reporter(request.user).report_removed_task(task)
    task.delete()
    return utils.successful_response(request, _("The task was successfully removed."), show)
コード例 #27
0
def edit(request, external_operator_id):
    """View for editing existing external operators.  You can also give the
    operator initials here.

    :param request: the current HTTP Request object
    :param external_operator_id: the database ID for the external operator

    :type request: HttpRequest
    :type external_operator_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    external_operator = get_object_or_404(
        models.ExternalOperator,
        pk=utils.convert_id_to_int(external_operator_id))
    permissions.assert_can_edit_external_operator(request.user,
                                                  external_operator)
    if request.method == "POST":
        external_operator_form = EditExternalOperatorForm(
            request.user, request.POST, instance=external_operator)
        if external_operator_form.is_valid():
            external_operator = external_operator_form.save()
            return utils.successful_response(
                request,
                _("The external operator “{operator}” was successfully changed."
                  ).format(operator=external_operator.name))
    else:
        external_operator_form = EditExternalOperatorForm(
            request.user, instance=external_operator)
    initials_form = utils.InitialsForm(external_operator,
                                       initials_mandatory=True)
    return render(
        request, "samples/edit_external_operator.html", {
            "title":
            _("Edit external operator “{operator}”").format(
                operator=external_operator.name),
            "external_operator":
            external_operator_form,
            "initials":
            initials_form
        })
コード例 #28
0
ファイル: result.py プロジェクト: msincan/juliabase
def show_image(request, process_id):
    """Shows a particular result image.  Although its response is an image
    rather than an HTML file, it is served by Django in order to enforce user
    permissions.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object with the image

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    image_locations = result.get_image_locations()
    return static_file_response(image_locations["image_file"], image_locations["sluggified_filename"])
コード例 #29
0
def show(request, external_operator_id):
    """View for displaying existing external operators.  Only users who are
    allowed to see all samples, and the current contact person are allowed to
    see it.

    :param request: the current HTTP Request object
    :param external_operator_id: the database ID for the external operator

    :type request: HttpRequest
    :type external_operator_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    external_operator = get_object_or_404(
        models.ExternalOperator,
        pk=utils.convert_id_to_int(external_operator_id))
    contact_persons = external_operator.contact_persons.all()
    if permissions.has_permission_to_view_external_operator(
            request.user, external_operator):
        try:
            initials = external_operator.initials
        except models.Initials.DoesNotExist:
            initials = None
        title = _("External operator “{name}”").format(
            name=external_operator.name)
    else:
        title = _("Confidential operator #{number}").format(
            number=external_operator.pk)
        external_operator = None
        initials = None
    return render(
        request, "samples/show_external_operator.html", {
            "title": title,
            "external_operator": external_operator,
            "initials": initials,
            "contact_persons": contact_persons,
            "can_edit": request.user in contact_persons
        })
コード例 #30
0
ファイル: task_lists.py プロジェクト: colima/juliabase
def remove(request, task_id):
    """Deletes a task from the database.

    :Paramerters:
    :param request: the current HTTP Request object
    :param task_id: the id from the task, which has to be deleted

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    task = get_object_or_404(Task, id=utils.convert_id_to_int(task_id))
    if task.customer != request.user:
        raise permissions.PermissionError(
            request.user, _("You are not the customer of this task."))
    utils.Reporter(request.user).report_removed_task(task)
    task.delete()
    return utils.successful_response(request,
                                     _("The task was successfully removed."),
                                     "samples:show_task_lists")
コード例 #31
0
ファイル: result.py プロジェクト: colima/juliabase
def show_image(request, process_id):
    """Shows a particular result image.  Although its response is an image
    rather than an HTML file, it is served by Django in order to enforce user
    permissions.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object with the image

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    image_locations = result.get_image_locations()
    return static_file_response(jb_common.utils.blobs.storage.export(image_locations["image_file"]),
                                image_locations["sluggified_filename"])
コード例 #32
0
ファイル: sample.py プロジェクト: muescha/juliabase
def rename_sample(request):
    """Rename a sample given by its id.  This view should only be available for
    adminstative users.  For normal users use
    ``samples.views.bulk_rename.bulk_rename``

    :param request: the current HTTP Request object

    :type request: HttpRequest

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample_id = request.GET.get("sample_id")
    if sample_id:
        sample = get_object_or_404(models.Sample, pk=utils.convert_id_to_int(sample_id))
        permissions.assert_can_rename_sample(request.user, sample)
    else:
        sample = None
    if request.method == "POST":
        sample_rename_form = SampleRenameForm(request.user, request.POST)
        if sample_rename_form.is_valid():
            old_name = sample_rename_form.cleaned_data["old_name"]
            if not sample:
                sample = models.Sample.objects.get(name=old_name)
            sample.name = sample_rename_form.cleaned_data["new_name"]
            sample.save()
            if sample_rename_form.cleaned_data["create_alias"]:
                models.SampleAlias.objects.create(name=old_name, sample=sample)
            feed_reporter = utils.Reporter(request.user)
            feed_reporter.report_edited_samples([sample], {"important": True,
               "description": _("Sample {old_name} was renamed to {new_name}").
                                                           format(new_name=sample.name, old_name=old_name)})
            return utils.successful_response(
                request, _("Sample {sample} was successfully changed in the database.").format(sample=sample))
    else:
        sample_rename_form = SampleRenameForm(request.user, initial={"old_name": sample.name if sample else ""})
    title = capfirst(_("rename sample")) + " “{sample}”".format(sample=sample) if sample else ""
    return render(request, "samples/rename_sample.html", {"title": title, "sample_rename": sample_rename_form})
コード例 #33
0
ファイル: json_client.py プロジェクト: Midnighter/juliabase
def substrate_by_sample(request, sample_id):
    """Searches for the substrate of a sample.  It returns a dictionary with
    the substrate data.  If the sample isn't found, a 404 is returned.  If
    something else went wrong (in particular, no substrate was found),
    ``False`` is returned.

    :param request: the HTTP request object
    :param sample_id: the primary key of the sample

    :type request: HttpRequest
    :type sample_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    if not request.user.is_staff:
        return respond_in_json(False)
    sample = get_object_or_404(models.Sample, pk=utils.convert_id_to_int(sample_id))
    substrate = get_substrate(sample)
    return respond_in_json(substrate.get_data())
コード例 #34
0
ファイル: json_client.py プロジェクト: msincan/juliabase
def substrate_by_sample(request, sample_id):
    """Searches for the substrate of a sample.  It returns a dictionary with
    the substrate data.  If the sample isn't found, a 404 is returned.  If
    something else went wrong (in particular, no substrate was found),
    ``False`` is returned.

    :param request: the HTTP request object
    :param sample_id: the primary key of the sample

    :type request: HttpRequest
    :type sample_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    if not request.user.is_superuser:
        return respond_in_json(False)
    sample = get_object_or_404(models.Sample, pk=utils.convert_id_to_int(sample_id))
    substrate = get_substrate(sample)
    return respond_in_json(substrate.get_data())
コード例 #35
0
ファイル: stack.py プロジェクト: msincan/juliabase
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))))
コード例 #36
0
ファイル: sample.py プロジェクト: muescha/juliabase
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
コード例 #37
0
ファイル: status.py プロジェクト: msincan/juliabase
def withdraw(request, id_):
    """This function withdraws a status message for good.  Note that it
    withdraws it for all its connected process types.  It is idempotent.

    :param request: the current HTTP Request object
    :param id_: the id of the message to be withdrawn

    :type request: HttpRequest
    :type id_: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    status_message = get_object_or_404(models.StatusMessage, withdrawn=False, pk=utils.convert_id_to_int(id_))
    if request.user != status_message.operator:
        raise PermissionError(request.user, "You cannot withdraw status messages of another user.")
    status_message.withdrawn = True
    status_message.save()
    for process_class in status_message.process_classes.all():
        utils.Reporter(request.user).report_withdrawn_status_message(process_class, status_message)
    return utils.successful_response(request, _("The status message was successfully withdrawn."), show)
コード例 #38
0
ファイル: result.py プロジェクト: colima/juliabase
def show_thumbnail(request, process_id):
    """Shows the thumnail of a particular result image.  Although its response
    is an image rather than an HTML file, it is served by Django in order to
    enforce user permissions.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object with the thumbnail image

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    image_locations = result.get_image_locations()
    image_filename = image_locations["image_file"]
    thumbnail_file = image_locations["thumbnail_file"]
    content = get_cached_file_content(thumbnail_file, partial(generate_thumbnail, result, image_filename),
                                      [image_filename])
    return static_response(content, content_type="image/png")
コード例 #39
0
ファイル: result.py プロジェクト: muescha/juliabase
def show(request, process_id):
    """Shows a particular result process.  The main purpose of this view is to
    be able to visit a result directly from a feed entry about a new/edited
    result.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    if jb_common.utils.base.is_json_requested(request):
        return jb_common.utils.base.respond_in_json(result.get_data())
    template_context = {"title": _("Result “{title}”").format(title=result.title), "result": result,
                        "samples": result.samples.all(), "sample_series": result.sample_series.all()}
    template_context.update(utils.digest_process(result, request.user))
    return render(request, "samples/show_single_result.html", template_context)
コード例 #40
0
ファイル: sample.py プロジェクト: colima/juliabase
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
コード例 #41
0
ファイル: result.py プロジェクト: muescha/juliabase
def show_thumbnail(request, process_id):
    """Shows the thumnail of a particular result image.  Although its response
    is an image rather than an HTML file, it is served by Django in order to
    enforce user permissions.

    :param request: the current HTTP Request object
    :param process_id: the database ID of the result to show

    :type request: HttpRequest
    :type process_id: unicode

    :return:
      the HTTP response object with the thumbnail image

    :rtype: HttpResponse
    """
    result = get_object_or_404(models.Result, pk=utils.convert_id_to_int(process_id))
    permissions.assert_can_view_result_process(request.user, result)
    image_locations = result.get_image_locations()
    image_filename = image_locations["image_file"]
    thumbnail_file = image_locations["thumbnail_file"]
    content = get_cached_file_content(thumbnail_file, partial(generate_thumbnail, result, image_filename),
                                      [image_filename])
    return static_response(content, content_type="image/png")
コード例 #42
0
ファイル: bulk_rename.py プロジェクト: msincan/juliabase
def bulk_rename(request):
    """View for bulk-renaming samples that have had a provisional name so far.  If
    the user doesn't have initials yet, he is redirected to his preferences
    page.

    :param request: the current HTTP Request object

    :type request: HttpRequest

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    # FixMe: Get rid of the "numbers" parameter.  I think it is only used in
    # the remote client.
    if "numbers" in request.GET:
        numbers_list = request.GET.get("numbers", "")
        samples = [get_object_or_404(models.Sample, name="*" + number.zfill(5)) for number in numbers_list.split(",")]
    elif "ids" in request.GET:
        ids = request.GET["ids"].split(",")
        samples = [get_object_or_404(models.Sample, pk=utils.convert_id_to_int(id_)) for id_ in ids]
        if not all(utils.sample_name_format(sample.name) in utils.get_renamable_name_formats() for sample in samples):
            raise Http404("Some given samples cannot be renamed.")
    else:
        samples = None
    if not samples:
        raise Http404("No samples given.")
    for sample in samples:
        permissions.assert_can_edit_sample(request.user, sample)

    available_prefixes = find_prefixes(request.user)
    if not available_prefixes and any("{user_initials}" in format_ for format_ in settings.NAME_PREFIX_TEMPLATES) \
       and not models.Initials.objects.filter(user=request.user).exists():
        query_string = "initials_mandatory=True&next=" + django.utils.http.urlquote_plus(
            request.path + "?" + request.META["QUERY_STRING"], safe="/")
        messages.info(request, _("You may change the sample names, but you must choose initials first."))
        return utils.successful_response(request, view="samples.views.user_details.edit_preferences",
                                         kwargs={"login_name": request.user.username},
                                         query_string=query_string, forced=True)
    single_prefix = available_prefixes[0][1] if len(available_prefixes) == 1 else None
    if request.method == "POST":
        if single_prefix:
            prefixes_form = None
            prefix = single_prefix
        elif available_prefixes:
            prefixes_form = PrefixesForm(available_prefixes, request.POST)
            prefix = prefixes_form.cleaned_data["prefix"] if prefixes_form.is_valid() else ""
        else:
            prefixes_form = None
            prefix = ""
        if prefix == "*":
            prefix = ""
        new_name_forms = [NewNameForm(request.user, prefix, sample, request.POST, prefix=str(sample.pk))
                          for sample in samples]
        all_valid = prefixes_form is None or prefixes_form.is_valid()
        all_valid = all([new_name_form.is_valid() for new_name_form in new_name_forms]) and all_valid
        referentially_valid = is_referentially_valid(samples, new_name_forms)
        if all_valid and referentially_valid:
            for sample, new_name_form in zip(samples, new_name_forms):
                if not sample.name.startswith("*"):
                    models.SampleAlias(name=sample.name, sample=sample).save()
                sample.name = new_name_form.cleaned_data["name"]
                sample.save()
            return utils.successful_response(request, _("Successfully renamed the samples."))
    else:
        prefixes_form = PrefixesForm(available_prefixes, initial={"prefix": available_prefixes[0][0]}) \
                            if available_prefixes else None
        new_name_forms = [NewNameForm(request.user, "", sample, prefix=str(sample.pk)) for sample in samples]
    return render(request, "samples/bulk_rename.html",
                  {"title": _("Rename samples"),
                   "prefixes": prefixes_form, "single_prefix": single_prefix,
                   "samples": list(zip(samples, new_name_forms))})
コード例 #43
0
def show_plot(request, process_id, plot_id, thumbnail):
    """Shows a particular plot.  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 process_id: the database ID of the process to show
    :param plot_id: the plot_id of the image.  This is mostly ``u""`` because
        most measurement models have only one graphics.
    :param thumbnail: whether we serve a thumbnail instead of a real PDF plot

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

    :return:
      the HTTP response object with the image

    :rtype: HttpResponse
    """
    process = get_object_or_404(models.Process, pk=utils.convert_id_to_int(process_id))
    process = process.actual_instance
    permissions.assert_can_view_physical_process(request.user, process)
    plot_filepath = process.calculate_plot_locations(plot_id)["thumbnail_file" if thumbnail else "plot_file"]
    datafile_name = process.get_datafile_name(plot_id)
    if datafile_name is None:
        raise Http404("No such plot available.")
    timestamps = [] if thumbnail else [sample.last_modified for sample in process.samples.all()]
    timestamps.append(process.last_modified)
    if datafile_name:
        datafile_names = datafile_name if isinstance(datafile_name, list) else [datafile_name]
        if not all(os.path.exists(filename) for filename in datafile_names):
            raise Http404("One of the raw datafiles was not found.")
        update_necessary = jb_common.utils.base.is_update_necessary(plot_filepath, datafile_names, timestamps)
    else:
        update_necessary = jb_common.utils.base.is_update_necessary(plot_filepath, timestamps=timestamps)
    if update_necessary:
        try:
            if thumbnail:
                figure = Figure(frameon=False, figsize=(4, 3))
                canvas = FigureCanvasAgg(figure)
                axes = figure.add_subplot(111)
                axes.set_position((0.17, 0.16, 0.78, 0.78))
                axes.grid(True)
                process.draw_plot(axes, plot_id, datafile_name, for_thumbnail=True)
                jb_common.utils.base.mkdirs(plot_filepath)
                canvas.print_figure(plot_filepath, dpi=settings.THUMBNAIL_WIDTH / 4)
            else:
                figure = Figure()
                canvas = FigureCanvasAgg(figure)
                axes = figure.add_subplot(111)
                axes.grid(True)
                axes.set_title(six.text_type(process))
                process.draw_plot(axes, plot_id, datafile_name, for_thumbnail=False)
                # FixMe: Activate this line with Matplotlib 1.1.0.
#                figure.tight_layout()
                jb_common.utils.base.mkdirs(plot_filepath)
                canvas.print_figure(plot_filepath, format="pdf")
            storage_changed.send(models.Process)
        except PlotError as e:
            raise Http404(six.text_type(e) or "Plot could not be generated.")
    return jb_common.utils.base.static_file_response(plot_filepath,
                                                     None if thumbnail else process.get_plotfile_basename(plot_id) + ".pdf")
コード例 #44
0
ファイル: plots.py プロジェクト: msincan/juliabase
def show_plot(request, process_id, plot_id, thumbnail):
    """Shows a particular plot.  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 process_id: the database ID of the process to show
    :param plot_id: the plot_id of the image.  This is mostly ``u""`` because
        most measurement models have only one graphics.
    :param thumbnail: whether we serve a thumbnail instead of a real PDF plot

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

    :return:
      the HTTP response object with the image

    :rtype: HttpResponse
    """
    process = get_object_or_404(models.Process, pk=utils.convert_id_to_int(process_id))
    process = process.actual_instance
    permissions.assert_can_view_physical_process(request.user, process)
    plot_filepath = process.calculate_plot_locations(plot_id)["thumbnail_file" if thumbnail else "plot_file"]
    datafile_name = process.get_datafile_name(plot_id)
    if datafile_name is None:
        raise Http404("No such plot available.")
    timestamps = [] if thumbnail else [sample.last_modified for sample in process.samples.all()]
    timestamps.append(process.last_modified)
    if datafile_name:
        datafile_names = datafile_name if isinstance(datafile_name, list) else [datafile_name]
        if not all(os.path.exists(filename) for filename in datafile_names):
            raise Http404("One of the raw datafiles was not found.")
        update_necessary = jb_common.utils.base.is_update_necessary(plot_filepath, datafile_names, timestamps)
    else:
        update_necessary = jb_common.utils.base.is_update_necessary(plot_filepath, timestamps=timestamps)
    if update_necessary:
        try:
            if thumbnail:
                figure = Figure(frameon=False, figsize=(4, 3))
                canvas = FigureCanvasAgg(figure)
                axes = figure.add_subplot(111)
                axes.set_position((0.17, 0.16, 0.78, 0.78))
                axes.grid(True)
                process.draw_plot(axes, plot_id, datafile_name, for_thumbnail=True)
                jb_common.utils.base.mkdirs(plot_filepath)
                canvas.print_figure(plot_filepath, dpi=settings.THUMBNAIL_WIDTH / 4)
            else:
                figure = Figure()
                canvas = FigureCanvasAgg(figure)
                axes = figure.add_subplot(111)
                axes.grid(True)
                axes.set_title(six.text_type(process))
                process.draw_plot(axes, plot_id, datafile_name, for_thumbnail=False)
                # FixMe: Activate this line with Matplotlib 1.1.0.
#                figure.tight_layout()
                jb_common.utils.base.mkdirs(plot_filepath)
                canvas.print_figure(plot_filepath, format="pdf")
            storage_changed.send(models.Process)
        except PlotError as e:
            raise Http404(six.text_type(e) or "Plot could not be generated.")
        except ValueError as e:
            raise Http404("Plot could not be generated: " + e.args[0])
    return jb_common.utils.base.static_file_response(plot_filepath,
                                                     None if thumbnail else process.get_plotfile_basename(plot_id) + ".pdf")
コード例 #45
0
ファイル: json_client.py プロジェクト: Midnighter/juliabase
def add_sample(request):
    """Adds a new sample to the database.  It is added without processes.  This
    view can only be used by admin accounts.

    :param request: the current HTTP Request object; it must contain the sample
        data in the POST data.

    :return:
      The primary key of the created sample.  ``False`` if something went
      wrong.  It may return a 404 if the topic or the currently responsible
      person wasn't found.

    :rtype: HttpResponse
    """
    try:
        name = request.POST["name"]
        current_location = request.POST["current_location"]
        currently_responsible_person = request.POST[
            "currently_responsible_person"]
        purpose = request.POST.get("purpose", "")
        tags = request.POST.get("tags", "")
        topic = request.POST.get("topic")
    except KeyError as error:
        raise JSONRequestException(
            3, "'{}' parameter missing.".format(error.args[0]))
    if len(name) > 30:
        raise JSONRequestException(5, "The sample name is too long.")
    name_format = utils.sample_name_format(name)
    if name_format is None or \
       not request.user.is_staff and name_format not in settings.SAMPLE_NAME_FORMATS["provisional"].get("possible_renames", set()):
        raise JSONRequestException(5, "The sample name is invalid.")
    eligible_users = django.contrib.auth.models.User.objects.filter(
        is_active=True, jb_user_details__department__isnull=False)
    try:
        currently_responsible_person = eligible_users.get(
            pk=utils.convert_id_to_int(currently_responsible_person))
    except django.contrib.auth.models.User.DoesNotExist:
        raise Http404("Currently reponsible user not found.")
    if topic:
        all_topics = Topic.objects.all() if request.user.is_staff else \
                     Topic.objects.filter(Q(confidential=False) | Q(members=request.user))
        try:
            topic = all_topics.get(pk=utils.convert_id_to_int(topic))
        except Topic.DoesNotExist:
            raise Http404("Topic not found")
    try:
        sample = models.Sample.objects.create(
            name=name,
            current_location=current_location,
            currently_responsible_person=currently_responsible_person,
            purpose=purpose,
            tags=tags,
            topic=topic)
        # They will be shadowed anyway.  Nevertheless, this action is an
        # emergency measure.  Probably the samples the aliases point to should
        # be merged with the sample but this can't be decided automatically.
        models.SampleAlias.objects.filter(name=name).delete()
    except IntegrityError as error:
        error_message = "The sample with this data could not be added."
        if request.user.is_staff:
            error_message += " {}".format(error)
        raise JSONRequestException(5, error_message)
    sample.watchers.add(request.user)
    return respond_in_json(sample.pk)
コード例 #46
0
ファイル: task_lists.py プロジェクト: colima/juliabase
def edit(request, task_id):
    """Edit or create a task.

    :param request: the current HTTP Request object
    :param task_id: number of the task to be edited.  If this is
        ``None``, create a new one.

    :type request: HttpRequest
    :type task_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    task = get_object_or_404(
        Task, id=utils.convert_id_to_int(task_id)) if task_id else None
    user = request.user
    if task and user != task.customer:
        permissions.assert_can_add_physical_process(
            request.user, task.process_class.model_class())
    preset_sample = utils.extract_preset_sample(
        request) if not task_id else None
    if request.method == "POST":
        task_form = TaskForm(user, request.POST, instance=task)
        samples_form = SamplesForm(user, preset_sample, task, request.POST)
        if task_id:
            old_task = copy.copy(task)
            old_samples = set(task.samples.all())
        if task_form.is_valid() and (not samples_form.is_bound
                                     or samples_form.is_valid()):
            task = save_to_database(task_form,
                                    samples_form,
                                    old_task=old_task if task_id else None)
            if task_id:
                edit_description = {"important": True, "description": ""}
                if old_task.status != task.status:
                    edit_description["description"] += \
                        _("* Status is now “{new_status}”.\n").format(new_status=task.get_status_display())
                if old_task.priority != task.priority:
                    edit_description["description"] += \
                        _("* Priority is now “{new_priority}̣”.\n").format(new_priority=task.get_priority_display())
                if old_task.finished_process != task.finished_process:
                    edit_description["description"] += _(
                        "* Connected process.\n")
                if old_task.operator != task.operator:
                    if task.operator:
                        edit_description["description"] += _(
                            "* Operator is now {operator}.\n").format(
                                operator=common_utils.get_really_full_name(
                                    task.operator))
                    else:
                        edit_description["description"] += _(
                            "* No operator is set anymore.\n")
                if old_samples != set(task.samples.all()):
                    edit_description["description"] += "* {0}.\n".format(
                        common_utils.capitalize_first_letter(_("samples")))
                if old_task.comments != task.comments:
                    edit_description["description"] += "* {0}.\n".format(
                        common_utils.capitalize_first_letter(_("comments")))
            else:
                edit_description = None
            utils.Reporter(request.user).report_task(task, edit_description)
            message = _("Task was {verb} successfully.").format(
                verb=_("edited") if task_id else _("added"))
            return utils.successful_response(request, message,
                                             "samples:show_task_lists")
    else:
        samples_form = SamplesForm(user, preset_sample, task)
        initial = {}
        if "process_class" in request.GET:
            initial["process_class"] = request.GET["process_class"]
        task_form = TaskForm(request.user, instance=task, initial=initial)
    title = capfirst(_("edit task")) if task else capfirst(_("add task"))
    return render(request, "samples/edit_task.html", {
        "title": title,
        "task": task_form,
        "samples": samples_form
    })
コード例 #47
0
ファイル: task_lists.py プロジェクト: muescha/juliabase
def edit(request, task_id):
    """Edit or create a task.

    :param request: the current HTTP Request object
    :param task_id: number of the task to be edited.  If this is
        ``None``, create a new one.

    :type request: HttpRequest
    :type task_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    task = get_object_or_404(Task, id=utils.convert_id_to_int(task_id)) if task_id else None
    user = request.user
    if task and user != task.customer:
        permissions.assert_can_add_physical_process(request.user, task.process_class.model_class())
    preset_sample = utils.extract_preset_sample(request) if not task_id else None
    if request.method == "POST":
        task_form = TaskForm(user, request.POST, instance=task)
        samples_form = SamplesForm(user, preset_sample, task, request.POST)
        if task_id:
            old_task = copy.copy(task)
            old_samples = set(task.samples.all())
        if task_form.is_valid() and (not samples_form.is_bound or samples_form.is_valid()):
            task = save_to_database(task_form, samples_form, old_task=old_task if task_id else None)
            if task_id:
                edit_description = {"important": True, "description": ""}
                if old_task.status != task.status:
                    edit_description["description"] += \
                        _("* Status is now “{new_status}”.\n").format(new_status=task.get_status_display())
                if old_task.priority != task.priority:
                    edit_description["description"] += \
                        _("* Priority is now “{new_priority}̣”.\n").format(new_priority=task.get_priority_display())
                if old_task.finished_process != task.finished_process:
                    edit_description["description"] += _("* Connected process.\n")
                if old_task.operator != task.operator:
                    if task.operator:
                        edit_description["description"] += _("* Operator is now {operator}.\n").format(
                            operator=common_utils.get_really_full_name(task.operator))
                    else:
                        edit_description["description"] += _("* No operator is set anymore.\n")
                if old_samples != set(task.samples.all()):
                    edit_description["description"] += "* {0}.\n".format(common_utils.capitalize_first_letter(_("samples")))
                if old_task.comments != task.comments:
                    edit_description["description"] += "* {0}.\n".format(common_utils.capitalize_first_letter(_("comments")))
            else:
                edit_description = None
            utils.Reporter(request.user).report_task(task, edit_description)
            message = _("Task was {verb} successfully.").format(verb=_("edited") if task_id else _("added"))
            return utils.successful_response(request, message, "samples.views.task_lists.show")
    else:
        samples_form = SamplesForm(user, preset_sample, task)
        initial = {}
        if "process_class" in request.GET:
            initial["process_class"] = request.GET["process_class"]
        task_form = TaskForm(request.user, instance=task, initial=initial)
    title = capfirst(_("edit task")) if task else capfirst(_("add task"))
    return render(request, "samples/edit_task.html", {"title": title, "task": task_form, "samples": samples_form})
コード例 #48
0
ファイル: claim.py プロジェクト: Midnighter/juliabase
def show(request, claim_id):
    """View for reviewing a claim.

    :param request: the current HTTP Request object
    :param claim_id: the primary key of the claim to be viewed

    :type request: HttpRequest
    :type claim_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    _ = ugettext
    claim = get_object_or_404(models.SampleClaim,
                              pk=utils.convert_id_to_int(claim_id))
    is_reviewer = request.user == claim.reviewer or request.user.is_staff
    is_requester = request.user == claim.requester
    if not is_reviewer and not is_requester:
        raise permissions.PermissionError(
            request.user,
            _("You are neither the requester nor the reviewer of this claim."))
    if request.method == "POST" and not claim.closed:
        withdraw_form = CloseForm(_("withdraw claim"),
                                  request.POST,
                                  prefix="withdraw") if is_requester else None
        approve_form = CloseForm(_("approve claim"),
                                 request.POST,
                                 prefix="approve") if is_reviewer else None
        all_valid = (withdraw_form is None or withdraw_form.is_valid()) and (
            approve_form is None or approve_form.is_valid())
        referencially_valid = is_referentially_valid(withdraw_form,
                                                     approve_form)
        if all_valid and referencially_valid:
            approved = approve_form and approve_form.cleaned_data["close"]
            closed = approved or (withdraw_form
                                  and withdraw_form.cleaned_data["close"])
            response = None
            if approved:
                sample_list = list(claim.samples.all())
                for sample in sample_list:
                    sample.currently_responsible_person = claim.requester
                    sample.save()
                sample_enumeration = "    " + ",\n    ".join(
                    six.text_type(sample) for sample in sample_list)
                _ = lambda x: x
                send_email(
                    _("Sample request approved"),
                    _("""Hello {requester},

your sample claim was approved.  You are now the “currently
responsible person” of the following samples:

{samples}

JuliaBase.
"""), claim.requester, {
                        "requester": get_really_full_name(claim.requester),
                        "samples": sample_enumeration
                    })
                _ = ugettext
                response = \
                    utils.successful_response(request,
                                              _("Sample claim {id_} was successfully approved.").format(id_=claim.pk))
            if closed:
                claim.closed = True
                claim.save()
                response = response or \
                    utils.successful_response(request,
                                              _("Sample claim {id_} was successfully withdrawn.").format(id_=claim.pk))
            return response
    else:
        withdraw_form = CloseForm(_("withdraw claim"),
                                  prefix="withdraw") if is_requester else None
        approve_form = CloseForm(_("approve claim"),
                                 prefix="approve") if is_reviewer else None
    return render(
        request, "samples/show_claim.html", {
            "title": _("Claim #{number}").format(number=claim_id),
            "claim": claim,
            "is_reviewer": is_reviewer,
            "is_requester": is_requester,
            "withdraw": withdraw_form,
            "approve": approve_form
        })
コード例 #49
0
ファイル: split_and_rename.py プロジェクト: colima/juliabase
def split_and_rename(request, parent_name=None, old_split_id=None):
    """Both splitting of a sample and re-split of an already existing split
    are handled here.  *Either* ``parent_name`` *or* ``old_split`` are unequal
    to ``None``.

    :param request: the current HTTP Request object
    :param parent_name: if given, the name of the sample to be split
    :param old_split_id: if given the process ID of the split to be modified

    :type request: HttpRequest
    :type parent_name: unicode or NoneType
    :type old_split_id: int or NoneType

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    assert (parent_name or old_split_id) and not (parent_name and old_split_id)
    if parent_name:
        old_split = None
        parent = utils.lookup_sample(parent_name, request.user)
    else:
        old_split = get_object_or_404(models.SampleSplit,
                                      pk=utils.convert_id_to_int(old_split_id))
        parent = old_split.parent
        permissions.assert_can_edit_sample(request.user, parent)
        if parent.last_process_if_split() != old_split:
            raise Http404(
                "This split is not the last one in the sample's process list.")
    number_of_old_pieces = old_split.pieces.count() if old_split else 0
    automatic_split_form = AutomaticSplitForm(request.POST)
    if request.method == "POST":
        new_name_forms, global_data_form, automatic_split_form, structure_changed, next_prefix = \
            forms_from_post_data(request.POST, parent, request.user)
        all_valid = is_all_valid(new_name_forms, global_data_form,
                                 automatic_split_form)
        referentially_valid = is_referentially_valid(new_name_forms,
                                                     global_data_form,
                                                     number_of_old_pieces)
        if all_valid and referentially_valid and not structure_changed:
            sample_split, new_pieces = save_to_database(
                new_name_forms, global_data_form, parent, old_split,
                request.user)
            utils.Reporter(request.user).report_sample_split(
                sample_split,
                global_data_form.cleaned_data["sample_completely_split"])
            return utils.successful_response(
                request,
                _("Sample “{sample}” was successfully split.").format(
                    sample=parent),
                "samples:show_sample_by_name", {"sample_name": parent.name},
                json_response=new_pieces)
    else:
        new_name_forms, global_data_form, automatic_split_form = forms_from_database(
            parent, request.user)
        next_prefix = "0"
    new_name_forms.append(
        NewNameForm(request.user,
                    parent.name,
                    initial={
                        "new_name": parent.name,
                        "new_purpose": parent.purpose
                    },
                    prefix=next_prefix))
    return render(
        request, "samples/split_and_rename.html", {
            "title":
            _("Split sample “{sample}”").format(sample=parent),
            "new_names":
            list(
                zip(
                    range(number_of_old_pieces + 1, number_of_old_pieces + 1 +
                          len(new_name_forms)), new_name_forms)),
            "automatic_split":
            automatic_split_form,
            "global_data":
            global_data_form,
            "old_split":
            old_split
        })
コード例 #50
0
def bulk_rename(request):
    """View for bulk-renaming samples that have had a provisional name so far.  If
    the user doesn't have initials yet, he is redirected to his preferences
    page.

    :param request: the current HTTP Request object

    :type request: HttpRequest

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    # FixMe: Get rid of the "numbers" parameter.  I think it is only used in
    # the remote client.
    if "numbers" in request.GET:
        numbers_list = request.GET.get("numbers", "")
        samples = [get_object_or_404(models.Sample, name="*" + number.zfill(5)) for number in numbers_list.split(",")]
    elif "ids" in request.GET:
        ids = request.GET["ids"].split(",")
        samples = [get_object_or_404(models.Sample, pk=utils.convert_id_to_int(id_)) for id_ in ids]
        if not all(utils.sample_name_format(sample.name) in utils.get_renamable_name_formats() for sample in samples):
            raise Http404("Some given samples cannot be renamed.")
    else:
        samples = None
    if not samples:
        raise Http404("No samples given.")
    for sample in samples:
        permissions.assert_can_edit_sample(request.user, sample)

    available_prefixes = find_prefixes(request.user)
    if not available_prefixes and any("{user_initials}" in format_ for format_ in settings.NAME_PREFIX_TEMPLATES) \
       and not models.Initials.objects.filter(user=request.user).exists():
        query_string = "initials_mandatory=True&next=" + django.utils.http.urlquote_plus(
            request.path + "?" + request.META["QUERY_STRING"], safe="/")
        messages.info(request, _("You may change the sample names, but you must choose initials first."))
        return utils.successful_response(request, view="samples.views.user_details.edit_preferences",
                                         kwargs={"login_name": request.user.username},
                                         query_string=query_string, forced=True)
    single_prefix = available_prefixes[0][1] if len(available_prefixes) == 1 else None
    if request.method == "POST":
        if single_prefix:
            prefixes_form = None
            prefix = single_prefix
        elif available_prefixes:
            prefixes_form = PrefixesForm(available_prefixes, request.POST)
            prefix = prefixes_form.cleaned_data["prefix"] if prefixes_form.is_valid() else ""
        else:
            prefixes_form = None
            prefix = ""
        if prefix == "*":
            prefix = ""
        new_name_forms = [NewNameForm(request.user, prefix, sample, request.POST, prefix=str(sample.pk))
                          for sample in samples]
        all_valid = prefixes_form is None or prefixes_form.is_valid()
        all_valid = all([new_name_form.is_valid() for new_name_form in new_name_forms]) and all_valid
        referentially_valid = is_referentially_valid(samples, new_name_forms)
        if all_valid and referentially_valid:
            for sample, new_name_form in zip(samples, new_name_forms):
                if not sample.name.startswith("*"):
                    models.SampleAlias(name=sample.name, sample=sample).save()
                sample.name = new_name_form.cleaned_data["name"]
                sample.save()
            return utils.successful_response(request, _("Successfully renamed the samples."))
    else:
        prefixes_form = PrefixesForm(available_prefixes, initial={"prefix": available_prefixes[0][0]}) \
                            if available_prefixes else None
        new_name_forms = [NewNameForm(request.user, "", sample, prefix=str(sample.pk)) for sample in samples]
    return render(request, "samples/bulk_rename.html",
                  {"title": _("Rename samples"),
                   "prefixes": prefixes_form, "single_prefix": single_prefix,
                   "samples": list(zip(samples, new_name_forms))})
コード例 #51
0
ファイル: claim.py プロジェクト: muescha/juliabase
def show(request, claim_id):
    """View for reviewing a claim.

    :param request: the current HTTP Request object
    :param claim_id: the primary key of the claim to be viewed

    :type request: HttpRequest
    :type claim_id: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    _ = ugettext
    claim = get_object_or_404(models.SampleClaim, pk=utils.convert_id_to_int(claim_id))
    is_reviewer = request.user == claim.reviewer or request.user.is_superuser
    is_requester = request.user == claim.requester
    if not is_reviewer and not is_requester:
        raise permissions.PermissionError(request.user, _("You are neither the requester nor the reviewer of this claim."))
    if request.method == "POST" and not claim.closed:
        withdraw_form = CloseForm(_("withdraw claim"), request.POST, prefix="withdraw") if is_requester else None
        approve_form = CloseForm(_("approve claim"), request.POST, prefix="approve") if is_reviewer else None
        all_valid = (withdraw_form is None or withdraw_form.is_valid()) and (approve_form is None or approve_form.is_valid())
        referencially_valid = is_referentially_valid(withdraw_form, approve_form)
        if all_valid and referencially_valid:
            approved = approve_form and approve_form.cleaned_data["close"]
            closed = approved or (withdraw_form and withdraw_form.cleaned_data["close"])
            response = None
            if approved:
                sample_list = list(claim.samples.all())
                for sample in sample_list:
                    sample.currently_responsible_person = claim.requester
                    sample.save()
                sample_enumeration = "    " + ",\n    ".join(six.text_type(sample) for sample in sample_list)
                _ = lambda x: x
                send_email(_("Sample request approved"),
                       _("""Hello {requester},

your sample claim was approved.  You are now the “currently
responsible person” of the following samples:

{samples}

JuliaBase.
"""), claim.requester, {"requester": get_really_full_name(claim.requester), "samples": sample_enumeration})
                _ = ugettext
                response = \
                    utils.successful_response(request,
                                              _("Sample claim {id_} was successfully approved.").format(id_=claim.pk))
            if closed:
                claim.closed = True
                claim.save()
                response = response or \
                    utils.successful_response(request,
                                              _("Sample claim {id_} was successfully withdrawn.").format(id_=claim.pk))
            return response
    else:
        withdraw_form = CloseForm(_("withdraw claim"), prefix="withdraw") if is_requester else None
        approve_form = CloseForm(_("approve claim"), prefix="approve") if is_reviewer else None
    return render(request, "samples/show_claim.html", {"title": _("Claim #{number}").format(number=claim_id),
                                                       "claim": claim, "is_reviewer": is_reviewer,
                                                       "is_requester": is_requester,
                                                       "withdraw": withdraw_form, "approve": approve_form})