Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion task_manager/labels/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ class Meta:
"name": forms.TextInput(attrs={"class": "form-control"}),
}
labels = {
"name": "Имя",
"name": "Name",
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='label',
name='created_at',
field=models.DateTimeField(auto_now_add=True, verbose_name='Дата создания'),
field=models.DateTimeField(auto_now_add=True, verbose_name='Created at'),
),
migrations.AlterField(
model_name='label',
name='name',
field=models.CharField(max_length=100, unique=True, verbose_name='Имя'),
field=models.CharField(max_length=100, unique=True, verbose_name='Name'),
),
]
11 changes: 5 additions & 6 deletions task_manager/labels/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class LabelCreateView(LoginRequiredMixin, CreateView):
login_url = "login"

def form_valid(self, form):
messages.success(self.request, "Метка успешно создана")
messages.success(self.request, "Label created successfully")
return super().form_valid(form)


Expand All @@ -35,7 +35,7 @@ class LabelUpdateView(LoginRequiredMixin, UpdateView):
login_url = "login"

def form_valid(self, form):
messages.success(self.request, "Метка успешно изменена")
messages.success(self.request, "Label updated successfully")
return super().form_valid(form)


Expand All @@ -48,11 +48,10 @@ class LabelDeleteView(LoginRequiredMixin, DeleteView):
def post(self, request, *args, **kwargs):
label = self.get_object()
if label.labeled_tasks.exists():
messages.error(request,
"Невозможно удалить метку, "
"потому что она используется")
messages.error(request,
"Cannot delete label because it is in use")
return redirect("labels:index")

response = super().post(request, *args, **kwargs)
messages.success(request, "Метка успешно удалена")
messages.success(request, "Label deleted successfully")
return response
2 changes: 1 addition & 1 deletion task_manager/statuses/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class StatusForm(forms.ModelForm):
class Meta:
model = Status
fields = ["name"]
labels = {"name": "Имя"}
labels = {"name": "Name"}
widgets = {
"name": forms.TextInput(attrs={"class": "form-control"}),
}
26 changes: 13 additions & 13 deletions task_manager/statuses/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,36 +35,36 @@ def test_login_required(client):

@pytest.mark.django_db
def test_list(auth_client):
Status.objects.create(name="новый")
Status.objects.create(name="в работе")
Status.objects.create(name="new")
Status.objects.create(name="in progress")
resp = auth_client.get(reverse("statuses:index"))
assert resp.status_code == 200
html = resp.content.decode()
assert "новый" in html
assert "в работе" in html
assert "new" in html
assert "in progress" in html


@pytest.mark.django_db
def test_create(auth_client):
resp = auth_client.post(reverse("statuses:create"),
data={"name": "на тестировании"})
data={"name": "testing"})
assert resp.status_code in (302, 301)
assert Status.objects.filter(name="на тестировании").exists()
assert Status.objects.filter(name="testing").exists()


@pytest.mark.django_db
def test_update(auth_client):
st = Status.objects.create(name="черновик")
st = Status.objects.create(name="draft")
resp = auth_client.post(reverse("statuses:update", args=[st.pk]),
data={"name": "завершён"})
data={"name": "done"})
assert resp.status_code in (302, 301)
st.refresh_from_db()
assert st.name == "завершён"
assert st.name == "done"


@pytest.mark.django_db
def test_delete(auth_client):
st = Status.objects.create(name="временный")
st = Status.objects.create(name="temporary")
get_resp = auth_client.get(reverse("statuses:delete", args=[st.pk]))
assert get_resp.status_code == 200
post_resp = auth_client.post(reverse("statuses:delete", args=[st.pk]))
Expand All @@ -76,10 +76,10 @@ def test_delete(auth_client):
def test_cannot_delete_status_in_use(django_user_model):
user = (django_user_model.objects.
create_user(username="alice", password="p123"))
status = Status.objects.create(name="новый")
status = Status.objects.create(name="new")
Task.objects.create(
name="Тестовая задача",
description="Проверка связи",
name="Test task",
description="Connection check",
status=status,
author=user,
)
Expand Down
8 changes: 4 additions & 4 deletions task_manager/statuses/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class StatusCreateView(LoginRequiredMixin, CreateView):
login_url = "login"

def form_valid(self, form):
messages.success(self.request, "Статус успешно создан")
messages.success(self.request, "Status created successfully")
return super().form_valid(form)


Expand All @@ -35,7 +35,7 @@ class StatusUpdateView(LoginRequiredMixin, UpdateView):
login_url = "login"

def form_valid(self, form):
messages.success(self.request, "Статус успешно изменен")
messages.success(self.request, "Status updated successfully")
return super().form_valid(form)


Expand All @@ -50,9 +50,9 @@ def post(self, request, *args, **kwargs):
if status.tasks.exists():
messages.error(
request,
"Невозможно удалить статус, потому что он используется",
"Cannot delete status because it is in use",
)
return redirect("statuses:index")
response = super().post(request, *args, **kwargs)
messages.success(request, "Статус успешно удален")
messages.success(request, "Status deleted successfully")
return response
8 changes: 4 additions & 4 deletions task_manager/tasks/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@
class TaskFilter(df.FilterSet):
status = df.ModelChoiceFilter(
queryset=Status.objects.all().order_by("id"),
label="Статус",
label="Status",
widget=forms.Select(attrs={"class": "form-select"}),
)
executor = df.ModelChoiceFilter(
queryset=User.objects.all().order_by("id"),
label="Исполнитель",
label="Executor",
widget=forms.Select(attrs={"class": "form-select"}),
)
label = df.ModelChoiceFilter(
field_name="labels",
queryset=Label.objects.all().order_by("id"),
label="Метка",
label="Label",
widget=forms.Select(attrs={"class": "form-select"}),
)
self_tasks = df.BooleanFilter(
method="filter_self_tasks",
label="Только свои задачи",
label="Only my tasks",
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
)

Expand Down
10 changes: 5 additions & 5 deletions task_manager/tasks/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ class Meta:
"size": 5}),
}
labels = {
"name": "Имя",
"description": "Описание",
"status": "Статус",
"executor": "Исполнитель",
"labels": "Метки",
"name": "Name",
"description": "Description",
"status": "Status",
"executor": "Executor",
"labels": "Labels",
}

def __init__(self, *args, **kwargs):
Expand Down
36 changes: 18 additions & 18 deletions task_manager/tasks/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def auth_client(users):

@pytest.fixture
def status_new(db):
return Status.objects.create(name="новый")
return Status.objects.create(name="new")


def test_login_required(client):
Expand All @@ -36,58 +36,58 @@ def test_login_required(client):


def test_list(auth_client, users, status_new):
Task.objects.create(name="Тестовая задача", description="Описание",
Task.objects.create(name="Test task", description="Description",
status=status_new, author=users["u1"])
Task.objects.create(name="Вторая", description="Ещё одна",
Task.objects.create(name="Second", description="Another one",
status=status_new, author=users["u1"])
r = auth_client.get(reverse("tasks:index"))
assert r.status_code == 200
html = r.content.decode()
assert "Тестовая задача" in html
assert "Вторая" in html
assert "Test task" in html
assert "Second" in html


def test_create(auth_client, users, status_new):
resp = auth_client.post(reverse("tasks:create"), data={
"name": "Новая задача",
"description": "Что-то сделать",
"name": "New task",
"description": "Do something",
"status": status_new.pk,
"executor": users["u2"].pk,
})
assert resp.status_code in (302, 301)
assert Task.objects.filter(name="Новая задача",
assert Task.objects.filter(name="New task",
status=status_new,
author=users["u1"]).exists()


def test_update(auth_client, users, status_new):
t = Task.objects.create(name="Черновик", description="Описание",
t = Task.objects.create(name="Draft", description="Description",
status=status_new, author=users["u1"])
resp = auth_client.post(reverse("tasks:update", args=[t.pk]), data={
"name": "Изменено",
"description": "Новое описание",
"name": "Updated",
"description": "New description",
"status": status_new.pk,
"executor": users["u2"].pk,
})
assert resp.status_code in (302, 301)
t.refresh_from_db()
assert t.name == "Изменено"
assert t.description == "Новое описание"
assert t.name == "Updated"
assert t.description == "New description"
assert t.executor == users["u2"]


def test_view(auth_client, users, status_new):
t = Task.objects.create(name="Посмотреть", description="Детали",
t = Task.objects.create(name="View", description="Details",
status=status_new, author=users["u1"])
r = auth_client.get(reverse("tasks:detail", args=[t.pk]))
assert r.status_code == 200
html = r.content.decode()
assert "Посмотреть" in html
assert "Детали" in html
assert "View" in html
assert "Details" in html


def test_delete(auth_client, users, status_new):
t = Task.objects.create(name="Удалить", description="Ненужная",
t = Task.objects.create(name="Delete", description="Unneeded",
status=status_new, author=users["u1"])
r_get = auth_client.get(reverse("tasks:delete", args=[t.pk]))
assert r_get.status_code == 200
Expand All @@ -98,7 +98,7 @@ def test_delete(auth_client, users, status_new):

def test_only_author_can_delete(auth_client, users, status_new):
t = Task.objects.create(
name="Чужая задача", description="...",
name="Someone else's task", description="...",
status=status_new, author=users["u2"]
)
r = auth_client.post(reverse("tasks:delete", args=[t.pk]))
Expand Down
8 changes: 4 additions & 4 deletions task_manager/tasks/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class TaskCreateView(LoginRequiredMixin, CreateView):

def form_valid(self, form):
form.instance.author = self.request.user
messages.success(self.request, "Задача успешно создана")
messages.success(self.request, "Task created successfully")
return super().form_valid(form)


Expand All @@ -54,7 +54,7 @@ class TaskUpdateView(LoginRequiredMixin, UpdateView):
login_url = "login"

def form_valid(self, form):
messages.success(self.request, "Задача успешно изменена")
messages.success(self.request, "Task updated successfully")
return super().form_valid(form)


Expand All @@ -69,10 +69,10 @@ def test_func(self):

def handle_no_permission(self):
if self.request.user.is_authenticated:
messages.error(self.request, "Задачу может удалить только ее автор")
messages.error(self.request, "Only the author can delete the task")
return redirect("tasks:index")
return super().handle_no_permission()

def post(self, request, *args, **kwargs):
messages.success(self.request, "Задача успешно удалена")
messages.success(self.request, "Task deleted successfully")
return super().post(request, *args, **kwargs)
20 changes: 10 additions & 10 deletions task_manager/templates/base.html
Original file line number Diff line number Diff line change
@@ -1,51 +1,51 @@
{% load django_bootstrap5 %}

<!doctype html>
<html lang="ru">
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}Менеджер Задач{% endblock %}</title>
<title>{% block title %}Task Manager{% endblock %}</title>
{% bootstrap_css %}
{% bootstrap_javascript %}
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4">
<div class="container-fluid">
<a class="navbar-brand" href="/">Менеджер Задач</a>
<a class="navbar-brand" href="/">Task Manager</a>
<div>
<ul class="navbar-nav me-auto mb-2 mb-md-0 align-items-center">
{% if user.is_authenticated %}
<li class="nav-item">
<form method="post" action="{% url 'logout' %}" class="d-inline m-0">
{% csrf_token %}
<button type="submit" class="btn btn-link nav-link px-2 py-2">
Выход
Log out
</button>
</form>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'login' %}">Вход</a>
<a class="nav-link" href="{% url 'login' %}">Log in</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'users:create' %}">Регистрация</a>
<a class="nav-link" href="{% url 'users:create' %}">Sign up</a>
</li>
{% endif %}

<li class="nav-item">
<a class="nav-link" href="{% url 'users:list' %}">Пользователи</a>
<a class="nav-link" href="{% url 'users:list' %}">Users</a>
</li>

{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'statuses:index' %}">Статусы</a>
<a class="nav-link" href="{% url 'statuses:index' %}">Statuses</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'tasks:index' %}">Задачи</a>
<a class="nav-link" href="{% url 'tasks:index' %}">Tasks</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'labels:index' %}">Метки</a>
<a class="nav-link" href="{% url 'labels:index' %}">Labels</a>
</li>
{% endif %}
</ul>
Expand Down
6 changes: 3 additions & 3 deletions task_manager/templates/index.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{% extends "base.html" %}

{% block title %}Домашняя страница{% endblock %}
{% block title %}Home page{% endblock %}

{% block content %}
<h1>Добро пожаловать в Менеджер Задач!</h1>
<p>Это домашняя страница.</p>
<h1>Welcome to Task Manager!</h1>
<p>This is the home page.</p>
{% endblock %}
Loading
Loading