Files
qlockify-backend-deployment/apps/workspaces/models.py

176 lines
5.1 KiB
Python

from django.contrib.auth import get_user_model
from django.db import models
from apps.logs.services import build_workspace_log_metadata
from apps.logs.services.constants import (
SECTION_RATES,
SECTION_WORKSPACE,
SECTION_WORKSPACE_MEMBERS,
)
from core.models.base import BaseModel
User = get_user_model()
class Workspace(BaseModel):
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
thumbnail = models.ImageField(upload_to="profile/workspaces/", blank=True, null=True)
owner = models.ForeignKey(
User,
on_delete=models.PROTECT,
related_name="owned_workspaces",
)
class Meta:
db_table = "workspace"
ordering = ("-updated_at", "-created_at")
indexes = [
models.Index(fields=["owner"], name="workspace_owner_idx"),
]
def __str__(self):
return self.name
def get_additional_data(self):
return build_workspace_log_metadata(
section=SECTION_WORKSPACE,
workspace_id=self.id,
target_id=self.id,
target_label=self.name,
extra={"owner_id": str(self.owner_id)},
)
@property
def members(self):
return User.objects.filter(
workspace_memberships__workspace=self,
workspace_memberships__is_active=True,
)
class WorkspaceMembership(BaseModel):
class Role(models.TextChoices):
OWNER = "owner", "Owner"
ADMIN = "admin", "Admin"
MEMBER = "member", "Member"
GUEST = "guest", "Guest"
workspace = models.ForeignKey(
Workspace,
on_delete=models.CASCADE,
related_name="memberships",
)
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="workspace_memberships",
)
role = models.CharField(
max_length=20,
choices=Role.choices,
default=Role.MEMBER,
)
is_active = models.BooleanField(default=True)
joined_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "workspace_membership"
ordering = ("-created_at",)
indexes = [
models.Index(fields=["workspace"], name="membership_workspace_idx"),
models.Index(fields=["user"], name="membership_user_idx"),
models.Index(fields=["workspace", "is_active", "user"], name="membership_ws_active_user_idx"),
]
constraints = [
models.UniqueConstraint(
fields=["workspace", "user"],
name="unique_workspace_membership",
condition=models.Q(is_deleted=False),
)
]
def __str__(self):
return f"{self.user} @ {self.workspace}"
def get_additional_data(self):
return build_workspace_log_metadata(
section=SECTION_WORKSPACE_MEMBERS,
workspace_id=self.workspace_id,
target_id=self.id,
target_label=self.user.full_name or self.user.mobile,
extra={
"member_user_id": str(self.user_id),
"role": self.role,
"canonical_owner_membership": (
self.role == self.Role.OWNER and self.user_id == self.workspace.owner_id
),
},
)
class PriceUnit(BaseModel):
code = models.CharField(max_length=8, unique=True)
name = models.CharField(max_length=64)
local_name = models.CharField(max_length=64, blank=True)
symbol = models.CharField(max_length=16, blank=True)
class Meta:
db_table = "price_unit"
ordering = ("code",)
indexes = [
models.Index(fields=["code"], name="price_unit_code_idx"),
]
def __str__(self):
return self.code
class WorkspaceUserRate(BaseModel):
workspace = models.ForeignKey(
Workspace,
on_delete=models.CASCADE,
related_name="user_rates",
)
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="workspace_rates",
)
hourly_rate = models.DecimalField(
max_digits=10,
decimal_places=2,
)
currency = models.CharField(
max_length=3,
default="USD",
)
effective_from = models.DateTimeField()
class Meta:
db_table = "workspace_user_rate"
ordering = ("-effective_from",)
constraints = [
models.UniqueConstraint(
fields=["workspace", "user"],
name="unique_workspace_user_rate",
condition=models.Q(is_deleted=False),
)
]
indexes = [
models.Index(fields=["workspace"], name="wur_workspace_idx"),
models.Index(fields=["user"], name="wur_user_idx"),
]
def get_additional_data(self):
return build_workspace_log_metadata(
section=SECTION_RATES,
workspace_id=self.workspace_id,
target_id=self.id,
target_label=self.user.full_name or self.user.mobile,
extra={
"rate_user_id": str(self.user_id),
"currency": self.currency,
},
)