diff --git a/apiserver/plane/app/serializers/user.py b/apiserver/plane/app/serializers/user.py index 1fff8a90f..05d8665b5 100644 --- a/apiserver/plane/app/serializers/user.py +++ b/apiserver/plane/app/serializers/user.py @@ -33,6 +33,7 @@ class UserSerializer(BaseSerializer): "is_bot", "is_password_autoset", "is_email_verified", + "is_active", ] extra_kwargs = {"password": {"write_only": True}} diff --git a/apiserver/plane/app/views/user/base.py b/apiserver/plane/app/views/user/base.py index 5a75f8105..9a9cdde43 100644 --- a/apiserver/plane/app/views/user/base.py +++ b/apiserver/plane/app/views/user/base.py @@ -1,3 +1,6 @@ +# Python imports +# import uuid + # Django imports from django.db.models import Case, Count, IntegerField, Q, When from django.contrib.auth import logout @@ -26,6 +29,7 @@ from plane.db.models import ( User, WorkspaceMember, WorkspaceMemberInvite, + Session, ) from plane.license.models import Instance, InstanceAdmin from plane.utils.cache import cache_response, invalidate_cache @@ -160,12 +164,13 @@ class UserEndpoint(BaseViewSet): email=user.email, ).delete() - # Deactivate the user - user.is_active = False + # Delete all sessions + Session.objects.filter(user_id=request.user.id).delete() # Profile updates profile = Profile.objects.get(user=user) + # Reset onboarding profile.last_workspace_id = None profile.is_tour_completed = False profile.is_onboarded = False @@ -177,7 +182,12 @@ class UserEndpoint(BaseViewSet): } profile.save() - # User log out + # Reset password + # user.is_password_autoset = True + # user.set_password(uuid.uuid4().hex) + + # Deactivate the user + user.is_active = False user.last_logout_ip = user_ip(request=request) user.last_logout_time = timezone.now() user.save() diff --git a/apiserver/plane/authentication/adapter/oauth.py b/apiserver/plane/authentication/adapter/oauth.py index b841db99d..60c2ea0c6 100644 --- a/apiserver/plane/authentication/adapter/oauth.py +++ b/apiserver/plane/authentication/adapter/oauth.py @@ -85,5 +85,6 @@ class OauthAdapter(Adapter): "refresh_token_expired_at" ), "last_connected_at": timezone.now(), + "id_token": self.token_data.get("id_token", ""), }, ) diff --git a/apiserver/plane/authentication/provider/oauth/github.py b/apiserver/plane/authentication/provider/oauth/github.py index edccea449..798863d8f 100644 --- a/apiserver/plane/authentication/provider/oauth/github.py +++ b/apiserver/plane/authentication/provider/oauth/github.py @@ -100,6 +100,7 @@ class GitHubOAuthProvider(OauthAdapter): if token_response.get("refresh_token_expired_at") else None ), + "id_token": token_response.get("id_token", ""), } ) diff --git a/apiserver/plane/authentication/provider/oauth/google.py b/apiserver/plane/authentication/provider/oauth/google.py index 591295cb1..9c17a75af 100644 --- a/apiserver/plane/authentication/provider/oauth/google.py +++ b/apiserver/plane/authentication/provider/oauth/google.py @@ -98,6 +98,7 @@ class GoogleOAuthProvider(OauthAdapter): if token_response.get("refresh_token_expired_at") else None ), + "id_token": token_response.get("id_token", ""), } ) diff --git a/apiserver/plane/db/migrations/0066_account_id_token_cycle_logo_props_module_logo_props.py b/apiserver/plane/db/migrations/0066_account_id_token_cycle_logo_props_module_logo_props.py new file mode 100644 index 000000000..2ad5b7481 --- /dev/null +++ b/apiserver/plane/db/migrations/0066_account_id_token_cycle_logo_props_module_logo_props.py @@ -0,0 +1,58 @@ +# Generated by Django 4.2.11 on 2024-05-22 15:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("db", "0065_auto_20240415_0937"), + ] + + operations = [ + migrations.AddField( + model_name="account", + name="id_token", + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name="cycle", + name="logo_props", + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name="module", + name="logo_props", + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name="issueview", + name="logo_props", + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name="inbox", + name="logo_props", + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name="dashboard", + name="logo_props", + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name="widget", + name="logo_props", + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name="issue", + name="description_binary", + field=models.BinaryField(null=True), + ), + migrations.AddField( + model_name="team", + name="logo_props", + field=models.JSONField(default=dict), + ), + ] diff --git a/apiserver/plane/db/models/cycle.py b/apiserver/plane/db/models/cycle.py index 1b4e8e75b..5128ecbc5 100644 --- a/apiserver/plane/db/models/cycle.py +++ b/apiserver/plane/db/models/cycle.py @@ -70,6 +70,7 @@ class Cycle(ProjectBaseModel): external_id = models.CharField(max_length=255, blank=True, null=True) progress_snapshot = models.JSONField(default=dict) archived_at = models.DateTimeField(null=True) + logo_props = models.JSONField(default=dict) class Meta: verbose_name = "Cycle" diff --git a/apiserver/plane/db/models/dashboard.py b/apiserver/plane/db/models/dashboard.py index 7d483060f..f21557a54 100644 --- a/apiserver/plane/db/models/dashboard.py +++ b/apiserver/plane/db/models/dashboard.py @@ -31,6 +31,7 @@ class Dashboard(BaseModel): verbose_name="Dashboard Type", default="home", ) + logo_props = models.JSONField(default=dict) def __str__(self): """Return name of the dashboard""" @@ -53,6 +54,7 @@ class Widget(TimeAuditModel): ) key = models.CharField(max_length=255) filters = models.JSONField(default=dict) + logo_props = models.JSONField(default=dict) def __str__(self): """Return name of the widget""" diff --git a/apiserver/plane/db/models/inbox.py b/apiserver/plane/db/models/inbox.py index 6d72029b6..f45e90042 100644 --- a/apiserver/plane/db/models/inbox.py +++ b/apiserver/plane/db/models/inbox.py @@ -12,6 +12,7 @@ class Inbox(ProjectBaseModel): ) is_default = models.BooleanField(default=False) view_props = models.JSONField(default=dict) + logo_props = models.JSONField(default=dict) def __str__(self): """Return name of the Inbox""" diff --git a/apiserver/plane/db/models/issue.py b/apiserver/plane/db/models/issue.py index 7a17853c3..527597ddc 100644 --- a/apiserver/plane/db/models/issue.py +++ b/apiserver/plane/db/models/issue.py @@ -128,6 +128,7 @@ class Issue(ProjectBaseModel): description = models.JSONField(blank=True, default=dict) description_html = models.TextField(blank=True, default="

") description_stripped = models.TextField(blank=True, null=True) + description_binary = models.BinaryField(null=True) priority = models.CharField( max_length=30, choices=PRIORITY_CHOICES, diff --git a/apiserver/plane/db/models/module.py b/apiserver/plane/db/models/module.py index 7e58088dc..a6b55f246 100644 --- a/apiserver/plane/db/models/module.py +++ b/apiserver/plane/db/models/module.py @@ -93,6 +93,7 @@ class Module(ProjectBaseModel): external_source = models.CharField(max_length=255, null=True, blank=True) external_id = models.CharField(max_length=255, blank=True, null=True) archived_at = models.DateTimeField(null=True) + logo_props = models.JSONField(default=dict) class Meta: unique_together = ["name", "project"] diff --git a/apiserver/plane/db/models/user.py b/apiserver/plane/db/models/user.py index f35520d8f..c083b631c 100644 --- a/apiserver/plane/db/models/user.py +++ b/apiserver/plane/db/models/user.py @@ -189,6 +189,7 @@ class Account(TimeAuditModel): refresh_token = models.TextField(null=True, blank=True) refresh_token_expired_at = models.DateTimeField(null=True) last_connected_at = models.DateTimeField(default=timezone.now) + id_token = models.TextField(blank=True) metadata = models.JSONField(default=dict) class Meta: diff --git a/apiserver/plane/db/models/view.py b/apiserver/plane/db/models/view.py index 87f0899c3..8916bd406 100644 --- a/apiserver/plane/db/models/view.py +++ b/apiserver/plane/db/models/view.py @@ -52,6 +52,7 @@ def get_default_display_properties(): } +# DEPRECATED TODO: - Remove in next release class GlobalView(BaseModel): workspace = models.ForeignKey( "db.Workspace", on_delete=models.CASCADE, related_name="global_views" @@ -87,7 +88,6 @@ class GlobalView(BaseModel): return f"{self.name} <{self.workspace.name}>" -# DEPRECATED TODO: - Remove in next release class IssueView(WorkspaceBaseModel): name = models.CharField(max_length=255, verbose_name="View Name") description = models.TextField(verbose_name="View Description", blank=True) @@ -101,6 +101,7 @@ class IssueView(WorkspaceBaseModel): default=1, choices=((0, "Private"), (1, "Public")) ) sort_order = models.FloatField(default=65535) + logo_props = models.JSONField(default=dict) class Meta: verbose_name = "Issue View" diff --git a/apiserver/plane/db/models/workspace.py b/apiserver/plane/db/models/workspace.py index fe39f2d09..f9cd681ec 100644 --- a/apiserver/plane/db/models/workspace.py +++ b/apiserver/plane/db/models/workspace.py @@ -244,6 +244,7 @@ class Team(BaseModel): workspace = models.ForeignKey( Workspace, on_delete=models.CASCADE, related_name="workspace_team" ) + logo_props = models.JSONField(default=dict) def __str__(self): """Return name of the team"""