Skip to content

Commit 526c68d

Browse files
committed
Реализованы модели для модуля канбан-доски и тесты для них
1 parent e24506a commit 526c68d

18 files changed

Lines changed: 1164 additions & 0 deletions

kanban/__init__.py

Whitespace-only changes.

kanban/admin.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.contrib import admin
2+
3+
# Register your models here.

kanban/apps.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.apps import AppConfig
2+
3+
4+
class KanbanConfig(AppConfig):
5+
default_auto_field = "django.db.models.BigAutoField"
6+
name = "kanban"
7+
8+
def ready(self):
9+
from kanban import signals # noqa: F401

kanban/migrations/0001_initial.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Generated by Django 4.2.24 on 2025-11-20 05:13
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
initial = True
10+
11+
dependencies = [
12+
('projects', '0030_company_resource_projectcompany_project_companies_and_more'),
13+
]
14+
15+
operations = [
16+
migrations.CreateModel(
17+
name='Board',
18+
fields=[
19+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20+
('name', models.CharField(max_length=150)),
21+
('color', models.CharField(choices=[('blue', 'Blue'), ('green', 'Green'), ('orange', 'Orange'), ('purple', 'Purple'), ('red', 'Red')], default='blue', max_length=32)),
22+
('icon', models.CharField(choices=[('rocket', 'Rocket'), ('target', 'Target'), ('bulb', 'Light Bulb'), ('chart', 'Chart'), ('note', 'Note')], default='rocket', max_length=32)),
23+
('description', models.TextField(blank=True)),
24+
('created_at', models.DateTimeField(auto_now_add=True)),
25+
('updated_at', models.DateTimeField(auto_now=True)),
26+
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='kanban_boards', to='projects.project')),
27+
],
28+
options={
29+
'verbose_name': 'Kanban board',
30+
'verbose_name_plural': 'Kanban boards',
31+
'ordering': ['project_id', 'id'],
32+
},
33+
),
34+
migrations.CreateModel(
35+
name='BoardColumn',
36+
fields=[
37+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
38+
('name', models.CharField(max_length=150)),
39+
('order', models.PositiveIntegerField(default=0)),
40+
('tasks_count', models.PositiveIntegerField(default=0, editable=False, help_text='Cached value of tasks inside the column.')),
41+
('created_at', models.DateTimeField(auto_now_add=True)),
42+
('updated_at', models.DateTimeField(auto_now=True)),
43+
('board', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='columns', to='kanban.board')),
44+
],
45+
options={
46+
'verbose_name': 'Board column',
47+
'verbose_name_plural': 'Board columns',
48+
'ordering': ['order', 'id'],
49+
},
50+
),
51+
migrations.AddConstraint(
52+
model_name='boardcolumn',
53+
constraint=models.UniqueConstraint(fields=('board', 'order'), name='unique_column_order_per_board'),
54+
),
55+
migrations.AddConstraint(
56+
model_name='boardcolumn',
57+
constraint=models.UniqueConstraint(fields=('board', 'name'), name='unique_column_name_per_board'),
58+
),
59+
migrations.AlterUniqueTogether(
60+
name='board',
61+
unique_together={('project', 'name')},
62+
),
63+
]
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# Generated by Django 4.2.24 on 2025-11-20 05:57
2+
3+
from django.conf import settings
4+
import django.core.validators
5+
from django.db import migrations, models
6+
import django.db.models.deletion
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
dependencies = [
12+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13+
('core', '0015_alter_skill_options_alter_skilltoobject_options'),
14+
('files', '0007_auto_20230929_1727'),
15+
('projects', '0030_company_resource_projectcompany_project_companies_and_more'),
16+
('kanban', '0001_initial'),
17+
]
18+
19+
operations = [
20+
migrations.CreateModel(
21+
name='BoardTag',
22+
fields=[
23+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
24+
('name', models.CharField(max_length=80)),
25+
('color', models.CharField(choices=[('blue', 'Blue'), ('green', 'Green'), ('orange', 'Orange'), ('purple', 'Purple'), ('red', 'Red')], default='blue', max_length=32)),
26+
('board', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tags', to='kanban.board')),
27+
],
28+
options={
29+
'ordering': ['board_id', 'name'],
30+
'unique_together': {('board', 'name')},
31+
},
32+
),
33+
migrations.CreateModel(
34+
name='Task',
35+
fields=[
36+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
37+
('name', models.CharField(max_length=255)),
38+
('description', models.TextField(blank=True)),
39+
('task_type', models.CharField(choices=[('action', 'Action'), ('meeting', 'Meeting'), ('call', 'Call')], default='action', max_length=32)),
40+
('priority', models.PositiveSmallIntegerField(default=3, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(6)])),
41+
('is_completed', models.BooleanField(default=False)),
42+
('status', models.CharField(choices=[('todo', 'To do'), ('in_progress', 'In progress'), ('review', 'Review'), ('done', 'Done'), ('declined', 'Declined')], default='todo', max_length=32)),
43+
('points', models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(10)])),
44+
('start_date', models.DateField(blank=True, null=True)),
45+
('deadline', models.DateField(blank=True, null=True)),
46+
('created_at', models.DateTimeField(auto_now_add=True)),
47+
('updated_at', models.DateTimeField(auto_now=True)),
48+
],
49+
options={
50+
'ordering': ['column_id', 'priority', '-created_at'],
51+
},
52+
),
53+
migrations.AlterField(
54+
model_name='boardcolumn',
55+
name='tasks_count',
56+
field=models.PositiveIntegerField(default=0, editable=False, help_text='Кешированное количество задач в столбце.'),
57+
),
58+
migrations.CreateModel(
59+
name='TaskTagLink',
60+
fields=[
61+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
62+
('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tag_links', to='kanban.boardtag')),
63+
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='task_tag_links', to='kanban.task')),
64+
],
65+
options={
66+
'unique_together': {('task', 'tag')},
67+
},
68+
),
69+
migrations.CreateModel(
70+
name='TaskSkillLink',
71+
fields=[
72+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
73+
('skill', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='skill_links', to='core.skill')),
74+
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='task_skill_links', to='kanban.task')),
75+
],
76+
options={
77+
'unique_together': {('task', 'skill')},
78+
},
79+
),
80+
migrations.CreateModel(
81+
name='TaskResult',
82+
fields=[
83+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
84+
('description', models.TextField()),
85+
('is_verified', models.BooleanField(default=False)),
86+
('verified_at', models.DateTimeField(blank=True, null=True)),
87+
('created_at', models.DateTimeField(auto_now_add=True)),
88+
('updated_at', models.DateTimeField(auto_now=True)),
89+
('result_file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task_result_files', to='files.userfile')),
90+
('task', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='result', to='kanban.task')),
91+
('verified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='verified_results', to=settings.AUTH_USER_MODEL)),
92+
],
93+
options={
94+
'ordering': ['-created_at'],
95+
},
96+
),
97+
migrations.CreateModel(
98+
name='TaskAttachment',
99+
fields=[
100+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
101+
('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='task_attachments', to='files.userfile')),
102+
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='kanban.task')),
103+
],
104+
options={
105+
'unique_together': {('task', 'file')},
106+
},
107+
),
108+
migrations.CreateModel(
109+
name='TaskAssignee',
110+
fields=[
111+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
112+
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='assignee_links', to='kanban.task')),
113+
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='task_assignees', to=settings.AUTH_USER_MODEL)),
114+
],
115+
options={
116+
'unique_together': {('task', 'user')},
117+
},
118+
),
119+
migrations.AddField(
120+
model_name='task',
121+
name='assignees',
122+
field=models.ManyToManyField(blank=True, related_name='assigned_tasks', through='kanban.TaskAssignee', to=settings.AUTH_USER_MODEL),
123+
),
124+
migrations.AddField(
125+
model_name='task',
126+
name='board',
127+
field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='tasks', to='kanban.board'),
128+
),
129+
migrations.AddField(
130+
model_name='task',
131+
name='column',
132+
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tasks', to='kanban.boardcolumn'),
133+
),
134+
migrations.AddField(
135+
model_name='task',
136+
name='creator',
137+
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='created_tasks', to=settings.AUTH_USER_MODEL),
138+
),
139+
migrations.AddField(
140+
model_name='task',
141+
name='files',
142+
field=models.ManyToManyField(blank=True, related_name='kanban_tasks', through='kanban.TaskAttachment', to='files.userfile'),
143+
),
144+
migrations.AddField(
145+
model_name='task',
146+
name='goal',
147+
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tasks', to='projects.projectgoal'),
148+
),
149+
migrations.AddField(
150+
model_name='task',
151+
name='responsible',
152+
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='responsible_tasks', to=settings.AUTH_USER_MODEL),
153+
),
154+
migrations.AddField(
155+
model_name='task',
156+
name='skills',
157+
field=models.ManyToManyField(blank=True, related_name='kanban_tasks', through='kanban.TaskSkillLink', to='core.skill'),
158+
),
159+
migrations.AddField(
160+
model_name='task',
161+
name='tags',
162+
field=models.ManyToManyField(blank=True, related_name='tasks', through='kanban.TaskTagLink', to='kanban.boardtag'),
163+
),
164+
]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Generated by Django 4.2.24 on 2025-11-20 06:10
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('files', '0007_auto_20230929_1727'),
12+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13+
('kanban', '0002_boardtag_task_alter_boardcolumn_tasks_count_and_more'),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='TaskComment',
19+
fields=[
20+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21+
('text', models.TextField()),
22+
('created_at', models.DateTimeField(auto_now_add=True)),
23+
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='task_comments', to=settings.AUTH_USER_MODEL)),
24+
('file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task_comment_files', to='files.userfile')),
25+
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='kanban.task')),
26+
],
27+
options={
28+
'ordering': ['created_at'],
29+
},
30+
),
31+
]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from django.db import migrations
2+
3+
4+
def create_board_and_column(apps, schema_editor):
5+
Board = apps.get_model("kanban", "Board")
6+
BoardColumn = apps.get_model("kanban", "BoardColumn")
7+
Project = apps.get_model("projects", "Project")
8+
9+
for project in Project.objects.all():
10+
if Board.objects.filter(project=project).exists():
11+
continue
12+
board = Board.objects.create(project=project, name=project.name or "Канбан")
13+
BoardColumn.objects.create(board=board, name="Бэклог", order=1)
14+
15+
16+
class Migration(migrations.Migration):
17+
dependencies = [
18+
("kanban", "0003_taskcomment"),
19+
]
20+
21+
operations = [
22+
migrations.RunPython(create_board_and_column, migrations.RunPython.noop),
23+
]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Generated by Django 4.2.24 on 2025-11-25 05:06
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12+
('kanban', '0004_auto_create_default_board'),
13+
]
14+
15+
operations = [
16+
migrations.AlterField(
17+
model_name='boardcolumn',
18+
name='tasks_count',
19+
field=models.PositiveIntegerField(default=0, editable=False, help_text='Количество задач в столбце.'),
20+
),
21+
migrations.AlterField(
22+
model_name='task',
23+
name='creator',
24+
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_tasks', to=settings.AUTH_USER_MODEL),
25+
),
26+
migrations.AlterField(
27+
model_name='task',
28+
name='responsible',
29+
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='responsible_tasks', to=settings.AUTH_USER_MODEL),
30+
),
31+
]

kanban/migrations/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)