def delete_process(request, process_id): """Deletes an existing physical process. :param request: the current HTTP Request object :param process_id: the process's ID :type request: HttpRequest :type process_id: unicode :return: the HTTP response object :rtype: HttpResponse """ process = get_object_or_404(Process, pk=int_or_zero(process_id)).actual_instance affected_objects = permissions.assert_can_delete_physical_process( request.user, process) for instance in affected_objects: if isinstance(instance, models.Sample): utils.Reporter(request.user).report_deleted_sample(instance) elif isinstance(instance, models.Process): utils.Reporter(request.user).report_deleted_process(instance) success_message = _( "Process {process} was successfully deleted in the database.").format( process=process) process.delete() return utils.successful_response(request, success_message)
def edit(request, id): """View for changing the members of a particular topic, and to set the restriction status. This is only allowed to heads of institute groups and topic managers. :param request: the current HTTP Request object :param id: the id of the topic :type request: HttpRequest :type name: unicode :return: the HTTP response object :rtype: HttpResponse """ topic = get_object_or_404(Topic, id=int_or_zero(id), parent_topic=None) permissions.assert_can_edit_topic(request.user, topic) if request.method == "POST": edit_topic_form = EditTopicForm(request.user, topic, request.POST) added_members = [] removed_members = [] if edit_topic_form.is_valid(): old_manager = topic.manager new_manager = edit_topic_form.cleaned_data["topic_manager"] topic.manager = new_manager old_members = list(topic.members.all()) new_members = edit_topic_form.cleaned_data["members"] + [new_manager] topic.members = new_members topic.confidential = edit_topic_form.cleaned_data["confidential"] topic.save() if old_manager != new_manager: if not old_manager.managed_topics.all(): old_manager.user_permissions.remove(PermissionsModels.topic_manager_permission) if not permissions.has_permission_to_edit_users_topics(new_manager): new_manager.user_permissions.add(PermissionsModels.topic_manager_permission) for user in new_members: if user not in old_members: added_members.append(user) topic.auto_adders.add(user.samples_user_details) for user in old_members: if user not in new_members: removed_members.append(user) topic.auto_adders.remove(user.samples_user_details) if added_members: utils.Reporter(request.user).report_changed_topic_membership(added_members, topic, "added") if removed_members: utils.Reporter(request.user).report_changed_topic_membership(removed_members, topic, "removed") return utils.successful_response( request, _("Members of topic “{name}” were successfully updated.").format(name=topic.name)) else: edit_topic_form = \ EditTopicForm(request.user, topic, initial={"members": topic.members.values_list("pk", flat=True), "topic_manager": topic.manager.pk}) return render(request, "samples/edit_topic.html", {"title": _("Change topic memberships of “{0}”").format(topic.name), "edit_topic": edit_topic_form})
def edit(request, process_id): """View for editing existing results, and for creating new ones. :param request: the current HTTP Request object :param process_id: the ID of the result process; ``None`` if we're creating a new one :type request: HttpRequest :type process_id: str :return: the HTTP response object :rtype: HttpResponse """ form_set = FormSet(request, process_id) if form_set.result: permissions.assert_can_edit_result_process(request.user, form_set.result) if request.method == "POST": form_set.from_post_data(request.POST, request.FILES) result = form_set.save_to_database(request.FILES) if result: utils.Reporter(request.user).report_result_process( result, form_set.edit_description_form.cleaned_data if form_set.edit_description_form else None) return utils.successful_response(request, json_response=result.pk) else: form_set.from_database() form_set.update_previous_dimensions_form() title = _("Edit result") if form_set.result else _("New result") context_dict = {"title": title} context_dict.update(form_set.get_context_dict()) return render(request, "samples/edit_result.html", context_dict)
def new(request): """View for creating a new sample series. Note that you can add arbitrary samples to a sample series, even those you can't see. :param request: the current HTTP Request object :type request: HttpRequest :return: the HTTP response object :rtype: HttpResponse """ if request.method == "POST": sample_series_form = SampleSeriesForm(request.user, request.POST) if sample_series_form.is_valid(): timestamp = datetime.datetime.today() full_name = "{0}-{1}-{2}".format( request.user.username, timestamp.strftime("%y"), sample_series_form.cleaned_data["short_name"]) if models.SampleSeries.objects.filter(name=full_name).exists(): sample_series_form.add_error( "short_name", _("This sample series name is already given.")) elif len(full_name) > models.SampleSeries._meta.get_field( "name").max_length: overfull_letters = len( full_name) - models.SampleSeries._meta.get_field( "name").max_length error_message = ungettext( "The name is {number} letter too long.", "The name is {number} letters too long.", overfull_letters).format(number=overfull_letters) sample_series_form.add_error("short_name", error_message) else: sample_series = sample_series_form.save(commit=False) sample_series.name = full_name sample_series.timestamp = timestamp sample_series.save() sample_series_form.save_m2m() utils.Reporter( request.user).report_new_sample_series(sample_series) return utils.successful_response( request, _("Sample series {name} was successfully added to the database." ).format(name=full_name)) else: sample_series_form = SampleSeriesForm(request.user) return render( request, "samples/edit_sample_series.html", { "title": _("Create new sample series"), "sample_series": sample_series_form, "is_new": True, "name_prefix": "{0}-{1}".format(request.user.username, datetime.datetime.today().strftime("%y")) })
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)
def add(request): """With this function, the messages are stored into the database. It also gets the information for displaying the "add_status_message" template. :param request: the current HTTP Request object :type request: HttpRequest :return: the HTTP response object :rtype: HttpResponse """ if request.method == "POST": status_form = StatusForm(request.user, request.POST) if status_form.is_valid(): status = status_form.save() for process_class in status.process_classes.all(): utils.Reporter(request.user).report_status_message( process_class, status) return utils.successful_response( request, _("The status message was successfully added to the database.") ) else: status_form = StatusForm(request.user) title = _("Add status message") return render(request, "samples/add_status_message.html", { "title": title, "status": status_form })
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)
def split_and_rename_after_deposition(request, deposition_number): """View for renaming and/or splitting samples immediately after they have been deposited in the same run. Optionally, you can give query string parameters of the form ``new-name-21=super`` where 21 is the sample ID and “super” is the suggested new name of this sample. :param request: the current HTTP Request object :param deposition_number: the number of the deposition after which samples should be split and/or renamed :type request: HttpRequest :type deposition_number: unicode :return: the HTTP response object :rtype: HttpResponse """ deposition = get_object_or_404(models.Deposition, number=deposition_number).actual_instance permissions.assert_can_edit_physical_process(request.user, deposition) if not deposition.finished: raise Http404("This deposition is not finished yet.") if deposition.split_done: raise Http404("You can use the split and rename function only once after a deposition.") remote_client = is_json_requested(request) if request.POST: original_data_forms, new_name_form_lists, global_new_data_form = \ forms_from_post_data(request.user, request.POST, deposition, remote_client) all_valid = is_all_valid(original_data_forms, new_name_form_lists, global_new_data_form) structure_changed = change_structure(request.user, original_data_forms, new_name_form_lists) referentially_valid = is_referentially_valid(original_data_forms, new_name_form_lists, deposition) if all_valid and referentially_valid and not structure_changed: sample_splits = save_to_database(original_data_forms, new_name_form_lists, global_new_data_form, deposition) for sample_split in sample_splits: utils.Reporter(request.user).report_sample_split(sample_split, sample_completely_split=True) return utils.successful_response(request, _("Samples were successfully split and/or renamed."), json_response=True) else: new_names = dict((int_or_zero(key[len("new-name-"):]), new_name) for key, new_name in request.GET.items() if key.startswith("new-name-")) new_names.pop(0, None) original_data_forms, new_name_form_lists, global_new_data_form = \ forms_from_database(request.user, deposition, remote_client, new_names) return render(request, "samples/split_after_deposition.html", {"title": _("Bulk sample rename for {deposition}").format(deposition=deposition), "samples": list(zip(original_data_forms, new_name_form_lists)), "new_sample_data": global_new_data_form})
def edit(request, name): """View for editing an existing sample series. Only the currently responsible person can edit a sample series. :param request: the current HTTP Request object :param name: name of the sample series :type request: HttpRequest :type name: unicode :return: the HTTP response object :rtype: HttpResponse """ sample_series = get_object_or_404(models.SampleSeries, name=name) permissions.assert_can_edit_sample_series(request.user, sample_series) if request.method == "POST": sample_series_form = SampleSeriesForm(request.user, request.POST, instance=sample_series) edit_description_form = utils.EditDescriptionForm(request.POST) all_valid = sample_series_form.is_valid() all_valid = edit_description_form.is_valid() and all_valid referentially_valid = is_referentially_valid(sample_series, sample_series_form, edit_description_form) if all_valid and referentially_valid: edit_description = edit_description_form.cleaned_data feed_reporter = utils.Reporter(request.user) if sample_series.currently_responsible_person != sample_series_form.cleaned_data["currently_responsible_person"]: feed_reporter.report_new_responsible_person_sample_series(sample_series, edit_description) if sample_series.topic != sample_series_form.cleaned_data["topic"]: feed_reporter.report_changed_sample_series_topic(sample_series, sample_series.topic, edit_description) feed_reporter.report_edited_sample_series(sample_series, edit_description) sample_series = sample_series_form.save() feed_reporter.report_edited_sample_series(sample_series, edit_description) return utils.successful_response( request, _("Sample series {name} was successfully updated in the database.").format(name=sample_series.name)) else: sample_series_form = \ SampleSeriesForm(request.user, instance=sample_series, initial={"short_name": sample_series.name.split("-", 2)[-1], "currently_responsible_person": sample_series.currently_responsible_person.pk, "topic": sample_series.topic.pk, "samples": [sample.pk for sample in sample_series.samples.all()]}) edit_description_form = utils.EditDescriptionForm() return render(request, "samples/edit_sample_series.html", {"title": _("Edit sample series “{name}”").format(name=sample_series.name), "sample_series": sample_series_form, "is_new": False, "edit_description": edit_description_form})
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")
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 })
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 })
def save_to_database(user, my_samples_form, action_form): """Execute the things that should be done with the selected “My Samples”. I do also the feed generation here. :param user: the user whose “My Samples” should be edited :param my_samples_form: the form with the selected “My Samples” :param action_form: the form with the things to be done with the selected samples. :type user: django.contrib.auth.models.User :type my_samples_form: `MySamplesForm` :type action_form: `ActionForm` """ action_data = action_form.cleaned_data if action_data["remove_from_my_samples"]: current_user_my_samples = user.my_samples samples = my_samples_form.cleaned_data["samples"] samples_with_new_responsible_person = [] samples_with_new_topic = {} for sample in samples: old_topic, old_responsible_person = sample.topic, sample.currently_responsible_person if action_data["new_currently_responsible_person"] and \ action_data["new_currently_responsible_person"] != sample.currently_responsible_person: sample.currently_responsible_person = action_data[ "new_currently_responsible_person"] samples_with_new_responsible_person.append(sample) if action_data[ "new_topic"] and action_data["new_topic"] != sample.topic: if sample.topic not in samples_with_new_topic: samples_with_new_topic[sample.topic] = [sample] else: samples_with_new_topic[sample.topic].append(sample) sample.topic = action_data["new_topic"] if action_data["new_current_location"]: sample.current_location = action_data["new_current_location"] if action_data["new_tags"]: sample.tags = "{old},{new}".format( old=sample.tags, new=action_data["new_tags"]).strip(",") sample.save() 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) if sample.currently_responsible_person != old_responsible_person: sample.currently_responsible_person.my_samples.add(sample) if action_data["copy_to_user"]: for copy_user in action_data["copy_to_user"]: copy_user.my_samples.add(sample) if action_data["clearance"] is not None: utils.enforce_clearance(user, action_data["clearance"], copy_user, sample) if action_data["remove_from_my_samples"]: current_user_my_samples.remove(sample) feed_reporter = utils.Reporter(user) edit_description = { "important": True, "description": action_data["comment"] } if samples_with_new_responsible_person: feed_reporter.report_new_responsible_person_samples( samples_with_new_responsible_person, edit_description) for old_topic, samples in samples_with_new_topic.items(): feed_reporter.report_changed_sample_topic(samples, old_topic, edit_description) if action_data["new_currently_responsible_person"] or action_data["new_current_location"] or action_data["new_topic"]\ or action_data["new_tags"]: feed_reporter.report_edited_samples(samples, edit_description) # Now a separate(!) message for copied samples if action_data["copy_to_user"]: for copy_user in action_data["copy_to_user"]: utils.Reporter(user).report_copied_my_samples( samples, copy_user, action_data["comment"])
def add(request): """View for adding new samples. :param request: the current HTTP Request object :type request: HttpRequest :return: the HTTP response object :rtype: HttpResponse """ user = request.user if request.method == "POST": add_samples_form = AddSamplesForm(user, request.POST) if add_samples_form.is_valid(): # FixMe: Find more reliable way to find stared sample names max_cycles = 10 while max_cycles > 0: max_cycles -= 1 try: savepoint_without_samples = transaction.savepoint() new_names, samples = add_samples_to_database( add_samples_form, user) except IntegrityError: if max_cycles > 0: transaction.savepoint_rollback( savepoint_without_samples) else: raise else: break ids = [sample.pk for sample in samples] utils.Reporter(user).report_new_samples(samples) if add_samples_form.cleaned_data["topic"]: for watcher in (user_details.user for user_details in add_samples_form. cleaned_data["topic"].auto_adders.all()): for sample in samples: watcher.my_samples.add(sample) if len(new_names) > 1: success_report = \ _("Your samples have the names from {first_name} to {last_name}. " "They were added to “My Samples”.").format(first_name=new_names[0], last_name=new_names[-1]) else: success_report = _("Your sample has the name {name}. It was added to “My Samples”."). \ format(name=new_names[0]) if add_samples_form.cleaned_data["rename"] == "new-style": return utils.successful_response( request, success_report, "samples:bulk_rename", query_string="ids=" + ",".join(str(id_) for id_ in ids), forced=True, json_response=ids) else: return utils.successful_response(request, success_report, json_response=ids) else: add_samples_form = AddSamplesForm(user) return render( request, "samples/add_samples.html", { "title": _("Add samples"), "add_samples": add_samples_form, "external_operators_available": user.external_contacts.exists() })