diff --git a/apiserver/plane/db/migrations/0083_issuetype_is_epic_workspace_timezone_and_more.py b/apiserver/plane/db/migrations/0083_device_workspace_timezone_and_more.py similarity index 85% rename from apiserver/plane/db/migrations/0083_issuetype_is_epic_workspace_timezone_and_more.py rename to apiserver/plane/db/migrations/0083_device_workspace_timezone_and_more.py index 4769c51442c..587ee880006 100644 --- a/apiserver/plane/db/migrations/0083_issuetype_is_epic_workspace_timezone_and_more.py +++ b/apiserver/plane/db/migrations/0083_device_workspace_timezone_and_more.py @@ -1,15 +1,106 @@ -# Generated by Django 4.2.15 on 2024-11-01 15:21 +# Generated by Django 4.2.15 on 2024-11-01 17:02 +from django.conf import settings from django.db import migrations, models import django.db.models.deletion +import uuid class Migration(migrations.Migration): + dependencies = [ ("db", "0082_alter_issue_managers_alter_cycleissue_issue_and_more"), ] operations = [ + migrations.CreateModel( + name="Device", + fields=[ + ( + "created_at", + models.DateTimeField( + auto_now_add=True, verbose_name="Created At" + ), + ), + ( + "updated_at", + models.DateTimeField( + auto_now=True, verbose_name="Last Modified At" + ), + ), + ( + "deleted_at", + models.DateTimeField( + blank=True, null=True, verbose_name="Deleted At" + ), + ), + ( + "id", + models.UUIDField( + db_index=True, + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + unique=True, + ), + ), + ( + "device_id", + models.CharField(blank=True, max_length=255, null=True), + ), + ( + "device_type", + models.CharField( + choices=[ + ("ANDROID", "Android"), + ("IOS", "iOS"), + ("WEB", "Web"), + ("DESKTOP", "Desktop"), + ], + max_length=255, + ), + ), + ( + "push_token", + models.CharField(blank=True, max_length=255, null=True), + ), + ("is_active", models.BooleanField(default=True)), + ( + "created_by", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="%(class)s_created_by", + to=settings.AUTH_USER_MODEL, + verbose_name="Created By", + ), + ), + ( + "updated_by", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="%(class)s_updated_by", + to=settings.AUTH_USER_MODEL, + verbose_name="Last Modified By", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="devices", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "verbose_name": "Device", + "verbose_name_plural": "Devices", + "db_table": "devices", + }, + ), migrations.AddField( model_name="issuetype", name="is_epic", @@ -663,18 +754,6 @@ class Migration(migrations.Migration): max_length=255, ), ), - migrations.AlterField( - model_name="account", - name="provider", - field=models.CharField( - choices=[ - ("google", "Google"), - ("github", "Github"), - ("gitlab", "GitLab"), - ("firebase", "Firebase"), - ] - ), - ), migrations.AlterField( model_name="issuerelation", name="relation_type", @@ -706,4 +785,90 @@ class Migration(migrations.Migration): to="db.project", ), ), + migrations.CreateModel( + name="DeviceSession", + fields=[ + ( + "created_at", + models.DateTimeField( + auto_now_add=True, verbose_name="Created At" + ), + ), + ( + "updated_at", + models.DateTimeField( + auto_now=True, verbose_name="Last Modified At" + ), + ), + ( + "deleted_at", + models.DateTimeField( + blank=True, null=True, verbose_name="Deleted At" + ), + ), + ( + "id", + models.UUIDField( + db_index=True, + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + unique=True, + ), + ), + ("is_active", models.BooleanField(default=True)), + ( + "user_agent", + models.CharField(blank=True, max_length=255, null=True), + ), + ( + "ip_address", + models.GenericIPAddressField(blank=True, null=True), + ), + ("start_time", models.DateTimeField(auto_now_add=True)), + ("end_time", models.DateTimeField(blank=True, null=True)), + ( + "created_by", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="%(class)s_created_by", + to=settings.AUTH_USER_MODEL, + verbose_name="Created By", + ), + ), + ( + "device", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="sessions", + to="db.device", + ), + ), + ( + "session", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="device_sessions", + to="db.session", + ), + ), + ( + "updated_by", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="%(class)s_updated_by", + to=settings.AUTH_USER_MODEL, + verbose_name="Last Modified By", + ), + ), + ], + options={ + "verbose_name": "Device Session", + "verbose_name_plural": "Device Sessions", + "db_table": "device_sessions", + }, + ), ] diff --git a/apiserver/plane/db/models/__init__.py b/apiserver/plane/db/models/__init__.py index 94dc5008565..dd91a4b1d39 100644 --- a/apiserver/plane/db/models/__init__.py +++ b/apiserver/plane/db/models/__init__.py @@ -5,7 +5,13 @@ from .cycle import Cycle, CycleIssue, CycleUserProperties from .dashboard import Dashboard, DashboardWidget, Widget from .deploy_board import DeployBoard -from .draft import DraftIssue, DraftIssueAssignee, DraftIssueLabel, DraftIssueModule, DraftIssueCycle +from .draft import ( + DraftIssue, + DraftIssueAssignee, + DraftIssueLabel, + DraftIssueModule, + DraftIssueCycle, +) from .estimate import Estimate, EstimatePoint from .exporter import ExporterHistory from .importer import Importer @@ -109,4 +115,6 @@ from .recent_visit import UserRecentVisit -from .label import Label \ No newline at end of file +from .label import Label + +from .device import Device, DeviceSession diff --git a/apiserver/plane/db/models/device.py b/apiserver/plane/db/models/device.py new file mode 100644 index 00000000000..862861f9011 --- /dev/null +++ b/apiserver/plane/db/models/device.py @@ -0,0 +1,50 @@ +# models.py +from django.db import models +from django.conf import settings +from .base import BaseModel + + +class Device(BaseModel): + class DeviceType(models.TextChoices): + ANDROID = "ANDROID", "Android" + IOS = "IOS", "iOS" + WEB = "WEB", "Web" + DESKTOP = "DESKTOP", "Desktop" + + 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) + is_active = models.BooleanField(default=True) + + class Meta: + db_table = "devices" + verbose_name = "Device" + verbose_name_plural = "Devices" + + +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", + ) + 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) + start_time = models.DateTimeField(auto_now_add=True) + end_time = models.DateTimeField(null=True, blank=True) + + class Meta: + db_table = "device_sessions" + verbose_name = "Device Session" + verbose_name_plural = "Device Sessions" diff --git a/apiserver/plane/db/models/user.py b/apiserver/plane/db/models/user.py index 81c766e98d3..3b84ec60e27 100644 --- a/apiserver/plane/db/models/user.py +++ b/apiserver/plane/db/models/user.py @@ -213,7 +213,6 @@ class Account(TimeAuditModel): ("google", "Google"), ("github", "Github"), ("gitlab", "GitLab"), - ("firebase", "Firebase"), ) id = models.UUIDField( @@ -230,8 +229,7 @@ class Account(TimeAuditModel): provider = models.CharField( choices=PROVIDER_CHOICES, ) - device_token = models.TextField(blank=True, null=True) - access_token = models.TextField(blank=True, null=True) + access_token = models.TextField() access_token_expired_at = models.DateTimeField(null=True) refresh_token = models.TextField(null=True, blank=True) refresh_token_expired_at = models.DateTimeField(null=True)