def test_defaults(settings): """todo's `defaults` module provides reasonable default values for unspecified settings. If a value is NOT set, it should be pulled from the hash in defaults.py. If a value IS set, it should be respected. n.b. TODO_STAFF_ONLY which defaults to True in the `defaults` module. модуль "defaults" todos предоставляет разумные значения по умолчанию для неуказанных настроек. Если значение НЕ задано, его следует извлечь из хэша в defaults.py . Если значение установлено, его следует принять. n.b. TODO_STAFF_ONLY, значение по умолчанию которого равно True в модуле "defaults". """ key = "TODO_STAFF_ONLY" # Setting is not set, and should default to True (the value in defaults.py) assert not hasattr(settings, key) assert defaults(key) # Setting is already set to True and should be respected. settings.TODO_STAFF_ONLY = True assert defaults(key) # Setting is already set to False and should be respected. settings.TODO_STAFF_ONLY = False assert not defaults(key)
def add_attachment_file(request, file_data, task): if file_data.size > defaults("TODO_MAXIMUM_ATTACHMENT_SIZE"): raise Exception(_("File exceeds maximum attachment size.")) name, extension = os.path.splitext(file_data.name) if extension not in defaults("TODO_LIMIT_FILE_ATTACHMENTS"): raise Exception(_("This site does not allow upload of '{}' files.").format(extension)) user = request.user # !! if 'django_sso_app' in settings.INSTALLED_APPS: user_id = user.sso_id else: user_id = user.username created_attachment = Attachment.objects.create( task=task, added_by=user, created_at=timezone.now(), file=file_data ) created_attachment_task = created_attachment.task created_attachment_task_list = created_attachment_task.task_list # creating filer folders users_folder, _created = FilerFolder.objects.get_or_create(name='users') user_folder, _created = FilerFolder.objects.get_or_create(name=user_id, parent=users_folder, owner=user) user_tasks_folder, _created = FilerFolder.objects.get_or_create(name='tasks', parent=user_folder) user_tasklist_folder, _created = FilerFolder.objects.get_or_create(name=created_attachment_task_list.slug, parent=user_tasks_folder) user_tasklist_task_folder, _created = FilerFolder.objects.get_or_create(name=str(created_attachment_task.id), parent=user_tasklist_folder) # creating filer file filer_file = FilerFile() filer_file.file = created_attachment.file filer_file.owner = user filer_file.original_filename = os.path.basename(created_attachment.file.name) filer_file.folder = user_tasklist_task_folder filer_file.save() # update attachment created_attachment.filer_file = filer_file created_attachment.save()
def test_defaults(settings): """todo's `defaults` module provides reasonable default values for unspecified settings. If a value is NOT set, it should be pulled from the hash in defaults.py. If a value IS set, it should be respected. n.b. TODO_STAFF_ONLY which defaults to True in the `defaults` module.""" key = "TODO_STAFF_ONLY" # Setting is not set, and should default to True (the value in defaults.py) assert not hasattr(settings, key) assert defaults(key) # Setting is already set to True and should be respected. settings.TODO_STAFF_ONLY = True assert defaults(key) # Setting is already set to False and should be respected. settings.TODO_STAFF_ONLY = False assert not defaults(key)
def staff_check(user): """If TODO_STAFF_ONLY is set to True, limit view access to staff users only. # FIXME: More granular access control needed - see https://github.com/shacker/django-todo/issues/50 """ if defaults("TODO_STAFF_ONLY"): return user.is_staff else: # If unset or False, allow all logged in users return True
def book_edit(request, book_id: int) -> HttpResponse: published_book = get_object_or_404(PublishedBook, pk=book_id) if request.POST: form = PublishedBookForm(request.POST) if form.is_valid(): # Handle uploaded files if request.FILES.get("attachment_file_input"): file = request.FILES.get("attachment_file_input") if file.size > defaults("TODO_MAXIMUM_ATTACHMENT_SIZE"): messages.error( request, f"El archivo excede el tamaño máximo permitido.") return redirect(request.path) published_book.final_version = file if request.FILES.get("attachment_image_input"): published_book.related_image = request.FILES.get( "attachment_image_input") published_book.title = request.POST.get("title") published_book.book.description = request.POST.get("description") published_book.author_text = request.POST.get("author") published_book.book.completed = True published_book.book.save() published_book.save() if can_covert_to_epub(): published_book.final_version_epub = convert_to_epub( published_book.final_version.path) published_book.save() messages.success( request, "¡Perfecto! Los parámetros se han modificado correctamente.") else: print(form.errors) messages.error(request, "Lo sentimos, el libro no ha podido editarse.") return redirect(request.path) return redirect("todo:book_detail", book_id=published_book.book.id) context = {'book': published_book, 'edit_book_form': PublishedBookForm()} return render(request, "todo/book_edit.html", context)
def staff_check(user): """If TODO_STAFF_ONLY is set to True, limit view access to staff users only. # FIXME: More granular access control needed - see https://github.com/shacker/django-todo/issues/50 Если для параметра DO_STUFF_ONLY установлено значение True, ограничьте доступ к просмотру только для сотрудников. FIXME: Требуется более детальный контроль доступа """ if defaults("TODO_STAFF_ONLY"): return user.is_staff else: # If unset or False, allow all logged in users # Если значение не задано или равно False, разрешить всем зарегистрированным пользователям return True
def external_add(request) -> HttpResponse: """Allow authenticated users who don't have access to the rest of the ticket system to file a ticket in the list specified in settings (e.g. django-todo can be used a ticket filing system for a school, where students can file tickets without access to the rest of the todo system). Publicly filed tickets are unassigned unless settings.DEFAULT_ASSIGNEE exists. """ if not settings.TODO_DEFAULT_LIST_SLUG: # We do NOT provide a default in defaults raise RuntimeError( "This feature requires TODO_DEFAULT_LIST_SLUG: in settings. See documentation." ) if not TaskList.objects.filter( slug=settings.TODO_DEFAULT_LIST_SLUG).exists(): raise RuntimeError( "There is no TaskList with slug specified for TODO_DEFAULT_LIST_SLUG in settings." ) if request.POST: form = AddExternalTaskForm(request.POST) if form.is_valid(): current_site = Site.objects.get_current() task = form.save(commit=False) task.task_list = TaskList.objects.get( slug=settings.TODO_DEFAULT_LIST_SLUG) task.created_by = request.user if defaults("TODO_DEFAULT_ASSIGNEE"): task.assigned_to = get_user_model().objects.get( username=settings.TODO_DEFAULT_ASSIGNEE) task.save() # Send email to assignee if we have one if task.assigned_to: email_subject = render_to_string( "todo/email/assigned_subject.txt", {"task": task.title}) email_body = render_to_string("todo/email/assigned_body.txt", { "task": task, "site": current_site }) try: send_mail( email_subject, email_body, task.created_by.email, [task.assigned_to.email], fail_silently=False, ) except ConnectionRefusedError: messages.warning( request, _("Task saved but mail not sent. Contact your administrator." )) messages.success( request, _("Your trouble ticket has been submitted. We'll get back to you soon." )) return redirect(defaults("TODO_PUBLIC_SUBMIT_REDIRECT")) else: form = AddExternalTaskForm(initial={"priority": 999}) context = {"form": form} return render(request, "todo/add_task_external.html", context)
def external_add(request) -> HttpResponse: """Allow authenticated users who don't have access to the rest of the ticket system to file a ticket in the list specified in settings (e.g. django-todo can be used a ticket filing system for a school, where students can file tickets without access to the rest of the todo system). Publicly filed tickets are unassigned unless settings.DEFAULT_ASSIGNEE exists. Разрешить аутентифицированным пользователям, у которых нет доступа к остальной части системы регистрации, подавать заявки в список, указанный в настройках (например, django-todo может использоваться в системе регистрации заявок для школы, где учащиеся могут подавать заявки без доступа к остальной части системы регистрации заявок). Общедоступные заявки не назначаются, если только не прописана settings.DEFAULT_ASSIGNEE. """ if not settings.TODO_DEFAULT_LIST_SLUG: # We do NOT provide a default in defaults # Мы не предоставляем дефолт по умолчанию raise RuntimeError( "This feature requires TODO_DEFAULT_LIST_SLUG: in settings. See documentation." ) if not TaskList.objects.filter(slug=settings.TODO_DEFAULT_LIST_SLUG).exists(): raise RuntimeError( "There is no TaskList with slug specified for TODO_DEFAULT_LIST_SLUG in settings." ) if request.POST: form = AddExternalTaskForm(request.POST) if form.is_valid(): current_site = Site.objects.get_current() task = form.save(commit=False) task.task_list = TaskList.objects.get(slug=settings.TODO_DEFAULT_LIST_SLUG) task.created_by = request.user if defaults("TODO_DEFAULT_ASSIGNEE"): task.assigned_to = get_user_model().objects.get(username=settings.TODO_DEFAULT_ASSIGNEE) task.save() # Send email to assignee if we have one # Отправьте электронное письмо правопреемнику, если он у нас есть if task.assigned_to: email_subject = render_to_string( "todo/email/assigned_subject.txt", {"task": task.title} ) email_body = render_to_string( "todo/email/assigned_body.txt", {"task": task, "site": current_site} ) try: send_mail( email_subject, email_body, task.created_by.email, [task.assigned_to.email], fail_silently=False, ) except ConnectionRefusedError: messages.warning( request, "Task saved but mail not sent. Contact your administrator." ) messages.success( request, "Your trouble ticket has been submitted. We'll get back to you soon." ) return redirect(defaults("TODO_PUBLIC_SUBMIT_REDIRECT")) else: form = AddExternalTaskForm(initial={"priority": 999}) context = {"form": form} return render(request, "todo/add_task_external.html", context)
def book_publish(request, book_id: int) -> HttpResponse: book = get_object_or_404(Book, pk=book_id) user_email = request.user editor = Editor.objects.filter(user=user_email).first() if editor == None: raise PermissionDenied if (book.editor != editor) and (not editor.chief): raise PermissionDenied if book.completed: raise PermissionDenied if request.POST: form = PublishedBookForm(request.POST) if form.is_valid(): published_book = form.save(commit=False) published_book.book = book # Handle uploaded files if request.FILES.get("attachment_file_input"): file = request.FILES.get("attachment_file_input") if file.size > defaults("TODO_MAXIMUM_ATTACHMENT_SIZE"): messages.error(request, f"El archivo excede el tamaño máximo permitido.") return redirect(request.path) published_book.final_version = file else: messages.error(request, f"Debes adjuntar la versión maquetada final en pdf, sino no podremos proceder a su publicación.") return redirect(request.path) if request.FILES.get("attachment_image_input"): published_book.related_image = request.FILES.get("attachment_image_input") published_book.title = request.POST.get("title") published_book.book.description = request.POST.get("description") published_book.author_text = request.POST.get("author") published_book.book.completed = True published_book.book.save() published_book.save() try_add_epub_version(published_book) messages.success(request, "¡Enhorabuena! El libro ha sido publicado correctamente.") ######### Send email to author email_body = render_to_string( "todo/email/published_book.txt", {"book": book} ) send_mail( "Libro publicado", email_body, None, [book.author.user.email], fail_silently=False, ) else: print(form.errors) messages.error(request, "Lo sentimos, el libro no ha podido publicarse.") return redirect(request.path) return redirect("todo:book_detail", book_id=book.id) context = { 'book': book, 'publish_form': PublishedBookForm() } return render(request, "todo/book_publish.html", context)
def external_add(request) -> HttpResponse: if request.POST: form = AddExternalBookForm(request.POST) form_book = AddBookForm(request.POST) if form.is_valid() and form_book.is_valid(): current_site = Site.objects.get_current() User = get_user_model() email = request.POST['email'] user = User.objects.filter(email=email).first() if not user: password = User.objects.make_random_password() user = User.objects.create_user(email, password) user_info = UserInfo.objects.filter(user=user).first() if not user_info: user_info = form.save(commit=False) user_info.user = user user_info.save() writer, created_writer = Writer.objects.update_or_create(user=user) book = form_book.save(commit=False) # Handle uploaded files if request.FILES.get("attachment_file_input"): file = request.FILES.get("attachment_file_input") if file.size > defaults("TODO_MAXIMUM_ATTACHMENT_SIZE"): messages.error(request, f"El archivo excede el tamaño máximo permitido") return redirect("todo:external_add") name, extension = os.path.splitext(file.name) if extension not in defaults("TODO_LIMIT_FILE_ATTACHMENTS"): messages.error(request, f"Este sitio no eccepta atchivos de extensión {extension}") return redirect("todo:external_add") book.file = file else: messages.error(request, f"Debes adjuntar un libro.") return redirect("todo:external_add") book.author = writer book.save() messages.success( request, "Su libro se ha enviado. Nos pondremos en contacto con usted pronto." ) send_emails(book, user_info, created_writer, email) return redirect(defaults("TODO_PUBLIC_SUBMIT_REDIRECT")) else: form = AddExternalBookForm(initial={"priority": 999}) form_book = AddBookForm() context = {"form": form, "form_book": form_book} return render(request, "todo/add_task_external.html", context)
def task_detail(request, task_id: int) -> HttpResponse: """View task details. Allow task details to be edited. Process new comments on task. """ task = get_object_or_404(Task, pk=task_id) comment_list = Comment.objects.filter(task=task_id).order_by("-date") # Ensure user has permission to view task. Superusers can view all tasks. # Get the group this task belongs to, and check whether current user is a member of that group. if not user_can_read_task(task, request.user): raise PermissionDenied # Handle task merging if not HAS_TASK_MERGE: merge_form = None else: class MergeForm(forms.Form): merge_target = forms.ModelChoiceField( queryset=Task.objects.all(), widget=autocomplete.ModelSelect2( url=reverse("todo:task_autocomplete", kwargs={"task_id": task_id}) ), ) # Handle task merging if not request.POST.get("merge_task_into"): merge_form = MergeForm() else: merge_form = MergeForm(request.POST) if merge_form.is_valid(): merge_target = merge_form.cleaned_data["merge_target"] if not user_can_read_task(merge_target, request.user): raise PermissionDenied task.merge_into(merge_target) return redirect(reverse("todo:task_detail", kwargs={"task_id": merge_target.pk})) # Save submitted comments handle_add_comment(request, task) # Save task edits if not request.POST.get("add_edit_task"): form = AddEditTaskForm(request.user, instance=task, initial={"task_list": task.task_list}) else: form = AddEditTaskForm( request.user, request.POST, instance=task, initial={"task_list": task.task_list} ) if form.is_valid(): item = form.save(commit=False) item.note = bleach.clean(form.cleaned_data["note"], strip=True) item.save() messages.success(request, "The task has been edited.") return redirect( "todo:list_detail", list_id=task.task_list.id, list_slug=task.task_list.slug ) # Mark complete if request.POST.get("toggle_done"): results_changed = toggle_task_completed(task.id) if results_changed: messages.success(request, f"Changed completion status for task {task.id}") return redirect("todo:task_detail", task_id=task.id) if task.due_date: thedate = task.due_date else: thedate = datetime.datetime.now() # Handle uploaded files if request.FILES.get("attachment_file_input"): file = request.FILES.get("attachment_file_input") if file.size > defaults("TODO_MAXIMUM_ATTACHMENT_SIZE"): messages.error(request, f"File exceeds maximum attachment size.") return redirect("todo:task_detail", task_id=task.id) name, extension = os.path.splitext(file.name) if extension not in defaults("TODO_LIMIT_FILE_ATTACHMENTS"): messages.error(request, f"This site does not allow upload of {extension} files.") return redirect("todo:task_detail", task_id=task.id) Attachment.objects.create( task=task, added_by=request.user, timestamp=datetime.datetime.now(), file=file ) messages.success(request, f"File attached successfully") return redirect("todo:task_detail", task_id=task.id) context = { "task": task, "comment_list": comment_list, "form": form, "merge_form": merge_form, "thedate": thedate, "comment_classes": defaults("TODO_COMMENT_CLASSES"), "attachments_enabled": defaults("TODO_ALLOW_FILE_ATTACHMENTS"), } return render(request, "todo/task_detail.html", context)
def task_detail(request, task_id: int) -> HttpResponse: """View task details. Allow task details to be edited. Process new comments on task. """ task = get_object_or_404(Task, pk=task_id) # comment_list = Comment.objects.filter(task=task_id).order_by("-date") # pai # Ensure user has permission to view task. Superusers can view all tasks. # Get the group this task belongs to, and check whether current user is a member of that group. if not user_can_read_task(task, request.user): # raise PermissionDenied # pai raise Http404 comment_list = Comment.objects.filter(task=task_id).order_by("-created_at") # pai # Handle task merging if not HAS_TASK_MERGE: merge_form = None else: class MergeForm(forms.Form): merge_target = forms.ModelChoiceField( queryset=Task.objects.filter(is_active=True), widget=autocomplete.ModelSelect2( url=reverse("todo:task_autocomplete", kwargs={"task_id": task_id}) ), ) # Handle task merging if not request.POST.get("merge_task_into"): merge_form = MergeForm() else: merge_form = MergeForm(request.POST) if merge_form.is_valid(): merge_target = merge_form.cleaned_data["merge_target"] if not user_can_read_task(merge_target, request.user): raise PermissionDenied task.merge_into(merge_target) return redirect(reverse("todo:task_detail", kwargs={"task_id": merge_target.pk})) # Save submitted comments handle_add_comment(request, task) # Save task edits # staff can edit task, non staff can only if creator if (task.procedure_uuid is None and staff_check(request.user) or (task.procedure_uuid is None and task.created_by == request.user)) \ and request.POST.getlist("add_edit_task"): # pai form = AddEditTaskForm( request.user, request.POST, instance=task, initial={"task_list": task.task_list} ) if form.is_valid(): item = form.save(commit=False) item.note = bleach.clean(form.cleaned_data["note"], strip=True) item.title = bleach.clean(form.cleaned_data["title"], strip=True) item.save() messages.success(request, _("The task has been edited.")) return redirect( "todo:list_detail", list_id=task.task_list.id, list_slug=task.task_list.slug ) else: form = AddEditTaskForm(request.user, instance=task, initial={"task_list": task.task_list}) """ # pai (why duplicate toggle_done view?) # Mark complete if request.POST.get("toggle_done"): results_changed = toggle_task_completed(task.id, user=request.user) if results_changed: messages.success(request, _("Task completion status changed for ") + '"' + task.title + '".') else: messages.error(request, _("Can not change completion status for ") + '"' + task.title + '".') return redirect("todo:task_detail", task_id=task.id) """ if task.due_date: thedate = task.due_date else: thedate = timezone.now() # Handle uploaded files # pai # Attachment.objects.create( # task=task, added_by=request.user, timestamp=datetime.datetime.now(), file=file # ) attachment_file = request.FILES.get("attachment_file_input", None) if attachment_file is not None: try: add_attachment_file(request, attachment_file, task) # pai except Exception as e: messages.error(request, str(e)) return redirect("todo:task_detail", task_id=task.id) messages.success(request, f"File attached successfully") return redirect("todo:task_detail", task_id=task.id) context = { "task": task, "comment_list": comment_list, "form": form, "merge_form": merge_form, "thedate": thedate, "comment_classes": defaults("TODO_COMMENT_CLASSES"), "attachments_enabled": defaults("TODO_ALLOW_FILE_ATTACHMENTS"), } return render(request, "todo/task_detail.html", context)
def external_add(request) -> HttpResponse: """Allow authenticated users who don't have access to the rest of the ticket system to file a ticket in the list specified in settings (e.g. django-todo can be used a ticket filing system for a school, where students can file tickets without access to the rest of the todo system). Publicly filed tickets are unassigned unless settings.DEFAULT_ASSIGNEE exists. """ if not settings.TODO_DEFAULT_LIST_SLUG: # We do NOT provide a default in defaults raise RuntimeError( "This feature requires TODO_DEFAULT_LIST_SLUG: in settings. See documentation." ) if not TaskList.objects.filter(slug=settings.TODO_DEFAULT_LIST_SLUG).exists(): raise RuntimeError( "There is no TaskList with slug specified for TODO_DEFAULT_LIST_SLUG in settings." ) if request.POST: form = AddExternalTaskForm(request.POST) if form.is_valid(): current_site = Site.objects.get_current() task = form.save(commit=False) task.task_list = TaskList.objects.get(slug=settings.TODO_DEFAULT_LIST_SLUG) task.created_by = request.user if defaults("TODO_DEFAULT_ASSIGNEE"): task.assigned_to = get_user_model().objects.get(username=settings.TODO_DEFAULT_ASSIGNEE) task.save() # Send email to assignee if we have one if task.assigned_to: email_subject = render_to_string( "todo/email/assigned_subject.txt", {"task": task.title} ) email_body = render_to_string( "todo/email/assigned_body.txt", {"task": task, "site": current_site} ) try: send_mail( email_subject, email_body, task.created_by.email, [task.assigned_to.email], fail_silently=False, ) except ConnectionRefusedError: messages.warning( request, "Task saved but mail not sent. Contact your administrator." ) messages.success( request, "Your trouble ticket has been submitted. We'll get back to you soon." ) return redirect(defaults("TODO_PUBLIC_SUBMIT_REDIRECT")) else: form = AddExternalTaskForm(initial={"priority": 999}) context = {"form": form} return render(request, "todo/add_task_external.html", context)
def task_detail(request, task_id: int) -> HttpResponse: """View task details. Allow task details to be edited. Process new comments on task. Просмотр сведений о задаче. Разрешить редактирование сведений о задаче. Обработайте новые комментарии к задаче. """ task = get_object_or_404(Task, pk=task_id) comment_list = Comment.objects.filter(task=task_id).order_by("-date") # Ensure user has permission to view task. Superusers can view all tasks. # Убедитесь, что у пользователя есть разрешение на просмотр задачи. Суперпользователи могут просматривать все задачи. # Get the group this task belongs to, and check whether current user is a member of that group. # Получите группу, к которой принадлежит эта задача, и проверьте, является ли текущий пользователь членом этой группы. if not user_can_read_task(task, request.user): raise PermissionDenied # Handle task merging # Обрабатывать слияние задач (скрыто) if not HAS_TASK_MERGE: merge_form = None else: class MergeForm(forms.Form): merge_target = forms.ModelChoiceField( queryset=Task.objects.all(), widget=autocomplete.ModelSelect2( url=reverse("todo:task_autocomplete", kwargs={"task_id": task_id}) ), ) # Handle task merging # Обрабатывать слияние задач (скрыто) if not request.POST.get("merge_task_into"): merge_form = MergeForm() else: merge_form = MergeForm(request.POST) if merge_form.is_valid(): merge_target = merge_form.cleaned_data["merge_target"] if not user_can_read_task(merge_target, request.user): raise PermissionDenied task.merge_into(merge_target) return redirect(reverse("todo:task_detail", kwargs={"task_id": merge_target.pk})) # Save submitted comments # Сохранить отправленные комментарии handle_add_comment(request, task) # Save task edits # Сохранение изменений задачи if not request.POST.get("add_edit_task"): form = AddEditTaskForm(request.user, instance=task, initial={"task_list": task.task_list}) else: form = AddEditTaskForm( request.user, request.POST, instance=task, initial={"task_list": task.task_list} ) if form.is_valid(): item = form.save(commit=False) item.note = bleach.clean(form.cleaned_data["note"], strip=True) item.title = bleach.clean(form.cleaned_data["title"], strip=True) item.save() messages.success(request, "The task has been edited.") return redirect( "todo:list_detail", list_id=task.task_list.id, list_slug=task.task_list.slug ) # Mark complete # Отметить завершение if request.POST.get("toggle_done"): results_changed = toggle_task_completed(task.id) if results_changed: messages.success(request, f"Changed completion status for task {task.id}") return redirect("todo:task_detail", task_id=task.id) if task.due_date: thedate = task.due_date else: thedate = datetime.datetime.now() # Handle uploaded files # Обрабатывать загруженные файлы if request.FILES.get("attachment_file_input"): file = request.FILES.get("attachment_file_input") if file.size > defaults("TODO_MAXIMUM_ATTACHMENT_SIZE"): messages.error(request, f"File exceeds maximum attachment size.") return redirect("todo:task_detail", task_id=task.id) name, extension = os.path.splitext(file.name) if extension not in defaults("TODO_LIMIT_FILE_ATTACHMENTS"): messages.error(request, f"This site does not allow upload of {extension} files.") return redirect("todo:task_detail", task_id=task.id) Attachment.objects.create( task=task, added_by=request.user, timestamp=datetime.datetime.now(), file=file ) messages.success(request, f"File attached successfully") return redirect("todo:task_detail", task_id=task.id) context = { "task": task, "comment_list": comment_list, "form": form, "merge_form": merge_form, "thedate": thedate, "comment_classes": defaults("TODO_COMMENT_CLASSES"), "attachments_enabled": defaults("TODO_ALLOW_FILE_ATTACHMENTS"), } return render(request, "todo/task_detail.html", context)