[WEB-5044] fix: ruff lint and format errors (#7868)
* fix: lint errors * fix: file formatting * fix: code refactor
This commit is contained in:
parent
1fb22bd252
commit
9237f568dd
261 changed files with 2199 additions and 6378 deletions
|
|
@ -14,9 +14,7 @@ class Command(BaseCommand):
|
|||
try:
|
||||
if options["key"]:
|
||||
cache.delete(options["key"])
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"Cache Cleared for key: {options['key']}")
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS(f"Cache Cleared for key: {options['key']}"))
|
||||
return
|
||||
|
||||
cache.clear()
|
||||
|
|
|
|||
|
|
@ -16,12 +16,8 @@ class Command(BaseCommand):
|
|||
s3_client = boto3.client(
|
||||
"s3",
|
||||
endpoint_url=os.environ.get("AWS_S3_ENDPOINT_URL"), # MinIO endpoint
|
||||
aws_access_key_id=os.environ.get(
|
||||
"AWS_ACCESS_KEY_ID"
|
||||
), # MinIO access key
|
||||
aws_secret_access_key=os.environ.get(
|
||||
"AWS_SECRET_ACCESS_KEY"
|
||||
), # MinIO secret key
|
||||
aws_access_key_id=os.environ.get("AWS_ACCESS_KEY_ID"), # MinIO access key
|
||||
aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY"), # MinIO secret key
|
||||
region_name=os.environ.get("AWS_REGION"), # MinIO region
|
||||
config=boto3.session.Config(signature_version="s3v4"),
|
||||
)
|
||||
|
|
@ -38,32 +34,20 @@ class Command(BaseCommand):
|
|||
bucket_name = os.environ.get("AWS_S3_BUCKET_NAME")
|
||||
if error_code == 404:
|
||||
# Bucket does not exist, create it
|
||||
self.stdout.write(
|
||||
self.style.WARNING(
|
||||
f"Bucket '{bucket_name}' does not exist. Creating bucket..."
|
||||
)
|
||||
)
|
||||
self.stdout.write(self.style.WARNING(f"Bucket '{bucket_name}' does not exist. Creating bucket..."))
|
||||
try:
|
||||
s3_client.create_bucket(Bucket=bucket_name)
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
f"Bucket '{bucket_name}' created successfully."
|
||||
)
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS(f"Bucket '{bucket_name}' created successfully."))
|
||||
|
||||
# Handle the exception if the bucket creation fails
|
||||
except ClientError as create_error:
|
||||
self.stdout.write(
|
||||
self.style.ERROR(f"Failed to create bucket: {create_error}")
|
||||
)
|
||||
self.stdout.write(self.style.ERROR(f"Failed to create bucket: {create_error}"))
|
||||
|
||||
# Handle the exception if access to the bucket is forbidden
|
||||
elif error_code == 403:
|
||||
# Access to the bucket is forbidden
|
||||
self.stdout.write(
|
||||
self.style.ERROR(
|
||||
f"Access to the bucket '{bucket_name}' is forbidden. Check permissions."
|
||||
)
|
||||
self.style.ERROR(f"Access to the bucket '{bucket_name}' is forbidden. Check permissions.")
|
||||
)
|
||||
else:
|
||||
# Another ClientError occurred
|
||||
|
|
|
|||
|
|
@ -23,27 +23,20 @@ class Command(BaseCommand):
|
|||
creator = input("Your email: ")
|
||||
|
||||
if creator == "" or not User.objects.filter(email=creator).exists():
|
||||
raise CommandError(
|
||||
"User email is required and should have signed in plane"
|
||||
)
|
||||
raise CommandError("User email is required and should have signed in plane")
|
||||
|
||||
user = User.objects.get(email=creator)
|
||||
|
||||
members = input("Enter Member emails (comma separated): ")
|
||||
members = members.split(",") if members != "" else []
|
||||
# Create workspace
|
||||
workspace = Workspace.objects.create(
|
||||
slug=workspace_slug, name=workspace_name, owner=user
|
||||
)
|
||||
workspace = Workspace.objects.create(slug=workspace_slug, name=workspace_name, owner=user)
|
||||
# Create workspace member
|
||||
WorkspaceMember.objects.create(workspace=workspace, role=20, member=user)
|
||||
user_ids = User.objects.filter(email__in=members)
|
||||
|
||||
_ = WorkspaceMember.objects.bulk_create(
|
||||
[
|
||||
WorkspaceMember(workspace=workspace, member=user_id, role=20)
|
||||
for user_id in user_ids
|
||||
],
|
||||
[WorkspaceMember(workspace=workspace, member=user_id, role=20) for user_id in user_ids],
|
||||
ignore_conflicts=True,
|
||||
)
|
||||
|
||||
|
|
@ -55,9 +48,7 @@ class Command(BaseCommand):
|
|||
cycle_count = int(input("Number of cycles to be created: "))
|
||||
module_count = int(input("Number of modules to be created: "))
|
||||
pages_count = int(input("Number of pages to be created: "))
|
||||
intake_issue_count = int(
|
||||
input("Number of intake issues to be created: ")
|
||||
)
|
||||
intake_issue_count = int(input("Number of intake issues to be created: "))
|
||||
|
||||
from plane.bgtasks.dummy_data_task import create_dummy_data
|
||||
|
||||
|
|
|
|||
|
|
@ -28,9 +28,7 @@ class Command(BaseCommand):
|
|||
instance = Instance.objects.last()
|
||||
|
||||
# Get or create an instance admin
|
||||
_, created = InstanceAdmin.objects.get_or_create(
|
||||
user=user, instance=instance, role=20
|
||||
)
|
||||
_, created = InstanceAdmin.objects.get_or_create(user=user, instance=instance, role=20)
|
||||
|
||||
if not created:
|
||||
raise CommandError("The provided email is already an instance admin.")
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@ class Command(BaseCommand):
|
|||
# Positional argument
|
||||
parser.add_argument("--project_id", type=str, nargs="?", help="Project ID")
|
||||
parser.add_argument("--user_email", type=str, nargs="?", help="User Email")
|
||||
parser.add_argument(
|
||||
"--role", type=int, nargs="?", help="Role of the user in the project"
|
||||
)
|
||||
parser.add_argument("--role", type=int, nargs="?", help="Role of the user in the project")
|
||||
|
||||
def handle(self, *args: Any, **options: Any):
|
||||
try:
|
||||
|
|
@ -46,16 +44,12 @@ class Command(BaseCommand):
|
|||
raise CommandError("Project not found")
|
||||
|
||||
# Check if the user exists in the workspace
|
||||
if not WorkspaceMember.objects.filter(
|
||||
workspace=project.workspace, member=user, is_active=True
|
||||
).exists():
|
||||
if not WorkspaceMember.objects.filter(workspace=project.workspace, member=user, is_active=True).exists():
|
||||
raise CommandError("User not member in workspace")
|
||||
|
||||
# Get the smallest sort order
|
||||
smallest_sort_order = (
|
||||
ProjectMember.objects.filter(workspace_id=project.workspace_id)
|
||||
.order_by("sort_order")
|
||||
.first()
|
||||
ProjectMember.objects.filter(workspace_id=project.workspace_id).order_by("sort_order").first()
|
||||
)
|
||||
|
||||
if smallest_sort_order:
|
||||
|
|
@ -70,17 +64,13 @@ class Command(BaseCommand):
|
|||
)
|
||||
else:
|
||||
# Create the project member
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=user, role=role, sort_order=sort_order
|
||||
)
|
||||
ProjectMember.objects.create(project=project, member=user, role=role, sort_order=sort_order)
|
||||
|
||||
# Issue Property
|
||||
IssueUserProperty.objects.get_or_create(user=user, project=project)
|
||||
|
||||
# Success message
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"User {user_email} added to project {project_id}")
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS(f"User {user_email} added to project {project_id}"))
|
||||
return
|
||||
except CommandError as e:
|
||||
self.stdout.write(self.style.ERROR(e))
|
||||
|
|
|
|||
|
|
@ -43,23 +43,15 @@ class Command(BaseCommand):
|
|||
issue_sequence = self.strict_str_to_int(identifier[1])
|
||||
|
||||
# Fetch the project
|
||||
project = Project.objects.get(
|
||||
identifier__iexact=project_identifier, workspace__slug=workspace_slug
|
||||
)
|
||||
project = Project.objects.get(identifier__iexact=project_identifier, workspace__slug=workspace_slug)
|
||||
|
||||
# Get the issues
|
||||
issues = Issue.objects.filter(project=project, sequence_id=issue_sequence)
|
||||
# Check if there are duplicate issues
|
||||
if not issues.count() > 1:
|
||||
raise CommandError(
|
||||
"No duplicate issues found with the given identifier"
|
||||
)
|
||||
raise CommandError("No duplicate issues found with the given identifier")
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
f"{issues.count()} issues found with identifier {issue_identifier}"
|
||||
)
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS(f"{issues.count()} issues found with identifier {issue_identifier}"))
|
||||
with transaction.atomic():
|
||||
# This ensures only one transaction per project can execute this code at a time
|
||||
lock_key = convert_uuid_to_integer(project.id)
|
||||
|
|
@ -70,17 +62,14 @@ class Command(BaseCommand):
|
|||
cursor.execute("SELECT pg_advisory_xact_lock(%s)", [lock_key])
|
||||
|
||||
# Get the maximum sequence ID for the project
|
||||
last_sequence = IssueSequence.objects.filter(project=project).aggregate(
|
||||
largest=Max("sequence")
|
||||
)["largest"]
|
||||
last_sequence = IssueSequence.objects.filter(project=project).aggregate(largest=Max("sequence"))[
|
||||
"largest"
|
||||
]
|
||||
|
||||
bulk_issues = []
|
||||
bulk_issue_sequences = []
|
||||
|
||||
issue_sequence_map = {
|
||||
isq.issue_id: isq
|
||||
for isq in IssueSequence.objects.filter(project=project)
|
||||
}
|
||||
issue_sequence_map = {isq.issue_id: isq for isq in IssueSequence.objects.filter(project=project)}
|
||||
|
||||
# change the ids of duplicate issues
|
||||
for index, issue in enumerate(issues[1:]):
|
||||
|
|
|
|||
|
|
@ -14,10 +14,6 @@ class Command(BaseCommand):
|
|||
batch_size = input("Enter the batch size: ")
|
||||
batch_countdown = input("Enter the batch countdown: ")
|
||||
|
||||
schedule_issue_description_version.delay(
|
||||
batch_size=batch_size, countdown=int(batch_countdown)
|
||||
)
|
||||
schedule_issue_description_version.delay(batch_size=batch_size, countdown=int(batch_countdown))
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS("Successfully created issue description version task")
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS("Successfully created issue description version task"))
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ class Command(BaseCommand):
|
|||
batch_size = input("Enter the batch size: ")
|
||||
batch_countdown = input("Enter the batch countdown: ")
|
||||
|
||||
schedule_issue_version.delay(
|
||||
batch_size=batch_size, countdown=int(batch_countdown)
|
||||
)
|
||||
schedule_issue_version.delay(batch_size=batch_size, countdown=int(batch_countdown))
|
||||
|
||||
self.stdout.write(self.style.SUCCESS("Successfully created issue version task"))
|
||||
|
|
|
|||
|
|
@ -60,6 +60,4 @@ class Command(BaseCommand):
|
|||
msg.send()
|
||||
self.stdout.write(self.style.SUCCESS("Email successfully sent"))
|
||||
except Exception as e:
|
||||
self.stdout.write(
|
||||
self.style.ERROR(f"Error: Email could not be delivered due to {e}")
|
||||
)
|
||||
self.stdout.write(self.style.ERROR(f"Error: Email could not be delivered due to {e}"))
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@ class Command(BaseCommand):
|
|||
"s3",
|
||||
endpoint_url=os.environ.get("AWS_S3_ENDPOINT_URL"), # MinIO endpoint
|
||||
aws_access_key_id=os.environ.get("AWS_ACCESS_KEY_ID"), # MinIO access key
|
||||
aws_secret_access_key=os.environ.get(
|
||||
"AWS_SECRET_ACCESS_KEY"
|
||||
), # MinIO secret key
|
||||
aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY"), # MinIO secret key
|
||||
region_name=os.environ.get("AWS_REGION"), # MinIO region
|
||||
config=boto3.session.Config(signature_version="s3v4"),
|
||||
)
|
||||
|
|
@ -59,9 +57,7 @@ class Command(BaseCommand):
|
|||
|
||||
# 3. Test s3:PutObject (attempt to upload an object)
|
||||
try:
|
||||
s3_client.put_object(
|
||||
Bucket=bucket_name, Key="test_permission_check.txt", Body=b"Test"
|
||||
)
|
||||
s3_client.put_object(Bucket=bucket_name, Key="test_permission_check.txt", Body=b"Test")
|
||||
permissions["s3:PutObject"] = True
|
||||
# Clean up
|
||||
except ClientError as e:
|
||||
|
|
@ -106,9 +102,7 @@ class Command(BaseCommand):
|
|||
if "Contents" in response:
|
||||
for obj in response["Contents"]:
|
||||
object_key = obj["Key"]
|
||||
public_object_resource.append(
|
||||
f"arn:aws:s3:::{bucket_name}/{object_key}"
|
||||
)
|
||||
public_object_resource.append(f"arn:aws:s3:::{bucket_name}/{object_key}")
|
||||
bucket_policy = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
|
|
@ -128,9 +122,7 @@ class Command(BaseCommand):
|
|||
# Get the bucket policy
|
||||
bucket_policy = self.generate_bucket_policy(bucket_name)
|
||||
# Apply the policy to the bucket
|
||||
s3_client.put_bucket_policy(
|
||||
Bucket=bucket_name, Policy=json.dumps(bucket_policy)
|
||||
)
|
||||
s3_client.put_bucket_policy(Bucket=bucket_name, Policy=json.dumps(bucket_policy))
|
||||
# Print a success message
|
||||
self.stdout.write("Bucket is private, but existing objects remain public.")
|
||||
return
|
||||
|
|
@ -144,11 +136,7 @@ class Command(BaseCommand):
|
|||
bucket_name = os.environ.get("AWS_S3_BUCKET_NAME")
|
||||
|
||||
if not bucket_name:
|
||||
self.stdout.write(
|
||||
self.style.ERROR(
|
||||
"Please set the AWS_S3_BUCKET_NAME environment variable."
|
||||
)
|
||||
)
|
||||
self.stdout.write(self.style.ERROR("Please set the AWS_S3_BUCKET_NAME environment variable."))
|
||||
return
|
||||
|
||||
self.stdout.write(self.style.NOTICE("Checking bucket..."))
|
||||
|
|
@ -158,9 +146,7 @@ class Command(BaseCommand):
|
|||
except ClientError as e:
|
||||
error_code = e.response["Error"]["Code"]
|
||||
if error_code == "404":
|
||||
self.stdout.write(
|
||||
self.style.ERROR(f"Bucket '{bucket_name}' does not exist.")
|
||||
)
|
||||
self.stdout.write(self.style.ERROR(f"Bucket '{bucket_name}' does not exist."))
|
||||
return
|
||||
else:
|
||||
self.stdout.write(f"Error: {e}")
|
||||
|
|
@ -177,9 +163,7 @@ class Command(BaseCommand):
|
|||
# If the access key has the required permissions
|
||||
try:
|
||||
if all(permissions.values()):
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS("Access key has the required permissions.")
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS("Access key has the required permissions."))
|
||||
# Making the existing objects public
|
||||
self.make_objects_public(bucket_name)
|
||||
return
|
||||
|
|
@ -187,18 +171,12 @@ class Command(BaseCommand):
|
|||
self.stdout.write(f"Error: {e}")
|
||||
|
||||
# write the bucket policy to a file
|
||||
self.stdout.write(
|
||||
self.style.WARNING(
|
||||
"Generating permissions.json for manual bucket policy update."
|
||||
)
|
||||
)
|
||||
self.stdout.write(self.style.WARNING("Generating permissions.json for manual bucket policy update."))
|
||||
try:
|
||||
# Writing to a file
|
||||
with open("permissions.json", "w") as f:
|
||||
f.write(json.dumps(self.generate_bucket_policy(bucket_name)))
|
||||
self.stdout.write(
|
||||
self.style.WARNING("Permissions have been written to permissions.json.")
|
||||
)
|
||||
self.stdout.write(self.style.WARNING("Permissions have been written to permissions.json."))
|
||||
return
|
||||
except IOError as e:
|
||||
self.stdout.write(f"Error writing permissions.json: {e}")
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ from plane.db.models import Workspace
|
|||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = (
|
||||
"Updates the slug of a soft-deleted workspace by appending the epoch timestamp"
|
||||
)
|
||||
help = "Updates the slug of a soft-deleted workspace by appending the epoch timestamp"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
|
|
@ -28,17 +26,13 @@ class Command(BaseCommand):
|
|||
try:
|
||||
workspace = Workspace.all_objects.get(slug=slug)
|
||||
except Workspace.DoesNotExist:
|
||||
self.stdout.write(
|
||||
self.style.ERROR(f"Workspace with slug '{slug}' not found.")
|
||||
)
|
||||
self.stdout.write(self.style.ERROR(f"Workspace with slug '{slug}' not found."))
|
||||
return
|
||||
|
||||
# Check if the workspace is soft-deleted
|
||||
if workspace.deleted_at is None:
|
||||
self.stdout.write(
|
||||
self.style.WARNING(
|
||||
f"Workspace '{workspace.name}' (slug: {workspace.slug}) is not deleted."
|
||||
)
|
||||
self.style.WARNING(f"Workspace '{workspace.name}' (slug: {workspace.slug}) is not deleted.")
|
||||
)
|
||||
return
|
||||
|
||||
|
|
@ -58,9 +52,7 @@ class Command(BaseCommand):
|
|||
new_slug = f"{workspace.slug}__{deletion_timestamp}"
|
||||
|
||||
if dry_run:
|
||||
self.stdout.write(
|
||||
f"Would update workspace '{workspace.name}' slug from '{workspace.slug}' to '{new_slug}'"
|
||||
)
|
||||
self.stdout.write(f"Would update workspace '{workspace.name}' slug from '{workspace.slug}' to '{new_slug}'")
|
||||
else:
|
||||
try:
|
||||
with transaction.atomic():
|
||||
|
|
@ -72,8 +64,4 @@ class Command(BaseCommand):
|
|||
)
|
||||
)
|
||||
except Exception as e:
|
||||
self.stdout.write(
|
||||
self.style.ERROR(
|
||||
f"Error updating workspace '{workspace.name}': {str(e)}"
|
||||
)
|
||||
)
|
||||
self.stdout.write(self.style.ERROR(f"Error updating workspace '{workspace.name}': {str(e)}"))
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@ class Command(BaseCommand):
|
|||
self.stdout.write("Waiting for database migrations to complete...")
|
||||
time.sleep(10) # wait for 10 seconds before checking again
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS("No migrations Pending. Starting processes ...")
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS("No migrations Pending. Starting processes ..."))
|
||||
|
||||
def _pending_migrations(self):
|
||||
connection = connections[DEFAULT_DB_ALIAS]
|
||||
|
|
|
|||
|
|
@ -48,9 +48,7 @@ class SoftDeletionQuerySet(models.QuerySet):
|
|||
|
||||
class SoftDeletionManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return SoftDeletionQuerySet(self.model, using=self._db).filter(
|
||||
deleted_at__isnull=True
|
||||
)
|
||||
return SoftDeletionQuerySet(self.model, using=self._db).filter(deleted_at__isnull=True)
|
||||
|
||||
|
||||
class SoftDeleteModel(models.Model):
|
||||
|
|
@ -70,9 +68,7 @@ class SoftDeleteModel(models.Model):
|
|||
self.deleted_at = timezone.now()
|
||||
self.save(using=using)
|
||||
|
||||
soft_delete_related_objects.delay(
|
||||
self._meta.app_label, self._meta.model_name, self.pk, using=using
|
||||
)
|
||||
soft_delete_related_objects.delay(self._meta.app_label, self._meta.model_name, self.pk, using=using)
|
||||
|
||||
else:
|
||||
# Perform hard delete if soft deletion is not enabled
|
||||
|
|
|
|||
|
|
@ -84,4 +84,4 @@ from .device import Device, DeviceSession
|
|||
|
||||
from .sticky import Sticky
|
||||
|
||||
from .description import Description, DescriptionVersion
|
||||
from .description import Description, DescriptionVersion
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ from .base import BaseModel
|
|||
|
||||
|
||||
class AnalyticView(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", related_name="analytics", on_delete=models.CASCADE
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", related_name="analytics", on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField(blank=True)
|
||||
query = models.JSONField()
|
||||
|
|
|
|||
|
|
@ -24,20 +24,12 @@ class APIToken(BaseModel):
|
|||
last_used = models.DateTimeField(null=True)
|
||||
|
||||
# Token
|
||||
token = models.CharField(
|
||||
max_length=255, unique=True, default=generate_token, db_index=True
|
||||
)
|
||||
token = models.CharField(max_length=255, unique=True, default=generate_token, db_index=True)
|
||||
|
||||
# User Information
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="bot_tokens"
|
||||
)
|
||||
user_type = models.PositiveSmallIntegerField(
|
||||
choices=((0, "Human"), (1, "Bot")), default=0
|
||||
)
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", related_name="api_tokens", on_delete=models.CASCADE, null=True
|
||||
)
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="bot_tokens")
|
||||
user_type = models.PositiveSmallIntegerField(choices=((0, "Human"), (1, "Bot")), default=0)
|
||||
workspace = models.ForeignKey("db.Workspace", related_name="api_tokens", on_delete=models.CASCADE, null=True)
|
||||
expired_at = models.DateTimeField(blank=True, null=True)
|
||||
is_service = models.BooleanField(default=False)
|
||||
|
||||
|
|
|
|||
|
|
@ -40,27 +40,13 @@ class FileAsset(BaseModel):
|
|||
|
||||
attributes = models.JSONField(default=dict)
|
||||
asset = models.FileField(upload_to=get_upload_path, max_length=800)
|
||||
user = models.ForeignKey(
|
||||
"db.User", on_delete=models.CASCADE, null=True, related_name="assets"
|
||||
)
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, null=True, related_name="assets"
|
||||
)
|
||||
draft_issue = models.ForeignKey(
|
||||
"db.DraftIssue", on_delete=models.CASCADE, null=True, related_name="assets"
|
||||
)
|
||||
project = models.ForeignKey(
|
||||
"db.Project", on_delete=models.CASCADE, null=True, related_name="assets"
|
||||
)
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", on_delete=models.CASCADE, null=True, related_name="assets"
|
||||
)
|
||||
comment = models.ForeignKey(
|
||||
"db.IssueComment", on_delete=models.CASCADE, null=True, related_name="assets"
|
||||
)
|
||||
page = models.ForeignKey(
|
||||
"db.Page", on_delete=models.CASCADE, null=True, related_name="assets"
|
||||
)
|
||||
user = models.ForeignKey("db.User", on_delete=models.CASCADE, null=True, related_name="assets")
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, null=True, related_name="assets")
|
||||
draft_issue = models.ForeignKey("db.DraftIssue", on_delete=models.CASCADE, null=True, related_name="assets")
|
||||
project = models.ForeignKey("db.Project", on_delete=models.CASCADE, null=True, related_name="assets")
|
||||
issue = models.ForeignKey("db.Issue", on_delete=models.CASCADE, null=True, related_name="assets")
|
||||
comment = models.ForeignKey("db.IssueComment", on_delete=models.CASCADE, null=True, related_name="assets")
|
||||
page = models.ForeignKey("db.Page", on_delete=models.CASCADE, null=True, related_name="assets")
|
||||
entity_type = models.CharField(max_length=255, null=True, blank=True)
|
||||
entity_identifier = models.CharField(max_length=255, null=True, blank=True)
|
||||
is_deleted = models.BooleanField(default=False)
|
||||
|
|
@ -78,12 +64,8 @@ class FileAsset(BaseModel):
|
|||
ordering = ("-created_at",)
|
||||
indexes = [
|
||||
models.Index(fields=["entity_type"], name="asset_entity_type_idx"),
|
||||
models.Index(
|
||||
fields=["entity_identifier"], name="asset_entity_identifier_idx"
|
||||
),
|
||||
models.Index(
|
||||
fields=["entity_type", "entity_identifier"], name="asset_entity_idx"
|
||||
),
|
||||
models.Index(fields=["entity_identifier"], name="asset_entity_identifier_idx"),
|
||||
models.Index(fields=["entity_type", "entity_identifier"], name="asset_entity_idx"),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
|
|
@ -100,7 +82,7 @@ class FileAsset(BaseModel):
|
|||
return f"/api/assets/v2/static/{self.id}/"
|
||||
|
||||
if self.entity_type == self.EntityTypeContext.ISSUE_ATTACHMENT:
|
||||
return f"/api/assets/v2/workspaces/{self.workspace.slug}/projects/{self.project_id}/issues/{self.issue_id}/attachments/{self.id}/"
|
||||
return f"/api/assets/v2/workspaces/{self.workspace.slug}/projects/{self.project_id}/issues/{self.issue_id}/attachments/{self.id}/" # noqa: E501
|
||||
|
||||
if self.entity_type in [
|
||||
self.EntityTypeContext.ISSUE_DESCRIPTION,
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ from ..mixins import AuditModel
|
|||
|
||||
|
||||
class BaseModel(AuditModel):
|
||||
id = models.UUIDField(
|
||||
default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True
|
||||
)
|
||||
id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
|
|
|||
|
|
@ -102,12 +102,8 @@ class CycleIssue(ProjectBaseModel):
|
|||
Cycle Issues
|
||||
"""
|
||||
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", on_delete=models.CASCADE, related_name="issue_cycle"
|
||||
)
|
||||
cycle = models.ForeignKey(
|
||||
Cycle, on_delete=models.CASCADE, related_name="issue_cycle"
|
||||
)
|
||||
issue = models.ForeignKey("db.Issue", on_delete=models.CASCADE, related_name="issue_cycle")
|
||||
cycle = models.ForeignKey(Cycle, on_delete=models.CASCADE, related_name="issue_cycle")
|
||||
|
||||
class Meta:
|
||||
unique_together = ["issue", "cycle", "deleted_at"]
|
||||
|
|
@ -128,9 +124,7 @@ class CycleIssue(ProjectBaseModel):
|
|||
|
||||
|
||||
class CycleUserProperties(ProjectBaseModel):
|
||||
cycle = models.ForeignKey(
|
||||
"db.Cycle", on_delete=models.CASCADE, related_name="cycle_user_properties"
|
||||
)
|
||||
cycle = models.ForeignKey("db.Cycle", on_delete=models.CASCADE, related_name="cycle_user_properties")
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
|
|
|
|||
|
|
@ -25,14 +25,10 @@ class DeployBoard(WorkspaceBaseModel):
|
|||
|
||||
entity_identifier = models.UUIDField(null=True)
|
||||
entity_name = models.CharField(max_length=30, null=True, blank=True)
|
||||
anchor = models.CharField(
|
||||
max_length=255, default=get_anchor, unique=True, db_index=True
|
||||
)
|
||||
anchor = models.CharField(max_length=255, default=get_anchor, unique=True, db_index=True)
|
||||
is_comments_enabled = models.BooleanField(default=False)
|
||||
is_reactions_enabled = models.BooleanField(default=False)
|
||||
intake = models.ForeignKey(
|
||||
"db.Intake", related_name="publish_intake", on_delete=models.SET_NULL, null=True
|
||||
)
|
||||
intake = models.ForeignKey("db.Intake", related_name="publish_intake", on_delete=models.SET_NULL, null=True)
|
||||
is_votes_enabled = models.BooleanField(default=False)
|
||||
view_props = models.JSONField(default=dict)
|
||||
is_activity_enabled = models.BooleanField(default=True)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ from .workspace import WorkspaceBaseModel
|
|||
|
||||
|
||||
class Description(WorkspaceBaseModel):
|
||||
|
||||
|
||||
description_json = models.JSONField(default=dict, blank=True)
|
||||
description_html = models.TextField(blank=True, default="<p></p>")
|
||||
description_binary = models.BinaryField(null=True)
|
||||
|
|
@ -32,9 +30,7 @@ class DescriptionVersion(WorkspaceBaseModel):
|
|||
DescriptionVersion is a model used to store historical versions of a Description.
|
||||
"""
|
||||
|
||||
description = models.ForeignKey(
|
||||
"db.Description", on_delete=models.CASCADE, related_name="versions"
|
||||
)
|
||||
description = models.ForeignKey("db.Description", on_delete=models.CASCADE, related_name="versions")
|
||||
description_json = models.JSONField(default=dict, blank=True)
|
||||
description_html = models.TextField(blank=True, default="<p></p>")
|
||||
description_binary = models.BinaryField(null=True)
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ class Device(BaseModel):
|
|||
WEB = "WEB", "Web"
|
||||
DESKTOP = "DESKTOP", "Desktop"
|
||||
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="devices"
|
||||
)
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="devices")
|
||||
device_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
device_type = models.CharField(max_length=255, choices=DeviceType.choices)
|
||||
push_token = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
|
@ -26,12 +24,8 @@ class Device(BaseModel):
|
|||
|
||||
|
||||
class DeviceSession(BaseModel):
|
||||
device = models.ForeignKey(
|
||||
Device, on_delete=models.CASCADE, related_name="sessions"
|
||||
)
|
||||
session = models.ForeignKey(
|
||||
"db.Session", on_delete=models.CASCADE, related_name="device_sessions"
|
||||
)
|
||||
device = models.ForeignKey(Device, on_delete=models.CASCADE, related_name="sessions")
|
||||
session = models.ForeignKey("db.Session", on_delete=models.CASCADE, related_name="device_sessions")
|
||||
is_active = models.BooleanField(default=True)
|
||||
user_agent = models.CharField(max_length=255, null=True, blank=True)
|
||||
ip_address = models.GenericIPAddressField(null=True, blank=True)
|
||||
|
|
|
|||
|
|
@ -38,9 +38,7 @@ class DraftIssue(WorkspaceBaseModel):
|
|||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
name = models.CharField(
|
||||
max_length=255, verbose_name="Issue Name", blank=True, null=True
|
||||
)
|
||||
name = models.CharField(max_length=255, verbose_name="Issue Name", blank=True, null=True)
|
||||
description = models.JSONField(blank=True, default=dict)
|
||||
description_html = models.TextField(blank=True, default="<p></p>")
|
||||
description_stripped = models.TextField(blank=True, null=True)
|
||||
|
|
@ -60,9 +58,7 @@ class DraftIssue(WorkspaceBaseModel):
|
|||
through="DraftIssueAssignee",
|
||||
through_fields=("draft_issue", "assignee"),
|
||||
)
|
||||
labels = models.ManyToManyField(
|
||||
"db.Label", blank=True, related_name="draft_labels", through="DraftIssueLabel"
|
||||
)
|
||||
labels = models.ManyToManyField("db.Label", blank=True, related_name="draft_labels", through="DraftIssueLabel")
|
||||
sort_order = models.FloatField(default=65535)
|
||||
completed_at = models.DateTimeField(null=True)
|
||||
external_source = models.CharField(max_length=255, null=True, blank=True)
|
||||
|
|
@ -90,9 +86,7 @@ class DraftIssue(WorkspaceBaseModel):
|
|||
~models.Q(is_triage=True), project=self.project, default=True
|
||||
).first()
|
||||
if default_state is None:
|
||||
random_state = State.objects.filter(
|
||||
~models.Q(is_triage=True), project=self.project
|
||||
).first()
|
||||
random_state = State.objects.filter(~models.Q(is_triage=True), project=self.project).first()
|
||||
self.state = random_state
|
||||
else:
|
||||
self.state = default_state
|
||||
|
|
@ -116,9 +110,9 @@ class DraftIssue(WorkspaceBaseModel):
|
|||
if (self.description_html == "" or self.description_html is None)
|
||||
else strip_tags(self.description_html)
|
||||
)
|
||||
largest_sort_order = DraftIssue.objects.filter(
|
||||
project=self.project, state=self.state
|
||||
).aggregate(largest=models.Max("sort_order"))["largest"]
|
||||
largest_sort_order = DraftIssue.objects.filter(project=self.project, state=self.state).aggregate(
|
||||
largest=models.Max("sort_order")
|
||||
)["largest"]
|
||||
if largest_sort_order is not None:
|
||||
self.sort_order = largest_sort_order + 10000
|
||||
|
||||
|
|
@ -139,9 +133,7 @@ class DraftIssue(WorkspaceBaseModel):
|
|||
|
||||
|
||||
class DraftIssueAssignee(WorkspaceBaseModel):
|
||||
draft_issue = models.ForeignKey(
|
||||
DraftIssue, on_delete=models.CASCADE, related_name="draft_issue_assignee"
|
||||
)
|
||||
draft_issue = models.ForeignKey(DraftIssue, on_delete=models.CASCADE, related_name="draft_issue_assignee")
|
||||
assignee = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
|
|
@ -167,12 +159,8 @@ class DraftIssueAssignee(WorkspaceBaseModel):
|
|||
|
||||
|
||||
class DraftIssueLabel(WorkspaceBaseModel):
|
||||
draft_issue = models.ForeignKey(
|
||||
"db.DraftIssue", on_delete=models.CASCADE, related_name="draft_label_issue"
|
||||
)
|
||||
label = models.ForeignKey(
|
||||
"db.Label", on_delete=models.CASCADE, related_name="draft_label_issue"
|
||||
)
|
||||
draft_issue = models.ForeignKey("db.DraftIssue", on_delete=models.CASCADE, related_name="draft_label_issue")
|
||||
label = models.ForeignKey("db.Label", on_delete=models.CASCADE, related_name="draft_label_issue")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Draft Issue Label"
|
||||
|
|
@ -185,12 +173,8 @@ class DraftIssueLabel(WorkspaceBaseModel):
|
|||
|
||||
|
||||
class DraftIssueModule(WorkspaceBaseModel):
|
||||
module = models.ForeignKey(
|
||||
"db.Module", on_delete=models.CASCADE, related_name="draft_issue_module"
|
||||
)
|
||||
draft_issue = models.ForeignKey(
|
||||
"db.DraftIssue", on_delete=models.CASCADE, related_name="draft_issue_module"
|
||||
)
|
||||
module = models.ForeignKey("db.Module", on_delete=models.CASCADE, related_name="draft_issue_module")
|
||||
draft_issue = models.ForeignKey("db.DraftIssue", on_delete=models.CASCADE, related_name="draft_issue_module")
|
||||
|
||||
class Meta:
|
||||
unique_together = ["draft_issue", "module", "deleted_at"]
|
||||
|
|
@ -215,12 +199,8 @@ class DraftIssueCycle(WorkspaceBaseModel):
|
|||
Draft Issue Cycles
|
||||
"""
|
||||
|
||||
draft_issue = models.ForeignKey(
|
||||
"db.DraftIssue", on_delete=models.CASCADE, related_name="draft_issue_cycle"
|
||||
)
|
||||
cycle = models.ForeignKey(
|
||||
"db.Cycle", on_delete=models.CASCADE, related_name="draft_issue_cycle"
|
||||
)
|
||||
draft_issue = models.ForeignKey("db.DraftIssue", on_delete=models.CASCADE, related_name="draft_issue_cycle")
|
||||
cycle = models.ForeignKey("db.Cycle", on_delete=models.CASCADE, related_name="draft_issue_cycle")
|
||||
|
||||
class Meta:
|
||||
unique_together = ["draft_issue", "cycle", "deleted_at"]
|
||||
|
|
|
|||
|
|
@ -33,12 +33,8 @@ class Estimate(ProjectBaseModel):
|
|||
|
||||
|
||||
class EstimatePoint(ProjectBaseModel):
|
||||
estimate = models.ForeignKey(
|
||||
"db.Estimate", on_delete=models.CASCADE, related_name="points"
|
||||
)
|
||||
key = models.IntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
)
|
||||
estimate = models.ForeignKey("db.Estimate", on_delete=models.CASCADE, related_name="points")
|
||||
key = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(12)])
|
||||
description = models.TextField(blank=True)
|
||||
value = models.CharField(max_length=255)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ def generate_token():
|
|||
|
||||
|
||||
class ExporterHistory(BaseModel):
|
||||
name = models.CharField(
|
||||
max_length=255, verbose_name="Exporter Name", null=True, blank=True
|
||||
)
|
||||
name = models.CharField(max_length=255, verbose_name="Exporter Name", null=True, blank=True)
|
||||
type = models.CharField(
|
||||
max_length=50,
|
||||
default="issue_exports",
|
||||
|
|
@ -29,13 +27,9 @@ class ExporterHistory(BaseModel):
|
|||
("issue_worklogs", "Issue Worklogs"),
|
||||
),
|
||||
)
|
||||
workspace = models.ForeignKey(
|
||||
"db.WorkSpace", on_delete=models.CASCADE, related_name="workspace_exporters"
|
||||
)
|
||||
workspace = models.ForeignKey("db.WorkSpace", on_delete=models.CASCADE, related_name="workspace_exporters")
|
||||
project = ArrayField(models.UUIDField(default=uuid.uuid4), blank=True, null=True)
|
||||
provider = models.CharField(
|
||||
max_length=50, choices=(("json", "json"), ("csv", "csv"), ("xlsx", "xlsx"))
|
||||
)
|
||||
provider = models.CharField(max_length=50, choices=(("json", "json"), ("csv", "csv"), ("xlsx", "xlsx")))
|
||||
status = models.CharField(
|
||||
max_length=50,
|
||||
choices=(
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ class UserFavorite(WorkspaceBaseModel):
|
|||
UserFavorite (model): To store all the favorites of the user
|
||||
"""
|
||||
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="favorites"
|
||||
)
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="favorites")
|
||||
entity_type = models.CharField(max_length=100)
|
||||
entity_identifier = models.UUIDField(null=True, blank=True)
|
||||
name = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
|
@ -43,24 +41,20 @@ class UserFavorite(WorkspaceBaseModel):
|
|||
ordering = ("-created_at",)
|
||||
indexes = [
|
||||
models.Index(fields=["entity_type"], name="fav_entity_type_idx"),
|
||||
models.Index(
|
||||
fields=["entity_identifier"], name="fav_entity_identifier_idx"
|
||||
),
|
||||
models.Index(
|
||||
fields=["entity_type", "entity_identifier"], name="fav_entity_idx"
|
||||
),
|
||||
models.Index(fields=["entity_identifier"], name="fav_entity_identifier_idx"),
|
||||
models.Index(fields=["entity_type", "entity_identifier"], name="fav_entity_idx"),
|
||||
]
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self._state.adding:
|
||||
if self.project:
|
||||
largest_sequence = UserFavorite.objects.filter(
|
||||
workspace=self.project.workspace
|
||||
).aggregate(largest=models.Max("sequence"))["largest"]
|
||||
largest_sequence = UserFavorite.objects.filter(workspace=self.project.workspace).aggregate(
|
||||
largest=models.Max("sequence")
|
||||
)["largest"]
|
||||
else:
|
||||
largest_sequence = UserFavorite.objects.filter(
|
||||
workspace=self.workspace
|
||||
).aggregate(largest=models.Max("sequence"))["largest"]
|
||||
largest_sequence = UserFavorite.objects.filter(workspace=self.workspace).aggregate(
|
||||
largest=models.Max("sequence")
|
||||
)["largest"]
|
||||
if largest_sequence is not None:
|
||||
self.sequence = largest_sequence + 10000
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,7 @@ from .project import ProjectBaseModel
|
|||
|
||||
|
||||
class Importer(ProjectBaseModel):
|
||||
service = models.CharField(
|
||||
max_length=50, choices=(("github", "GitHub"), ("jira", "Jira"))
|
||||
)
|
||||
service = models.CharField(max_length=50, choices=(("github", "GitHub"), ("jira", "Jira")))
|
||||
status = models.CharField(
|
||||
max_length=50,
|
||||
choices=(
|
||||
|
|
@ -20,15 +18,11 @@ class Importer(ProjectBaseModel):
|
|||
),
|
||||
default="queued",
|
||||
)
|
||||
initiated_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="imports"
|
||||
)
|
||||
initiated_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="imports")
|
||||
metadata = models.JSONField(default=dict)
|
||||
config = models.JSONField(default=dict)
|
||||
data = models.JSONField(default=dict)
|
||||
token = models.ForeignKey(
|
||||
"db.APIToken", on_delete=models.CASCADE, related_name="importer"
|
||||
)
|
||||
token = models.ForeignKey("db.APIToken", on_delete=models.CASCADE, related_name="importer")
|
||||
imported_data = models.JSONField(null=True)
|
||||
|
||||
class Meta:
|
||||
|
|
|
|||
|
|
@ -44,12 +44,8 @@ class IntakeIssueStatus(models.IntegerChoices):
|
|||
|
||||
|
||||
class IntakeIssue(ProjectBaseModel):
|
||||
intake = models.ForeignKey(
|
||||
"db.Intake", related_name="issue_intake", on_delete=models.CASCADE
|
||||
)
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", related_name="issue_intake", on_delete=models.CASCADE
|
||||
)
|
||||
intake = models.ForeignKey("db.Intake", related_name="issue_intake", on_delete=models.CASCADE)
|
||||
issue = models.ForeignKey("db.Issue", related_name="issue_intake", on_delete=models.CASCADE)
|
||||
status = models.IntegerField(
|
||||
choices=(
|
||||
(-2, "Pending"),
|
||||
|
|
|
|||
|
|
@ -10,14 +10,10 @@ from plane.db.mixins import AuditModel
|
|||
|
||||
|
||||
class Integration(AuditModel):
|
||||
id = models.UUIDField(
|
||||
default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True
|
||||
)
|
||||
id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True)
|
||||
title = models.CharField(max_length=400)
|
||||
provider = models.CharField(max_length=400, unique=True)
|
||||
network = models.PositiveIntegerField(
|
||||
default=1, choices=((1, "Private"), (2, "Public"))
|
||||
)
|
||||
network = models.PositiveIntegerField(default=1, choices=((1, "Private"), (2, "Public")))
|
||||
description = models.JSONField(default=dict)
|
||||
author = models.CharField(max_length=400, blank=True)
|
||||
webhook_url = models.TextField(blank=True)
|
||||
|
|
@ -39,19 +35,11 @@ class Integration(AuditModel):
|
|||
|
||||
|
||||
class WorkspaceIntegration(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", related_name="workspace_integrations", on_delete=models.CASCADE
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", related_name="workspace_integrations", on_delete=models.CASCADE)
|
||||
# Bot user
|
||||
actor = models.ForeignKey(
|
||||
"db.User", related_name="integrations", on_delete=models.CASCADE
|
||||
)
|
||||
integration = models.ForeignKey(
|
||||
"db.Integration", related_name="integrated_workspaces", on_delete=models.CASCADE
|
||||
)
|
||||
api_token = models.ForeignKey(
|
||||
"db.APIToken", related_name="integrations", on_delete=models.CASCADE
|
||||
)
|
||||
actor = models.ForeignKey("db.User", related_name="integrations", on_delete=models.CASCADE)
|
||||
integration = models.ForeignKey("db.Integration", related_name="integrated_workspaces", on_delete=models.CASCADE)
|
||||
api_token = models.ForeignKey("db.APIToken", related_name="integrations", on_delete=models.CASCADE)
|
||||
metadata = models.JSONField(default=dict)
|
||||
|
||||
config = models.JSONField(default=dict)
|
||||
|
|
|
|||
|
|
@ -26,20 +26,14 @@ class GithubRepository(ProjectBaseModel):
|
|||
|
||||
|
||||
class GithubRepositorySync(ProjectBaseModel):
|
||||
repository = models.OneToOneField(
|
||||
"db.GithubRepository", on_delete=models.CASCADE, related_name="syncs"
|
||||
)
|
||||
repository = models.OneToOneField("db.GithubRepository", on_delete=models.CASCADE, related_name="syncs")
|
||||
credentials = models.JSONField(default=dict)
|
||||
# Bot user
|
||||
actor = models.ForeignKey(
|
||||
"db.User", related_name="user_syncs", on_delete=models.CASCADE
|
||||
)
|
||||
actor = models.ForeignKey("db.User", related_name="user_syncs", on_delete=models.CASCADE)
|
||||
workspace_integration = models.ForeignKey(
|
||||
"db.WorkspaceIntegration", related_name="github_syncs", on_delete=models.CASCADE
|
||||
)
|
||||
label = models.ForeignKey(
|
||||
"db.Label", on_delete=models.SET_NULL, null=True, related_name="repo_syncs"
|
||||
)
|
||||
label = models.ForeignKey("db.Label", on_delete=models.SET_NULL, null=True, related_name="repo_syncs")
|
||||
|
||||
def __str__(self):
|
||||
"""Return the repo sync"""
|
||||
|
|
@ -57,12 +51,8 @@ class GithubIssueSync(ProjectBaseModel):
|
|||
repo_issue_id = models.BigIntegerField()
|
||||
github_issue_id = models.BigIntegerField()
|
||||
issue_url = models.URLField(blank=False)
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", related_name="github_syncs", on_delete=models.CASCADE
|
||||
)
|
||||
repository_sync = models.ForeignKey(
|
||||
"db.GithubRepositorySync", related_name="issue_syncs", on_delete=models.CASCADE
|
||||
)
|
||||
issue = models.ForeignKey("db.Issue", related_name="github_syncs", on_delete=models.CASCADE)
|
||||
repository_sync = models.ForeignKey("db.GithubRepositorySync", related_name="issue_syncs", on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
"""Return the github issue sync"""
|
||||
|
|
@ -78,12 +68,8 @@ class GithubIssueSync(ProjectBaseModel):
|
|||
|
||||
class GithubCommentSync(ProjectBaseModel):
|
||||
repo_comment_id = models.BigIntegerField()
|
||||
comment = models.ForeignKey(
|
||||
"db.IssueComment", related_name="comment_syncs", on_delete=models.CASCADE
|
||||
)
|
||||
issue_sync = models.ForeignKey(
|
||||
"db.GithubIssueSync", related_name="comment_syncs", on_delete=models.CASCADE
|
||||
)
|
||||
comment = models.ForeignKey("db.IssueComment", related_name="comment_syncs", on_delete=models.CASCADE)
|
||||
issue_sync = models.ForeignKey("db.GithubIssueSync", related_name="comment_syncs", on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
"""Return the github issue sync"""
|
||||
|
|
|
|||
|
|
@ -123,9 +123,7 @@ class Issue(ProjectBaseModel):
|
|||
blank=True,
|
||||
related_name="state_issue",
|
||||
)
|
||||
point = models.IntegerField(
|
||||
validators=[MinValueValidator(0), MaxValueValidator(12)], null=True, blank=True
|
||||
)
|
||||
point = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(12)], null=True, blank=True)
|
||||
estimate_point = models.ForeignKey(
|
||||
"db.EstimatePoint",
|
||||
on_delete=models.SET_NULL,
|
||||
|
|
@ -154,9 +152,7 @@ class Issue(ProjectBaseModel):
|
|||
through_fields=("issue", "assignee"),
|
||||
)
|
||||
sequence_id = models.IntegerField(default=1, verbose_name="Issue Sequence ID")
|
||||
labels = models.ManyToManyField(
|
||||
"db.Label", blank=True, related_name="labels", through="IssueLabel"
|
||||
)
|
||||
labels = models.ManyToManyField("db.Label", blank=True, related_name="labels", through="IssueLabel")
|
||||
sort_order = models.FloatField(default=65535)
|
||||
completed_at = models.DateTimeField(null=True)
|
||||
archived_at = models.DateField(null=True)
|
||||
|
|
@ -188,9 +184,7 @@ class Issue(ProjectBaseModel):
|
|||
~models.Q(is_triage=True), project=self.project, default=True
|
||||
).first()
|
||||
if default_state is None:
|
||||
random_state = State.objects.filter(
|
||||
~models.Q(is_triage=True), project=self.project
|
||||
).first()
|
||||
random_state = State.objects.filter(~models.Q(is_triage=True), project=self.project).first()
|
||||
self.state = random_state
|
||||
else:
|
||||
self.state = default_state
|
||||
|
|
@ -219,29 +213,25 @@ class Issue(ProjectBaseModel):
|
|||
|
||||
try:
|
||||
# Get the last sequence for the project
|
||||
last_sequence = IssueSequence.objects.filter(
|
||||
project=self.project
|
||||
).aggregate(largest=models.Max("sequence"))["largest"]
|
||||
last_sequence = IssueSequence.objects.filter(project=self.project).aggregate(
|
||||
largest=models.Max("sequence")
|
||||
)["largest"]
|
||||
self.sequence_id = last_sequence + 1 if last_sequence else 1
|
||||
# Strip the html tags using html parser
|
||||
self.description_stripped = (
|
||||
None
|
||||
if (
|
||||
self.description_html == "" or self.description_html is None
|
||||
)
|
||||
if (self.description_html == "" or self.description_html is None)
|
||||
else strip_tags(self.description_html)
|
||||
)
|
||||
largest_sort_order = Issue.objects.filter(
|
||||
project=self.project, state=self.state
|
||||
).aggregate(largest=models.Max("sort_order"))["largest"]
|
||||
largest_sort_order = Issue.objects.filter(project=self.project, state=self.state).aggregate(
|
||||
largest=models.Max("sort_order")
|
||||
)["largest"]
|
||||
if largest_sort_order is not None:
|
||||
self.sort_order = largest_sort_order + 10000
|
||||
|
||||
super(Issue, self).save(*args, **kwargs)
|
||||
|
||||
IssueSequence.objects.create(
|
||||
issue=self, sequence=self.sequence_id, project=self.project
|
||||
)
|
||||
IssueSequence.objects.create(issue=self, sequence=self.sequence_id, project=self.project)
|
||||
finally:
|
||||
# Release the lock
|
||||
with connection.cursor() as cursor:
|
||||
|
|
@ -261,12 +251,8 @@ class Issue(ProjectBaseModel):
|
|||
|
||||
|
||||
class IssueBlocker(ProjectBaseModel):
|
||||
block = models.ForeignKey(
|
||||
Issue, related_name="blocker_issues", on_delete=models.CASCADE
|
||||
)
|
||||
blocked_by = models.ForeignKey(
|
||||
Issue, related_name="blocked_issues", on_delete=models.CASCADE
|
||||
)
|
||||
block = models.ForeignKey(Issue, related_name="blocker_issues", on_delete=models.CASCADE)
|
||||
blocked_by = models.ForeignKey(Issue, related_name="blocked_issues", on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Issue Blocker"
|
||||
|
|
@ -288,12 +274,8 @@ class IssueRelationChoices(models.TextChoices):
|
|||
|
||||
|
||||
class IssueRelation(ProjectBaseModel):
|
||||
issue = models.ForeignKey(
|
||||
Issue, related_name="issue_relation", on_delete=models.CASCADE
|
||||
)
|
||||
related_issue = models.ForeignKey(
|
||||
Issue, related_name="issue_related", on_delete=models.CASCADE
|
||||
)
|
||||
issue = models.ForeignKey(Issue, related_name="issue_relation", on_delete=models.CASCADE)
|
||||
related_issue = models.ForeignKey(Issue, related_name="issue_related", on_delete=models.CASCADE)
|
||||
relation_type = models.CharField(
|
||||
max_length=20,
|
||||
verbose_name="Issue Relation Type",
|
||||
|
|
@ -319,12 +301,8 @@ class IssueRelation(ProjectBaseModel):
|
|||
|
||||
|
||||
class IssueMention(ProjectBaseModel):
|
||||
issue = models.ForeignKey(
|
||||
Issue, on_delete=models.CASCADE, related_name="issue_mention"
|
||||
)
|
||||
mention = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="issue_mention"
|
||||
)
|
||||
issue = models.ForeignKey(Issue, on_delete=models.CASCADE, related_name="issue_mention")
|
||||
mention = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="issue_mention")
|
||||
|
||||
class Meta:
|
||||
unique_together = ["issue", "mention", "deleted_at"]
|
||||
|
|
@ -345,9 +323,7 @@ class IssueMention(ProjectBaseModel):
|
|||
|
||||
|
||||
class IssueAssignee(ProjectBaseModel):
|
||||
issue = models.ForeignKey(
|
||||
Issue, on_delete=models.CASCADE, related_name="issue_assignee"
|
||||
)
|
||||
issue = models.ForeignKey(Issue, on_delete=models.CASCADE, related_name="issue_assignee")
|
||||
assignee = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
|
|
@ -375,9 +351,7 @@ class IssueAssignee(ProjectBaseModel):
|
|||
class IssueLink(ProjectBaseModel):
|
||||
title = models.CharField(max_length=255, null=True, blank=True)
|
||||
url = models.TextField()
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", on_delete=models.CASCADE, related_name="issue_link"
|
||||
)
|
||||
issue = models.ForeignKey("db.Issue", on_delete=models.CASCADE, related_name="issue_link")
|
||||
metadata = models.JSONField(default=dict)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -403,9 +377,7 @@ def file_size(value):
|
|||
class IssueAttachment(ProjectBaseModel):
|
||||
attributes = models.JSONField(default=dict)
|
||||
asset = models.FileField(upload_to=get_upload_path, validators=[file_size])
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", on_delete=models.CASCADE, related_name="issue_attachment"
|
||||
)
|
||||
issue = models.ForeignKey("db.Issue", on_delete=models.CASCADE, related_name="issue_attachment")
|
||||
external_source = models.CharField(max_length=255, null=True, blank=True)
|
||||
external_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
|
|
@ -420,13 +392,9 @@ class IssueAttachment(ProjectBaseModel):
|
|||
|
||||
|
||||
class IssueActivity(ProjectBaseModel):
|
||||
issue = models.ForeignKey(
|
||||
Issue, on_delete=models.SET_NULL, null=True, related_name="issue_activity"
|
||||
)
|
||||
issue = models.ForeignKey(Issue, on_delete=models.SET_NULL, null=True, related_name="issue_activity")
|
||||
verb = models.CharField(max_length=255, verbose_name="Action", default="created")
|
||||
field = models.CharField(
|
||||
max_length=255, verbose_name="Field Name", blank=True, null=True
|
||||
)
|
||||
field = models.CharField(max_length=255, verbose_name="Field Name", blank=True, null=True)
|
||||
old_value = models.TextField(verbose_name="Old Value", blank=True, null=True)
|
||||
new_value = models.TextField(verbose_name="New Value", blank=True, null=True)
|
||||
|
||||
|
|
@ -464,9 +432,7 @@ class IssueComment(ProjectBaseModel):
|
|||
comment_json = models.JSONField(blank=True, default=dict)
|
||||
comment_html = models.TextField(blank=True, default="<p></p>")
|
||||
attachments = ArrayField(models.URLField(), size=10, blank=True, default=list)
|
||||
issue = models.ForeignKey(
|
||||
Issue, on_delete=models.CASCADE, related_name="issue_comments"
|
||||
)
|
||||
issue = models.ForeignKey(Issue, on_delete=models.CASCADE, related_name="issue_comments")
|
||||
# System can also create comment
|
||||
actor = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
|
|
@ -484,9 +450,7 @@ class IssueComment(ProjectBaseModel):
|
|||
edited_at = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.comment_stripped = (
|
||||
strip_tags(self.comment_html) if self.comment_html != "" else ""
|
||||
)
|
||||
self.comment_stripped = strip_tags(self.comment_html) if self.comment_html != "" else ""
|
||||
return super(IssueComment, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -531,12 +495,8 @@ class IssueUserProperty(ProjectBaseModel):
|
|||
|
||||
|
||||
class IssueLabel(ProjectBaseModel):
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", on_delete=models.CASCADE, related_name="label_issue"
|
||||
)
|
||||
label = models.ForeignKey(
|
||||
"db.Label", on_delete=models.CASCADE, related_name="label_issue"
|
||||
)
|
||||
issue = models.ForeignKey("db.Issue", on_delete=models.CASCADE, related_name="label_issue")
|
||||
label = models.ForeignKey("db.Label", on_delete=models.CASCADE, related_name="label_issue")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Issue Label"
|
||||
|
|
@ -566,9 +526,7 @@ class IssueSequence(ProjectBaseModel):
|
|||
|
||||
|
||||
class IssueSubscriber(ProjectBaseModel):
|
||||
issue = models.ForeignKey(
|
||||
Issue, on_delete=models.CASCADE, related_name="issue_subscribers"
|
||||
)
|
||||
issue = models.ForeignKey(Issue, on_delete=models.CASCADE, related_name="issue_subscribers")
|
||||
subscriber = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
|
|
@ -599,9 +557,7 @@ class IssueReaction(ProjectBaseModel):
|
|||
on_delete=models.CASCADE,
|
||||
related_name="issue_reactions",
|
||||
)
|
||||
issue = models.ForeignKey(
|
||||
Issue, on_delete=models.CASCADE, related_name="issue_reactions"
|
||||
)
|
||||
issue = models.ForeignKey(Issue, on_delete=models.CASCADE, related_name="issue_reactions")
|
||||
reaction = models.TextField()
|
||||
|
||||
class Meta:
|
||||
|
|
@ -628,9 +584,7 @@ class CommentReaction(ProjectBaseModel):
|
|||
on_delete=models.CASCADE,
|
||||
related_name="comment_reactions",
|
||||
)
|
||||
comment = models.ForeignKey(
|
||||
IssueComment, on_delete=models.CASCADE, related_name="comment_reactions"
|
||||
)
|
||||
comment = models.ForeignKey(IssueComment, on_delete=models.CASCADE, related_name="comment_reactions")
|
||||
reaction = models.TextField()
|
||||
|
||||
class Meta:
|
||||
|
|
@ -653,9 +607,7 @@ class CommentReaction(ProjectBaseModel):
|
|||
|
||||
class IssueVote(ProjectBaseModel):
|
||||
issue = models.ForeignKey(Issue, on_delete=models.CASCADE, related_name="votes")
|
||||
actor = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="votes"
|
||||
)
|
||||
actor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="votes")
|
||||
vote = models.IntegerField(choices=((-1, "DOWNVOTE"), (1, "UPVOTE")), default=1)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -713,9 +665,7 @@ class IssueVersion(ProjectBaseModel):
|
|||
meta = models.JSONField(default=dict) # issue meta
|
||||
last_saved_at = models.DateTimeField(default=timezone.now)
|
||||
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", on_delete=models.CASCADE, related_name="versions"
|
||||
)
|
||||
issue = models.ForeignKey("db.Issue", on_delete=models.CASCADE, related_name="versions")
|
||||
activity = models.ForeignKey(
|
||||
"db.IssueActivity",
|
||||
on_delete=models.SET_NULL,
|
||||
|
|
@ -760,17 +710,9 @@ class IssueVersion(ProjectBaseModel):
|
|||
priority=issue.priority,
|
||||
start_date=issue.start_date,
|
||||
target_date=issue.target_date,
|
||||
assignees=list(
|
||||
IssueAssignee.objects.filter(issue=issue).values_list(
|
||||
"assignee_id", flat=True
|
||||
)
|
||||
),
|
||||
assignees=list(IssueAssignee.objects.filter(issue=issue).values_list("assignee_id", flat=True)),
|
||||
sequence_id=issue.sequence_id,
|
||||
labels=list(
|
||||
IssueLabel.objects.filter(issue=issue).values_list(
|
||||
"label_id", flat=True
|
||||
)
|
||||
),
|
||||
labels=list(IssueLabel.objects.filter(issue=issue).values_list("label_id", flat=True)),
|
||||
sort_order=issue.sort_order,
|
||||
completed_at=issue.completed_at,
|
||||
archived_at=issue.archived_at,
|
||||
|
|
@ -779,9 +721,7 @@ class IssueVersion(ProjectBaseModel):
|
|||
external_id=issue.external_id,
|
||||
type=issue.type_id,
|
||||
cycle=cycle_issue.cycle_id if cycle_issue else None,
|
||||
modules=list(
|
||||
Module.objects.filter(issue=issue).values_list("id", flat=True)
|
||||
),
|
||||
modules=list(Module.objects.filter(issue=issue).values_list("id", flat=True)),
|
||||
properties={},
|
||||
meta={},
|
||||
last_saved_at=timezone.now(),
|
||||
|
|
@ -794,9 +734,7 @@ class IssueVersion(ProjectBaseModel):
|
|||
|
||||
|
||||
class IssueDescriptionVersion(ProjectBaseModel):
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", on_delete=models.CASCADE, related_name="description_versions"
|
||||
)
|
||||
issue = models.ForeignKey("db.Issue", on_delete=models.CASCADE, related_name="description_versions")
|
||||
description_binary = models.BinaryField(null=True)
|
||||
description_html = models.TextField(blank=True, default="<p></p>")
|
||||
description_stripped = models.TextField(blank=True, null=True)
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ from .base import BaseModel
|
|||
|
||||
|
||||
class IssueType(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", related_name="issue_types", on_delete=models.CASCADE
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", related_name="issue_types", on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField(blank=True)
|
||||
logo_props = models.JSONField(default=dict)
|
||||
|
|
@ -31,9 +29,7 @@ class IssueType(BaseModel):
|
|||
|
||||
|
||||
class ProjectIssueType(ProjectBaseModel):
|
||||
issue_type = models.ForeignKey(
|
||||
"db.IssueType", related_name="project_issue_types", on_delete=models.CASCADE
|
||||
)
|
||||
issue_type = models.ForeignKey("db.IssueType", related_name="project_issue_types", on_delete=models.CASCADE)
|
||||
level = models.PositiveIntegerField(default=0)
|
||||
is_default = models.BooleanField(default=False)
|
||||
|
||||
|
|
|
|||
|
|
@ -42,9 +42,7 @@ class Label(WorkspaceBaseModel):
|
|||
def save(self, *args, **kwargs):
|
||||
if self._state.adding:
|
||||
# Get the maximum sequence value from the database
|
||||
last_id = Label.objects.filter(project=self.project).aggregate(
|
||||
largest=models.Max("sort_order")
|
||||
)["largest"]
|
||||
last_id = Label.objects.filter(project=self.project).aggregate(largest=models.Max("sort_order"))["largest"]
|
||||
# if last_id is not None
|
||||
if last_id is not None:
|
||||
self.sort_order = last_id + 10000
|
||||
|
|
|
|||
|
|
@ -63,12 +63,8 @@ class ModuleStatus(models.TextChoices):
|
|||
class Module(ProjectBaseModel):
|
||||
name = models.CharField(max_length=255, verbose_name="Module Name")
|
||||
description = models.TextField(verbose_name="Module Description", blank=True)
|
||||
description_text = models.JSONField(
|
||||
verbose_name="Module Description RT", blank=True, null=True
|
||||
)
|
||||
description_html = models.JSONField(
|
||||
verbose_name="Module Description HTML", blank=True, null=True
|
||||
)
|
||||
description_text = models.JSONField(verbose_name="Module Description RT", blank=True, null=True)
|
||||
description_html = models.JSONField(verbose_name="Module Description HTML", blank=True, null=True)
|
||||
start_date = models.DateField(null=True)
|
||||
target_date = models.DateField(null=True)
|
||||
status = models.CharField(
|
||||
|
|
@ -83,9 +79,7 @@ class Module(ProjectBaseModel):
|
|||
default="planned",
|
||||
max_length=20,
|
||||
)
|
||||
lead = models.ForeignKey(
|
||||
"db.User", on_delete=models.SET_NULL, related_name="module_leads", null=True
|
||||
)
|
||||
lead = models.ForeignKey("db.User", on_delete=models.SET_NULL, related_name="module_leads", null=True)
|
||||
members = models.ManyToManyField(
|
||||
settings.AUTH_USER_MODEL,
|
||||
blank=True,
|
||||
|
|
@ -152,12 +146,8 @@ class ModuleMember(ProjectBaseModel):
|
|||
|
||||
|
||||
class ModuleIssue(ProjectBaseModel):
|
||||
module = models.ForeignKey(
|
||||
"db.Module", on_delete=models.CASCADE, related_name="issue_module"
|
||||
)
|
||||
issue = models.ForeignKey(
|
||||
"db.Issue", on_delete=models.CASCADE, related_name="issue_module"
|
||||
)
|
||||
module = models.ForeignKey("db.Module", on_delete=models.CASCADE, related_name="issue_module")
|
||||
issue = models.ForeignKey("db.Issue", on_delete=models.CASCADE, related_name="issue_module")
|
||||
|
||||
class Meta:
|
||||
unique_together = ["issue", "module", "deleted_at"]
|
||||
|
|
@ -180,9 +170,7 @@ class ModuleIssue(ProjectBaseModel):
|
|||
class ModuleLink(ProjectBaseModel):
|
||||
title = models.CharField(max_length=255, blank=True, null=True)
|
||||
url = models.URLField()
|
||||
module = models.ForeignKey(
|
||||
Module, on_delete=models.CASCADE, related_name="link_module"
|
||||
)
|
||||
module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name="link_module")
|
||||
metadata = models.JSONField(default=dict)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -196,9 +184,7 @@ class ModuleLink(ProjectBaseModel):
|
|||
|
||||
|
||||
class ModuleUserProperties(ProjectBaseModel):
|
||||
module = models.ForeignKey(
|
||||
"db.Module", on_delete=models.CASCADE, related_name="module_user_properties"
|
||||
)
|
||||
module = models.ForeignKey("db.Module", on_delete=models.CASCADE, related_name="module_user_properties")
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
|
|
|
|||
|
|
@ -7,12 +7,8 @@ from .base import BaseModel
|
|||
|
||||
|
||||
class Notification(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", related_name="notifications", on_delete=models.CASCADE
|
||||
)
|
||||
project = models.ForeignKey(
|
||||
"db.Project", related_name="notifications", on_delete=models.CASCADE, null=True
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", related_name="notifications", on_delete=models.CASCADE)
|
||||
project = models.ForeignKey("db.Project", related_name="notifications", on_delete=models.CASCADE, null=True)
|
||||
data = models.JSONField(null=True)
|
||||
entity_identifier = models.UUIDField(null=True)
|
||||
entity_name = models.CharField(max_length=255)
|
||||
|
|
@ -27,9 +23,7 @@ class Notification(BaseModel):
|
|||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
)
|
||||
receiver = models.ForeignKey(
|
||||
"db.User", related_name="received_notifications", on_delete=models.CASCADE
|
||||
)
|
||||
receiver = models.ForeignKey("db.User", related_name="received_notifications", on_delete=models.CASCADE)
|
||||
read_at = models.DateTimeField(null=True)
|
||||
snoozed_till = models.DateTimeField(null=True)
|
||||
archived_at = models.DateTimeField(null=True)
|
||||
|
|
@ -40,9 +34,7 @@ class Notification(BaseModel):
|
|||
db_table = "notifications"
|
||||
ordering = ("-created_at",)
|
||||
indexes = [
|
||||
models.Index(
|
||||
fields=["entity_identifier"], name="notif_entity_identifier_idx"
|
||||
),
|
||||
models.Index(fields=["entity_identifier"], name="notif_entity_identifier_idx"),
|
||||
models.Index(fields=["entity_name"], name="notif_entity_name_idx"),
|
||||
models.Index(fields=["read_at"], name="notif_read_at_idx"),
|
||||
models.Index(fields=["receiver", "read_at"], name="notif_entity_idx"),
|
||||
|
|
|
|||
|
|
@ -23,24 +23,16 @@ class Page(BaseModel):
|
|||
|
||||
ACCESS_CHOICES = ((PRIVATE_ACCESS, "Private"), (PUBLIC_ACCESS, "Public"))
|
||||
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="pages"
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="pages")
|
||||
name = models.TextField(blank=True)
|
||||
description = models.JSONField(default=dict, blank=True)
|
||||
description_binary = models.BinaryField(null=True)
|
||||
description_html = models.TextField(blank=True, default="<p></p>")
|
||||
description_stripped = models.TextField(blank=True, null=True)
|
||||
owned_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="pages"
|
||||
)
|
||||
access = models.PositiveSmallIntegerField(
|
||||
choices=((0, "Public"), (1, "Private")), default=0
|
||||
)
|
||||
owned_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="pages")
|
||||
access = models.PositiveSmallIntegerField(choices=((0, "Public"), (1, "Private")), default=0)
|
||||
color = models.CharField(max_length=255, blank=True)
|
||||
labels = models.ManyToManyField(
|
||||
"db.Label", blank=True, related_name="pages", through="db.PageLabel"
|
||||
)
|
||||
labels = models.ManyToManyField("db.Label", blank=True, related_name="pages", through="db.PageLabel")
|
||||
parent = models.ForeignKey(
|
||||
"self",
|
||||
on_delete=models.CASCADE,
|
||||
|
|
@ -53,9 +45,7 @@ class Page(BaseModel):
|
|||
view_props = models.JSONField(default=get_view_props)
|
||||
logo_props = models.JSONField(default=dict)
|
||||
is_global = models.BooleanField(default=False)
|
||||
projects = models.ManyToManyField(
|
||||
"db.Project", related_name="pages", through="db.ProjectPage"
|
||||
)
|
||||
projects = models.ManyToManyField("db.Project", related_name="pages", through="db.ProjectPage")
|
||||
moved_to_page = models.UUIDField(null=True, blank=True)
|
||||
moved_to_project = models.UUIDField(null=True, blank=True)
|
||||
sort_order = models.FloatField(default=DEFAULT_SORT_ORDER)
|
||||
|
|
@ -102,12 +92,8 @@ class PageLog(BaseModel):
|
|||
page = models.ForeignKey(Page, related_name="page_log", on_delete=models.CASCADE)
|
||||
entity_identifier = models.UUIDField(null=True, blank=True)
|
||||
entity_name = models.CharField(max_length=30, verbose_name="Transaction Type")
|
||||
entity_type = models.CharField(
|
||||
max_length=30, verbose_name="Entity Type", null=True, blank=True
|
||||
)
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="workspace_page_log"
|
||||
)
|
||||
entity_type = models.CharField(max_length=30, verbose_name="Entity Type", null=True, blank=True)
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="workspace_page_log")
|
||||
|
||||
class Meta:
|
||||
unique_together = ["page", "transaction"]
|
||||
|
|
@ -119,12 +105,8 @@ class PageLog(BaseModel):
|
|||
models.Index(fields=["entity_type"], name="pagelog_entity_type_idx"),
|
||||
models.Index(fields=["entity_identifier"], name="pagelog_entity_id_idx"),
|
||||
models.Index(fields=["entity_name"], name="pagelog_entity_name_idx"),
|
||||
models.Index(
|
||||
fields=["entity_type", "entity_identifier"], name="pagelog_type_id_idx"
|
||||
),
|
||||
models.Index(
|
||||
fields=["entity_name", "entity_identifier"], name="pagelog_name_id_idx"
|
||||
),
|
||||
models.Index(fields=["entity_type", "entity_identifier"], name="pagelog_type_id_idx"),
|
||||
models.Index(fields=["entity_name", "entity_identifier"], name="pagelog_name_id_idx"),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
|
|
@ -132,15 +114,9 @@ class PageLog(BaseModel):
|
|||
|
||||
|
||||
class PageLabel(BaseModel):
|
||||
label = models.ForeignKey(
|
||||
"db.Label", on_delete=models.CASCADE, related_name="page_labels"
|
||||
)
|
||||
page = models.ForeignKey(
|
||||
"db.Page", on_delete=models.CASCADE, related_name="page_labels"
|
||||
)
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="workspace_page_label"
|
||||
)
|
||||
label = models.ForeignKey("db.Label", on_delete=models.CASCADE, related_name="page_labels")
|
||||
page = models.ForeignKey("db.Page", on_delete=models.CASCADE, related_name="page_labels")
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="workspace_page_label")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Page Label"
|
||||
|
|
@ -153,15 +129,9 @@ class PageLabel(BaseModel):
|
|||
|
||||
|
||||
class ProjectPage(BaseModel):
|
||||
project = models.ForeignKey(
|
||||
"db.Project", on_delete=models.CASCADE, related_name="project_pages"
|
||||
)
|
||||
page = models.ForeignKey(
|
||||
"db.Page", on_delete=models.CASCADE, related_name="project_pages"
|
||||
)
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="project_pages"
|
||||
)
|
||||
project = models.ForeignKey("db.Project", on_delete=models.CASCADE, related_name="project_pages")
|
||||
page = models.ForeignKey("db.Page", on_delete=models.CASCADE, related_name="project_pages")
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="project_pages")
|
||||
|
||||
class Meta:
|
||||
unique_together = ["project", "page", "deleted_at"]
|
||||
|
|
@ -182,16 +152,10 @@ class ProjectPage(BaseModel):
|
|||
|
||||
|
||||
class PageVersion(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="page_versions"
|
||||
)
|
||||
page = models.ForeignKey(
|
||||
"db.Page", on_delete=models.CASCADE, related_name="page_versions"
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="page_versions")
|
||||
page = models.ForeignKey("db.Page", on_delete=models.CASCADE, related_name="page_versions")
|
||||
last_saved_at = models.DateTimeField(default=timezone.now)
|
||||
owned_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="page_versions"
|
||||
)
|
||||
owned_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="page_versions")
|
||||
description_binary = models.BinaryField(null=True)
|
||||
description_html = models.TextField(blank=True, default="<p></p>")
|
||||
description_stripped = models.TextField(blank=True, null=True)
|
||||
|
|
|
|||
|
|
@ -66,19 +66,11 @@ class Project(BaseModel):
|
|||
NETWORK_CHOICES = ((0, "Secret"), (2, "Public"))
|
||||
name = models.CharField(max_length=255, verbose_name="Project Name")
|
||||
description = models.TextField(verbose_name="Project Description", blank=True)
|
||||
description_text = models.JSONField(
|
||||
verbose_name="Project Description RT", blank=True, null=True
|
||||
)
|
||||
description_html = models.JSONField(
|
||||
verbose_name="Project Description HTML", blank=True, null=True
|
||||
)
|
||||
description_text = models.JSONField(verbose_name="Project Description RT", blank=True, null=True)
|
||||
description_html = models.JSONField(verbose_name="Project Description HTML", blank=True, null=True)
|
||||
network = models.PositiveSmallIntegerField(default=2, choices=NETWORK_CHOICES)
|
||||
workspace = models.ForeignKey(
|
||||
"db.WorkSpace", on_delete=models.CASCADE, related_name="workspace_project"
|
||||
)
|
||||
identifier = models.CharField(
|
||||
max_length=12, verbose_name="Project Identifier", db_index=True
|
||||
)
|
||||
workspace = models.ForeignKey("db.WorkSpace", on_delete=models.CASCADE, related_name="workspace_project")
|
||||
identifier = models.CharField(max_length=12, verbose_name="Project Identifier", db_index=True)
|
||||
default_assignee = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
|
|
@ -111,19 +103,11 @@ class Project(BaseModel):
|
|||
blank=True,
|
||||
related_name="project_cover_image",
|
||||
)
|
||||
estimate = models.ForeignKey(
|
||||
"db.Estimate", on_delete=models.SET_NULL, related_name="projects", null=True
|
||||
)
|
||||
archive_in = models.IntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
)
|
||||
close_in = models.IntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
)
|
||||
estimate = models.ForeignKey("db.Estimate", on_delete=models.SET_NULL, related_name="projects", null=True)
|
||||
archive_in = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(12)])
|
||||
close_in = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(12)])
|
||||
logo_props = models.JSONField(default=dict)
|
||||
default_state = models.ForeignKey(
|
||||
"db.State", on_delete=models.SET_NULL, null=True, related_name="default_state"
|
||||
)
|
||||
default_state = models.ForeignKey("db.State", on_delete=models.SET_NULL, null=True, related_name="default_state")
|
||||
archived_at = models.DateTimeField(null=True)
|
||||
# timezone
|
||||
TIMEZONE_CHOICES = tuple(zip(pytz.common_timezones, pytz.common_timezones))
|
||||
|
|
@ -176,12 +160,8 @@ class Project(BaseModel):
|
|||
|
||||
|
||||
class ProjectBaseModel(BaseModel):
|
||||
project = models.ForeignKey(
|
||||
Project, on_delete=models.CASCADE, related_name="project_%(class)s"
|
||||
)
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="workspace_%(class)s"
|
||||
)
|
||||
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="project_%(class)s")
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="workspace_%(class)s")
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
|
@ -258,12 +238,8 @@ class ProjectMember(ProjectBaseModel):
|
|||
|
||||
# TODO: Remove workspace relation later
|
||||
class ProjectIdentifier(AuditModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", models.CASCADE, related_name="project_identifiers", null=True
|
||||
)
|
||||
project = models.OneToOneField(
|
||||
Project, on_delete=models.CASCADE, related_name="project_identifier"
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", models.CASCADE, related_name="project_identifiers", null=True)
|
||||
project = models.OneToOneField(Project, on_delete=models.CASCADE, related_name="project_identifier")
|
||||
name = models.CharField(max_length=12, db_index=True)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -298,14 +274,10 @@ def get_default_views():
|
|||
# DEPRECATED TODO:
|
||||
# used to get the old anchors for the project deploy boards
|
||||
class ProjectDeployBoard(ProjectBaseModel):
|
||||
anchor = models.CharField(
|
||||
max_length=255, default=get_anchor, unique=True, db_index=True
|
||||
)
|
||||
anchor = models.CharField(max_length=255, default=get_anchor, unique=True, db_index=True)
|
||||
comments = models.BooleanField(default=False)
|
||||
reactions = models.BooleanField(default=False)
|
||||
intake = models.ForeignKey(
|
||||
"db.Intake", related_name="board_intake", on_delete=models.SET_NULL, null=True
|
||||
)
|
||||
intake = models.ForeignKey("db.Intake", related_name="board_intake", on_delete=models.SET_NULL, null=True)
|
||||
votes = models.BooleanField(default=False)
|
||||
views = models.JSONField(default=get_default_views)
|
||||
|
||||
|
|
|
|||
|
|
@ -52,9 +52,7 @@ class State(ProjectBaseModel):
|
|||
self.slug = slugify(self.name)
|
||||
if self._state.adding:
|
||||
# Get the maximum sequence value from the database
|
||||
last_id = State.objects.filter(project=self.project).aggregate(
|
||||
largest=models.Max("sequence")
|
||||
)["largest"]
|
||||
last_id = State.objects.filter(project=self.project).aggregate(largest=models.Max("sequence"))["largest"]
|
||||
# if last_id is not None
|
||||
if last_id is not None:
|
||||
self.sequence = last_id + 15000
|
||||
|
|
|
|||
|
|
@ -21,12 +21,8 @@ class Sticky(BaseModel):
|
|||
color = models.CharField(max_length=255, blank=True, null=True)
|
||||
background_color = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="stickies"
|
||||
)
|
||||
owner = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="stickies"
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="stickies")
|
||||
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="stickies")
|
||||
sort_order = models.FloatField(default=65535)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -44,9 +40,9 @@ class Sticky(BaseModel):
|
|||
)
|
||||
if self._state.adding:
|
||||
# Get the maximum sequence value from the database
|
||||
last_id = Sticky.objects.filter(workspace=self.workspace).aggregate(
|
||||
largest=models.Max("sort_order")
|
||||
)["largest"]
|
||||
last_id = Sticky.objects.filter(workspace=self.workspace).aggregate(largest=models.Max("sort_order"))[
|
||||
"largest"
|
||||
]
|
||||
# if last_id is not None
|
||||
if last_id is not None:
|
||||
self.sort_order = last_id + 10000
|
||||
|
|
|
|||
|
|
@ -36,9 +36,7 @@ def get_mobile_default_onboarding():
|
|||
|
||||
|
||||
class User(AbstractBaseUser, PermissionsMixin):
|
||||
id = models.UUIDField(
|
||||
default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True
|
||||
)
|
||||
id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True)
|
||||
username = models.CharField(max_length=128, unique=True)
|
||||
# user fields
|
||||
mobile_number = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
|
@ -97,15 +95,11 @@ class User(AbstractBaseUser, PermissionsMixin):
|
|||
# my_issues_prop = models.JSONField(null=True)
|
||||
|
||||
is_bot = models.BooleanField(default=False)
|
||||
bot_type = models.CharField(
|
||||
max_length=30, verbose_name="Bot Type", blank=True, null=True
|
||||
)
|
||||
bot_type = models.CharField(max_length=30, verbose_name="Bot Type", blank=True, null=True)
|
||||
|
||||
# timezone
|
||||
USER_TIMEZONE_CHOICES = tuple(zip(pytz.common_timezones, pytz.common_timezones))
|
||||
user_timezone = models.CharField(
|
||||
max_length=255, default="UTC", choices=USER_TIMEZONE_CHOICES
|
||||
)
|
||||
user_timezone = models.CharField(max_length=255, default="UTC", choices=USER_TIMEZONE_CHOICES)
|
||||
|
||||
# email validation
|
||||
is_email_valid = models.BooleanField(default=False)
|
||||
|
|
@ -189,13 +183,9 @@ class Profile(TimeAuditModel):
|
|||
(SATURDAY, "Saturday"),
|
||||
)
|
||||
|
||||
id = models.UUIDField(
|
||||
default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True
|
||||
)
|
||||
id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True)
|
||||
# User
|
||||
user = models.OneToOneField(
|
||||
"db.User", on_delete=models.CASCADE, related_name="profile"
|
||||
)
|
||||
user = models.OneToOneField("db.User", on_delete=models.CASCADE, related_name="profile")
|
||||
# General
|
||||
theme = models.JSONField(default=dict)
|
||||
is_app_rail_docked = models.BooleanField(default=True)
|
||||
|
|
@ -220,9 +210,7 @@ class Profile(TimeAuditModel):
|
|||
mobile_timezone_auto_set = models.BooleanField(default=False)
|
||||
# language
|
||||
language = models.CharField(max_length=255, default="en")
|
||||
start_of_the_week = models.PositiveSmallIntegerField(
|
||||
choices=START_OF_THE_WEEK_CHOICES, default=SUNDAY
|
||||
)
|
||||
start_of_the_week = models.PositiveSmallIntegerField(choices=START_OF_THE_WEEK_CHOICES, default=SUNDAY)
|
||||
goals = models.JSONField(default=dict)
|
||||
background_color = models.CharField(max_length=255, default=get_random_color)
|
||||
|
||||
|
|
@ -243,12 +231,8 @@ class Account(TimeAuditModel):
|
|||
("gitlab", "GitLab"),
|
||||
)
|
||||
|
||||
id = models.UUIDField(
|
||||
default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
"db.User", on_delete=models.CASCADE, related_name="accounts"
|
||||
)
|
||||
id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True)
|
||||
user = models.ForeignKey("db.User", on_delete=models.CASCADE, related_name="accounts")
|
||||
provider_account_id = models.CharField(max_length=255)
|
||||
provider = models.CharField(choices=PROVIDER_CHOICES)
|
||||
access_token = models.TextField()
|
||||
|
|
|
|||
|
|
@ -59,14 +59,10 @@ class IssueView(WorkspaceBaseModel):
|
|||
display_filters = models.JSONField(default=get_default_display_filters)
|
||||
display_properties = models.JSONField(default=get_default_display_properties)
|
||||
rich_filters = models.JSONField(default=dict)
|
||||
access = models.PositiveSmallIntegerField(
|
||||
default=1, choices=((0, "Private"), (1, "Public"))
|
||||
)
|
||||
access = models.PositiveSmallIntegerField(default=1, choices=((0, "Private"), (1, "Public")))
|
||||
sort_order = models.FloatField(default=65535)
|
||||
logo_props = models.JSONField(default=dict)
|
||||
owned_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="views"
|
||||
)
|
||||
owned_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="views")
|
||||
is_locked = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -81,13 +77,13 @@ class IssueView(WorkspaceBaseModel):
|
|||
|
||||
if self._state.adding:
|
||||
if self.project:
|
||||
largest_sort_order = IssueView.objects.filter(
|
||||
project=self.project
|
||||
).aggregate(largest=models.Max("sort_order"))["largest"]
|
||||
largest_sort_order = IssueView.objects.filter(project=self.project).aggregate(
|
||||
largest=models.Max("sort_order")
|
||||
)["largest"]
|
||||
else:
|
||||
largest_sort_order = IssueView.objects.filter(
|
||||
workspace=self.workspace, project__isnull=True
|
||||
).aggregate(largest=models.Max("sort_order"))["largest"]
|
||||
largest_sort_order = IssueView.objects.filter(workspace=self.workspace, project__isnull=True).aggregate(
|
||||
largest=models.Max("sort_order")
|
||||
)["largest"]
|
||||
if largest_sort_order is not None:
|
||||
self.sort_order = largest_sort_order + 10000
|
||||
|
||||
|
|
|
|||
|
|
@ -28,12 +28,8 @@ def validate_domain(value):
|
|||
|
||||
|
||||
class Webhook(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="workspace_webhooks"
|
||||
)
|
||||
url = models.URLField(
|
||||
validators=[validate_schema, validate_domain], max_length=1024
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="workspace_webhooks")
|
||||
url = models.URLField(validators=[validate_schema, validate_domain], max_length=1024)
|
||||
is_active = models.BooleanField(default=True)
|
||||
secret_key = models.CharField(max_length=255, default=generate_token)
|
||||
project = models.BooleanField(default=False)
|
||||
|
|
@ -62,9 +58,7 @@ class Webhook(BaseModel):
|
|||
|
||||
|
||||
class WebhookLog(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="webhook_logs"
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="webhook_logs")
|
||||
# Associated webhook
|
||||
webhook = models.UUIDField()
|
||||
|
||||
|
|
@ -92,11 +86,8 @@ class WebhookLog(BaseModel):
|
|||
return f"{self.event_type} {str(self.webhook)}"
|
||||
|
||||
|
||||
|
||||
class ProjectWebhook(ProjectBaseModel):
|
||||
webhook = models.ForeignKey(
|
||||
"db.Webhook", on_delete=models.CASCADE, related_name="project_webhooks"
|
||||
)
|
||||
webhook = models.ForeignKey("db.Webhook", on_delete=models.CASCADE, related_name="project_webhooks")
|
||||
|
||||
class Meta:
|
||||
unique_together = ["project", "webhook", "deleted_at"]
|
||||
|
|
@ -110,4 +101,4 @@ class ProjectWebhook(ProjectBaseModel):
|
|||
verbose_name = "Project Webhook"
|
||||
verbose_name_plural = "Project Webhooks"
|
||||
db_table = "project_webhooks"
|
||||
ordering = ("-created_at",)
|
||||
ordering = ("-created_at",)
|
||||
|
|
|
|||
|
|
@ -129,9 +129,7 @@ class Workspace(BaseModel):
|
|||
on_delete=models.CASCADE,
|
||||
related_name="owner_workspace",
|
||||
)
|
||||
slug = models.SlugField(
|
||||
max_length=48, db_index=True, unique=True, validators=[slug_validator]
|
||||
)
|
||||
slug = models.SlugField(max_length=48, db_index=True, unique=True, validators=[slug_validator])
|
||||
organization_size = models.CharField(max_length=20, blank=True, null=True)
|
||||
timezone = models.CharField(max_length=255, default="UTC", choices=TIMEZONE_CHOICES)
|
||||
background_color = models.CharField(max_length=255, default=get_random_color)
|
||||
|
|
@ -151,9 +149,7 @@ class Workspace(BaseModel):
|
|||
return self.logo
|
||||
return None
|
||||
|
||||
def delete(
|
||||
self, using: Optional[str] = None, soft: bool = True, *args: Any, **kwargs: Any
|
||||
):
|
||||
def delete(self, using: Optional[str] = None, soft: bool = True, *args: Any, **kwargs: Any):
|
||||
"""
|
||||
Override the delete method to append epoch timestamp to the slug when soft deleting.
|
||||
|
||||
|
|
@ -183,12 +179,8 @@ class Workspace(BaseModel):
|
|||
|
||||
|
||||
class WorkspaceBaseModel(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", models.CASCADE, related_name="workspace_%(class)s"
|
||||
)
|
||||
project = models.ForeignKey(
|
||||
"db.Project", models.CASCADE, related_name="project_%(class)s", null=True
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", models.CASCADE, related_name="workspace_%(class)s")
|
||||
project = models.ForeignKey("db.Project", models.CASCADE, related_name="project_%(class)s", null=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
|
@ -200,9 +192,7 @@ class WorkspaceBaseModel(BaseModel):
|
|||
|
||||
|
||||
class WorkspaceMember(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="workspace_member"
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="workspace_member")
|
||||
member = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
|
|
@ -235,9 +225,7 @@ class WorkspaceMember(BaseModel):
|
|||
|
||||
|
||||
class WorkspaceMemberInvite(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="workspace_member_invite"
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="workspace_member_invite")
|
||||
email = models.CharField(max_length=255)
|
||||
accepted = models.BooleanField(default=False)
|
||||
token = models.CharField(max_length=255)
|
||||
|
|
@ -266,9 +254,7 @@ class WorkspaceMemberInvite(BaseModel):
|
|||
class Team(BaseModel):
|
||||
name = models.CharField(max_length=255, verbose_name="Team Name")
|
||||
description = models.TextField(verbose_name="Team Description", blank=True)
|
||||
workspace = models.ForeignKey(
|
||||
Workspace, on_delete=models.CASCADE, related_name="workspace_team"
|
||||
)
|
||||
workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE, related_name="workspace_team")
|
||||
logo_props = models.JSONField(default=dict)
|
||||
|
||||
def __str__(self):
|
||||
|
|
@ -291,13 +277,9 @@ class Team(BaseModel):
|
|||
|
||||
|
||||
class WorkspaceTheme(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="themes"
|
||||
)
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="themes")
|
||||
name = models.CharField(max_length=300)
|
||||
actor = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="themes"
|
||||
)
|
||||
actor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="themes")
|
||||
colors = models.JSONField(default=dict)
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue