Example #1
0
def export(request, sample_name):
    """View for exporting sample data in CSV or JSON format.  Thus, the return
    value is not an HTML response.

    :param request: the current HTTP Request object
    :param sample_name: the name of the sample

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = utils.lookup_sample(sample_name, request.user)
    data = sample.get_data_for_table_export()
    result = utils.table_export(request, data, _("process"))
    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", "")})
Example #2
0
def new(request, sample_name):
    """View for killing samples.  Note that it is not possible to re-kill an
    already dead sample.  Furthermore, you must be the currently responsible
    person to be able to kill a sample.

    :param request: the current HTTP Request object
    :param sample_name: name of the sample to be killed

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = utils.lookup_sample(sample_name, request.user)
    permissions.assert_can_edit_sample(request.user, sample)
    if sample.is_dead():
        raise Http404("Sample is already dead.")
    if request.method == "POST":
        sample_death_form = SampleDeathForm(sample, request.POST)
        if sample_death_form.is_valid():
            sample_death = sample_death_form.save(commit=False)
            sample_death.timestamp = django.utils.timezone.now()
            sample_death.operator = request.user
            sample_death.save()
            sample_death.samples = [sample]
            # FixMe: Feed entries
            return utils.successful_response(request, _("Sample “{sample}” was killed.").format(sample=sample),
                                             "samples:show_sample_by_name", {"sample_name": sample_name})
    else:
        sample_death_form = SampleDeathForm(sample)
    return render(request, "samples/edit_sample_death.html", {"title": _("Kill sample “{sample}”").format(sample=sample),
                                                              "sample_death": sample_death_form})
Example #3
0
def new(request, sample_name):
    """View for killing samples.  Note that it is not possible to re-kill an
    already dead sample.  Furthermore, you must be the currently responsible
    person to be able to kill a sample.

    :param request: the current HTTP Request object
    :param sample_name: name of the sample to be killed

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = utils.lookup_sample(sample_name, request.user)
    permissions.assert_can_edit_sample(request.user, sample)
    if sample.is_dead():
        raise Http404("Sample is already dead.")
    if request.method == "POST":
        sample_death_form = SampleDeathForm(sample, request.POST)
        if sample_death_form.is_valid():
            sample_death = sample_death_form.save(commit=False)
            sample_death.timestamp = datetime.datetime.now()
            sample_death.operator = request.user
            sample_death.save()
            sample_death.samples = [sample]
            # FixMe: Feed entries
            return utils.successful_response(request, _("Sample “{sample}” was killed.").format(sample=sample),
                                             "show_sample_by_name", {"sample_name": sample_name})
    else:
        sample_death_form = SampleDeathForm(sample)
    return render(request, "samples/edit_sample_death.html", {"title": _("Kill sample “{sample}”").format(sample=sample),
                                                              "sample_death": sample_death_form})
Example #4
0
def copy_informal_stack(request, sample_name):
    """View for copying the informal stack of a sample to other samples.

    :param request: the current HTTP Request object
    :param sample_name: the name of the sample

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample, __ = utils.lookup_sample(sample_name,
                                     request.user,
                                     with_clearance=True)
    if request.method == "POST":
        destination_samples_form = DestinationSamplesForm(
            request.user, sample, request.POST)
        if destination_samples_form.is_valid():
            destination_samples = destination_samples_form.cleaned_data[
                "samples"]
            informal_layers = sample.sample_details.informal_layers.all()
            for destination_sample in destination_samples:
                destination_sample.sample_details.informal_layers.all().delete(
                )
                for layer in informal_layers:
                    layer.sample_details = destination_sample.sample_details
                    layer.id = None
                    layer.save()
            feed_reporter = utils.Reporter(request.user)
            message = _(
                "Informal stack was copied from sample {sample}.".format(
                    sample=sample))
            feed_reporter.report_edited_samples(destination_samples,
                                                edit_description={
                                                    "important": False,
                                                    "description": message
                                                })
            return utils.successful_response(
                request,
                _("Informal stack of {sample} was successfully copied.").
                format(sample=sample), "samples:show_sample_by_id", {
                    "sample_id": sample.id,
                    "path_suffix": ""
                })
    else:
        destination_samples_form = DestinationSamplesForm(request.user, sample)
    context = {
        "title": _("Copy informal stack of “{sample}”").format(sample=sample),
        "sample": sample,
        "destination_samples": destination_samples_form
    }
    context.update(sample.sample_details.get_context_for_user(
        request.user, {}))
    return render(request, "samples/copy_informal_stack.html", context)
Example #5
0
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})
Example #6
0
def edit(request, sample_name):
    """View for editing existing samples.  You can't use it to add new
    samples.

    :param request: the current HTTP Request object
    :param sample_name: the name of the sample

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = utils.lookup_sample(sample_name, request.user)
    permissions.assert_can_edit_sample(request.user, sample)
    old_topic, old_responsible_person = sample.topic, sample.currently_responsible_person
    user_details = request.user.samples_user_details
    sample_details = sample.get_sample_details()
    if request.method == "POST":
        sample_form = SampleForm(request.user, request.POST, instance=sample)
        edit_description_form = utils.EditDescriptionForm(request.POST)
        all_valid = all([sample_form.is_valid(), edit_description_form.is_valid()])
        referentially_valid = is_referentially_valid(sample, sample_form, edit_description_form)
        if sample_details:
            sample_details_context, sample_details_valid = \
                sample_details.process_post(request.user, request.POST, sample_form, edit_description_form)
            all_valid = all_valid and sample_details_valid
        else:
            sample_details_context = {}
        if all_valid and referentially_valid:
            sample = sample_form.save()
            if sample_details:
                sample_details.save_form_data(sample_details_context)
            feed_reporter = utils.Reporter(request.user)
            if sample.currently_responsible_person != old_responsible_person:
                sample.currently_responsible_person.my_samples.add(sample)
                feed_reporter.report_new_responsible_person_samples([sample], edit_description_form.cleaned_data)
            if sample.topic and sample.topic != old_topic:
                for watcher in (user_details.user for user_details in sample.topic.auto_adders.all()):
                    watcher.my_samples.add(sample)
                feed_reporter.report_changed_sample_topic([sample], old_topic, edit_description_form.cleaned_data)
            feed_reporter.report_edited_samples([sample], edit_description_form.cleaned_data)
            return utils.successful_response(
                request, _("Sample {sample} was successfully changed in the database.").format(sample=sample),
                by_id, {"sample_id": sample.pk, "path_suffix": ""})
    else:
        sample_form = SampleForm(request.user, instance=sample)
        edit_description_form = utils.EditDescriptionForm()
        sample_details_context = sample_details.process_get(request.user) if sample_details else {}
    context = {"title": _("Edit sample “{sample}”").format(sample=sample), "sample": sample_form,
               "edit_description": edit_description_form}
    context.update(sample_details_context)
    return render(request, "samples/edit_sample.html", context)
Example #7
0
    def samples_and_processes(sample_name, user, post_data=None):
        """Returns the data structure used in the template to display the
        sample with all its processes.

        :param sample_name: the sample or alias of the sample to display
        :param user: the currently logged-in user
        :param post_data: the POST dictionary if it was an HTTP POST request, or
            ``None`` otherwise

        :type sample_name: unicode
        :type user: django.contrib.auth.models.User
        :type post_data: QueryDict

        :return:
          a list with all result processes of this sample in chronological
          order.

        :rtype: `SamplesAndProcesses`
        """
        sample, clearance = utils.lookup_sample(sample_name, user, with_clearance=True)
        cache_key = "sample:{0}-{1}".format(sample.pk, user.jb_user_details.get_data_hash())
        # The following ``10`` is the expectation value of the number of
        # processes.  To get accurate results, use
        # ``samples.processes.count()`` instead.  However, this would slow down
        # JuliaBase.
        samples_and_processes = get_from_cache(cache_key, hits=10)
        if samples_and_processes is None:
            samples_and_processes = SamplesAndProcesses(sample, clearance, user, post_data)
            keys_list_key = "sample-keys:{0}".format(sample.pk)
            with cache_key_locked("sample-lock:{0}".format(sample.pk)):
                keys = cache.get(keys_list_key, [])
                keys.append(cache_key)
                cache.set(keys_list_key, keys, settings.CACHES["default"].get("TIMEOUT", 300) + 10)
                # FixMe: Remove try block when it is clear that request.user is
                # a SimpleLazyObject which is not pickable.  Maybe this can be
                # removed completely if
                # https://code.djangoproject.com/ticket/16563 is fixed.
                try:
                    samples_and_processes.user = unlazy_object(samples_and_processes.user)
                except AttributeError:
                    pass
                cache.set(cache_key, samples_and_processes)
            samples_and_processes.remove_noncleared_process_contexts(user, clearance)
        else:
            samples_and_processes.personalize(user, clearance, post_data)
        return samples_and_processes
Example #8
0
def show(request, sample_name):
    """A view for showing existing samples.

    :param request: the current HTTP Request object
    :param sample_name: the name of the sample

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    start = time.time()
    if request.method == "POST":
        samples_and_processes = SamplesAndProcesses.samples_and_processes(sample_name, request.user, request.POST)
        if samples_and_processes.is_valid():
            added, removed = samples_and_processes.save_to_database()
            if is_json_requested(request):
                return respond_in_json(True)
            if added:
                success_message = ungettext("Sample {samples} was added to My Samples.",
                                            "Samples {samples} were added to My Samples.",
                                            len(added)).format(samples=format_enumeration(added))
            else:
                success_message = ""
            if removed:
                if added:
                    success_message += "  "
                success_message += ungettext("Sample {samples} was removed from My Samples.",
                                             "Samples {samples} were removed from My Samples.",
                                             len(removed)).format(samples=format_enumeration(removed))
            elif not added:
                success_message = _("Nothing was changed.")
            messages.success(request, success_message)
    else:
        if is_json_requested(request):
            sample = utils.lookup_sample(sample_name, request.user)
            return respond_in_json(sample.get_data())
        samples_and_processes = SamplesAndProcesses.samples_and_processes(sample_name, request.user)
    messages.debug(request, "DB-Zugriffszeit: {0:.1f} ms".format((time.time() - start) * 1000))
    return render(request, "samples/show_sample.html",
                  {"title": _("Sample “{sample}”").format(sample=samples_and_processes.sample_context["sample"]),
                   "samples_and_processes": samples_and_processes})
Example #9
0
def latest_split(request, sample_name):
    """Get the database ID of the latest split of a sample, if it is also the
    very latest process for that sample.  In all other cases, return ``None``
    (or an error HTML page if the sample didn't exist).

    :param request: the current HTTP Request object
    :param sample_name: the name of the sample

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = utils.lookup_sample(sample_name, request.user)
    split = sample.last_process_if_split()
    return respond_in_json(split.pk if split else None)
Example #10
0
def latest_split(request, sample_name):
    """Get the database ID of the latest split of a sample, if it is also the
    very latest process for that sample.  In all other cases, return ``None``
    (or an error HTML page if the sample didn't exist).

    :param request: the current HTTP Request object
    :param sample_name: the name of the sample

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = utils.lookup_sample(sample_name, request.user)
    split = sample.last_process_if_split()
    return respond_in_json(split.pk if split else None)
Example #11
0
def add_process(request, sample_name):
    """View for appending a new process to the process list of a sample.

    :param request: the current HTTP Request object
    :param sample_name: the name of the sample

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample = utils.lookup_sample(sample_name, request.user)
    sample_processes, general_processes = get_allowed_processes(request.user, sample)
    for process in general_processes:
        process["url"] += "?sample={0}&next={1}".format(urlquote_plus(sample_name), sample.get_absolute_url())
    return render(request, "samples/add_process.html",
                  {"title": _("Add process to sample “{sample}”").format(sample=sample),
                   "processes": sample_processes + general_processes})
Example #12
0
def copy_informal_stack(request, sample_name):
    """View for copying the informal stack of a sample to other samples.

    :param request: the current HTTP Request object
    :param sample_name: the name of the sample

    :type request: HttpRequest
    :type sample_name: unicode

    :return:
      the HTTP response object

    :rtype: HttpResponse
    """
    sample, __ = utils.lookup_sample(sample_name, request.user, with_clearance=True)
    if request.method == "POST":
        destination_samples_form = DestinationSamplesForm(request.user, sample, request.POST)
        if destination_samples_form.is_valid():
            destination_samples = destination_samples_form.cleaned_data["samples"]
            informal_layers = sample.sample_details.informal_layers.all()
            for destination_sample in destination_samples:
                destination_sample.sample_details.informal_layers.all().delete()
                for layer in informal_layers:
                    layer.sample_details = destination_sample.sample_details
                    layer.id = None
                    layer.save()
            feed_reporter = utils.Reporter(request.user)
            message = _("Informal stack was copied from sample {sample}.".format(sample=sample))
            feed_reporter.report_edited_samples(destination_samples,
                                                edit_description={"important": False, "description": message})
            return utils.successful_response(
                request, _("Informal stack of {sample} was successfully copied.").format(sample=sample),
                "samples.views.sample.by_id", {"sample_id": sample.id, "path_suffix": ""})
    else:
        destination_samples_form = DestinationSamplesForm(request.user, sample)
    context = {"title": _("Copy informal stack of “{sample}”").format(sample=sample),
               "sample": sample, "destination_samples": destination_samples_form}
    context.update(sample.sample_details.get_context_for_user(request.user, {}))
    return render(request, "samples/copy_informal_stack.html", context)
Example #13
0
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
        })