chore(django): track initial migrations and test config
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -17,10 +17,8 @@ db.sqlite3
|
||||
media/
|
||||
staticfiles/
|
||||
|
||||
# Migrations (except __init__.py)
|
||||
**/migrations/*.py
|
||||
**/migrations/*.pyc
|
||||
!**/migrations/__init__.py
|
||||
# Migrations
|
||||
**/migrations/*.pyc
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
80
apps/clients/migrations/0001_initial.py
Normal file
80
apps/clients/migrations/0001_initial.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-11 10:22
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("workspaces", "0001_initial"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Client",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
("is_active", models.BooleanField(default=False)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("notes", models.TextField(blank=True)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"workspace",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="clients",
|
||||
to="workspaces.workspace",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "client",
|
||||
"ordering": ("-updated_at", "-created_at"),
|
||||
"indexes": [
|
||||
models.Index(fields=["id"], name="client_id_idx"),
|
||||
models.Index(fields=["workspace"], name="client_workspace_idx"),
|
||||
],
|
||||
"constraints": [
|
||||
models.UniqueConstraint(
|
||||
condition=models.Q(("is_deleted", False)),
|
||||
fields=("workspace", "name"),
|
||||
name="unique_client_name_per_workspace",
|
||||
)
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
306
apps/projects/migrations/0001_initial.py
Normal file
306
apps/projects/migrations/0001_initial.py
Normal file
@@ -0,0 +1,306 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-11 11:01
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("clients", "0001_initial"),
|
||||
("workspaces", "0001_initial"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Project",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
("is_active", models.BooleanField(default=False)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("description", models.TextField(blank=True)),
|
||||
("is_archived", models.BooleanField(default=False)),
|
||||
("color", models.CharField(blank=True, max_length=7)),
|
||||
(
|
||||
"client",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="projects",
|
||||
to="clients.client",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"workspace",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="projects",
|
||||
to="workspaces.workspace",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "project",
|
||||
"ordering": ("-updated_at", "-created_at"),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ProjectMembership",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
(
|
||||
"role",
|
||||
models.CharField(
|
||||
choices=[("manager", "Manager"), ("member", "Member")],
|
||||
default="member",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
("is_active", models.BooleanField(default=True)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"project",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="memberships",
|
||||
to="projects.project",
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="project_memberships",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "project_membership",
|
||||
"ordering": ("-created_at",),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ProjectRate",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
("hourly_rate", models.DecimalField(decimal_places=2, max_digits=10)),
|
||||
("currency", models.CharField(default="USD", max_length=3)),
|
||||
("effective_from", models.DateTimeField()),
|
||||
("is_active", models.BooleanField(default=True)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"project",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="rates",
|
||||
to="projects.project",
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "project_rate",
|
||||
"ordering": ("-effective_from",),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ProjectUserRate",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
("hourly_rate", models.DecimalField(decimal_places=2, max_digits=10)),
|
||||
("currency", models.CharField(default="USD", max_length=3)),
|
||||
("effective_from", models.DateTimeField()),
|
||||
("is_active", models.BooleanField(default=True)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"project",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="user_rates",
|
||||
to="projects.project",
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="project_rates",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "project_user_rate",
|
||||
"ordering": ("-effective_from",),
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="project",
|
||||
index=models.Index(fields=["workspace"], name="project_workspace_idx"),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="project",
|
||||
constraint=models.UniqueConstraint(
|
||||
condition=models.Q(("is_deleted", False)),
|
||||
fields=("workspace", "name"),
|
||||
name="unique_project_name_per_workspace",
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="projectmembership",
|
||||
index=models.Index(
|
||||
fields=["project"], name="project_membership_project_idx"
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="projectmembership",
|
||||
index=models.Index(fields=["user"], name="project_membership_user_idx"),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="projectmembership",
|
||||
constraint=models.UniqueConstraint(
|
||||
condition=models.Q(("is_deleted", False)),
|
||||
fields=("project", "user"),
|
||||
name="unique_project_membership",
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="projectrate",
|
||||
index=models.Index(fields=["project"], name="project_rate_project_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="projectuserrate",
|
||||
index=models.Index(fields=["project"], name="pur_project_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="projectuserrate",
|
||||
index=models.Index(fields=["user"], name="pur_user_idx"),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="projectuserrate",
|
||||
constraint=models.UniqueConstraint(
|
||||
condition=models.Q(("is_deleted", False)),
|
||||
fields=("project", "user", "effective_from"),
|
||||
name="unique_project_user_rate_time",
|
||||
),
|
||||
),
|
||||
]
|
||||
80
apps/tags/migrations/0001_initial.py
Normal file
80
apps/tags/migrations/0001_initial.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-11 11:16
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("workspaces", "0001_initial"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Tag",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
("is_active", models.BooleanField(default=False)),
|
||||
("name", models.CharField(max_length=100)),
|
||||
("color", models.CharField(blank=True, max_length=7)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"workspace",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="tags",
|
||||
to="workspaces.workspace",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "tag",
|
||||
"ordering": ("-updated_at", "-created_at"),
|
||||
"indexes": [
|
||||
models.Index(fields=["id"], name="tag_id_idx"),
|
||||
models.Index(fields=["workspace"], name="tag_workspace_idx"),
|
||||
],
|
||||
"constraints": [
|
||||
models.UniqueConstraint(
|
||||
condition=models.Q(("is_deleted", False)),
|
||||
fields=("workspace", "name"),
|
||||
name="unique_tag_name_per_workspace",
|
||||
)
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
124
apps/time_entries/migrations/0001_initial.py
Normal file
124
apps/time_entries/migrations/0001_initial.py
Normal file
@@ -0,0 +1,124 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-11 11:29
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("projects", "0001_initial"),
|
||||
("tags", "0001_initial"),
|
||||
("workspaces", "0001_initial"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="TimeEntry",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
("is_active", models.BooleanField(default=False)),
|
||||
("description", models.TextField(blank=True)),
|
||||
("start_time", models.DateTimeField()),
|
||||
("end_time", models.DateTimeField(blank=True, null=True)),
|
||||
("duration", models.DurationField(blank=True, null=True)),
|
||||
("is_billable", models.BooleanField(default=False)),
|
||||
(
|
||||
"hourly_rate",
|
||||
models.DecimalField(
|
||||
blank=True, decimal_places=2, max_digits=10, null=True
|
||||
),
|
||||
),
|
||||
("currency", models.CharField(default="USD", max_length=3)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"project",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="time_entries",
|
||||
to="projects.project",
|
||||
),
|
||||
),
|
||||
(
|
||||
"tags",
|
||||
models.ManyToManyField(
|
||||
blank=True, related_name="time_entries", to="tags.tag"
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="time_entries",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"workspace",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="time_entries",
|
||||
to="workspaces.workspace",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "time_entry",
|
||||
"ordering": ("-updated_at", "-created_at"),
|
||||
"indexes": [
|
||||
models.Index(fields=["workspace"], name="time_entry_workspace_idx"),
|
||||
models.Index(fields=["user"], name="time_entry_user_idx"),
|
||||
models.Index(fields=["project"], name="time_entry_project_idx"),
|
||||
models.Index(fields=["start_time"], name="time_entry_start_idx"),
|
||||
models.Index(
|
||||
fields=["workspace", "start_time"],
|
||||
name="time_entry_workspace_start_idx",
|
||||
),
|
||||
],
|
||||
"constraints": [
|
||||
models.UniqueConstraint(
|
||||
condition=models.Q(
|
||||
("end_time__isnull", True), ("is_deleted", False)
|
||||
),
|
||||
fields=("workspace", "user"),
|
||||
name="unique_running_timer_per_user",
|
||||
)
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
213
apps/users/migrations/0001_initial.py
Normal file
213
apps/users/migrations/0001_initial.py
Normal file
@@ -0,0 +1,213 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-10 23:27
|
||||
|
||||
import apps.users.services.managers
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("auth", "0012_alter_user_first_name_max_length"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="User",
|
||||
fields=[
|
||||
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||
(
|
||||
"last_login",
|
||||
models.DateTimeField(
|
||||
blank=True, null=True, verbose_name="last login"
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_superuser",
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text="Designates that this user has all permissions without explicitly assigning them.",
|
||||
verbose_name="superuser status",
|
||||
),
|
||||
),
|
||||
(
|
||||
"first_name",
|
||||
models.CharField(
|
||||
blank=True, max_length=150, verbose_name="first name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"last_name",
|
||||
models.CharField(
|
||||
blank=True, max_length=150, verbose_name="last name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_staff",
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text="Designates whether the user can log into this admin site.",
|
||||
verbose_name="staff status",
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_active",
|
||||
models.BooleanField(
|
||||
default=True,
|
||||
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
|
||||
verbose_name="active",
|
||||
),
|
||||
),
|
||||
(
|
||||
"date_joined",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now, verbose_name="date joined"
|
||||
),
|
||||
),
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
("mobile", models.CharField(max_length=11, unique=True)),
|
||||
("email", models.EmailField(blank=True, default="", max_length=254)),
|
||||
("description", models.TextField(blank=True, default="")),
|
||||
(
|
||||
"profile_picture",
|
||||
models.ImageField(
|
||||
blank=True, null=True, upload_to="profile/users/"
|
||||
),
|
||||
),
|
||||
("birth_date", models.DateField(blank=True, null=True)),
|
||||
("password_updated_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_verified", models.BooleanField(default=False)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"groups",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
|
||||
related_name="user_set",
|
||||
related_query_name="user",
|
||||
to="auth.group",
|
||||
verbose_name="groups",
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user_permissions",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Specific permissions for this user.",
|
||||
related_name="user_set",
|
||||
related_query_name="user",
|
||||
to="auth.permission",
|
||||
verbose_name="user permissions",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "user",
|
||||
"verbose_name_plural": "users",
|
||||
"db_table": "user",
|
||||
"ordering": ("-updated_at", "-created_at"),
|
||||
},
|
||||
managers=[
|
||||
("objects", apps.users.services.managers.UserManager(alive_only=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="LoginAttempt",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
("is_active", models.BooleanField(default=False)),
|
||||
(
|
||||
"status",
|
||||
models.PositiveSmallIntegerField(
|
||||
choices=[(0, "failed"), (1, "success")], default=0
|
||||
),
|
||||
),
|
||||
("ip_address", models.GenericIPAddressField(blank=True, null=True)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "login_attempts",
|
||||
"verbose_name_plural": "login_attempts",
|
||||
"db_table": "login_attempt",
|
||||
"ordering": ("-updated_at", "-created_at"),
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="user",
|
||||
index=models.Index(fields=["id"], name="user_id_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="user",
|
||||
index=models.Index(fields=["mobile"], name="user_mobile_idx"),
|
||||
),
|
||||
]
|
||||
158
apps/workspaces/migrations/0001_initial.py
Normal file
158
apps/workspaces/migrations/0001_initial.py
Normal file
@@ -0,0 +1,158 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-11 09:14
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Workspace",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
("is_active", models.BooleanField(default=False)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("description", models.TextField(blank=True)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"owner",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="owned_workspaces",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "workspace",
|
||||
"ordering": ("-updated_at", "-created_at"),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="WorkspaceMembership",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid7, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("deleted_at", models.DateTimeField(blank=True, null=True)),
|
||||
("is_deleted", models.BooleanField(default=False)),
|
||||
(
|
||||
"role",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("owner", "Owner"),
|
||||
("admin", "Admin"),
|
||||
("member", "Member"),
|
||||
("guest", "Guest"),
|
||||
],
|
||||
default="member",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
("is_active", models.BooleanField(default=True)),
|
||||
("joined_at", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="created_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="updated_%(app_label)s_%(class)s_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="workspace_memberships",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"workspace",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="memberships",
|
||||
to="workspaces.workspace",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "workspace_membership",
|
||||
"ordering": ("-created_at",),
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="workspace",
|
||||
index=models.Index(fields=["owner"], name="workspace_owner_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="workspacemembership",
|
||||
index=models.Index(fields=["workspace"], name="membership_workspace_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="workspacemembership",
|
||||
index=models.Index(fields=["user"], name="membership_user_idx"),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="workspacemembership",
|
||||
constraint=models.UniqueConstraint(
|
||||
condition=models.Q(("is_deleted", False)),
|
||||
fields=("workspace", "user"),
|
||||
name="unique_workspace_membership",
|
||||
),
|
||||
),
|
||||
]
|
||||
30
config/settings/test.py
Normal file
30
config/settings/test.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from .base import *
|
||||
|
||||
DEBUG = False
|
||||
SECRET_KEY = SECRET_KEY or "qlockify-test-secret-key"
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "test.sqlite3",
|
||||
}
|
||||
}
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
|
||||
"LOCATION": "qlockify-tests",
|
||||
}
|
||||
}
|
||||
|
||||
PASSWORD_HASHERS = [
|
||||
"django.contrib.auth.hashers.MD5PasswordHasher",
|
||||
]
|
||||
|
||||
MEDIA_ROOT = BASE_DIR / "test_media"
|
||||
STATIC_ROOT = BASE_DIR / "test_static"
|
||||
|
||||
CELERY_TASK_ALWAYS_EAGER = True
|
||||
CELERY_TASK_EAGER_PROPAGATES = True
|
||||
|
||||
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
||||
3
pytest.ini
Normal file
3
pytest.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[pytest]
|
||||
DJANGO_SETTINGS_MODULE = config.settings.test
|
||||
python_files = tests.py test_*.py *_tests.py
|
||||
Reference in New Issue
Block a user