From 01a8525ec20999a96d8cbb1d086ffbc369581eea Mon Sep 17 00:00:00 2001 From: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Date: Tue, 31 Dec 2024 16:40:44 +0530 Subject: [PATCH] feat: add workspace member and project member activity models (#2054) * workspace-activity-model * fix: workspace activity --- ...rkspaceentityconnection_source_and_more.py | 71 +++++++++++++++++++ apiserver/plane/ee/models/job.py | 2 +- apiserver/plane/ee/models/project.py | 45 ++++++++++++ apiserver/plane/ee/models/workspace.py | 34 +++++++++ 4 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 apiserver/plane/ee/migrations/0020_rename_type_workspaceentityconnection_source_and_more.py diff --git a/apiserver/plane/ee/migrations/0020_rename_type_workspaceentityconnection_source_and_more.py b/apiserver/plane/ee/migrations/0020_rename_type_workspaceentityconnection_source_and_more.py new file mode 100644 index 0000000000..5fa4dc0f39 --- /dev/null +++ b/apiserver/plane/ee/migrations/0020_rename_type_workspaceentityconnection_source_and_more.py @@ -0,0 +1,71 @@ +# Generated by Django 4.2.17 on 2024-12-31 05:54 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0088_sticky_sort_order_workspaceuserlink'), + ('ee', '0019_workspaceconnection_alter_entityupdates_status_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='importjob', + old_name='type', + new_name='source', + ), + migrations.CreateModel( + name='WorkspaceMemberActivityModel', + 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)), + ('type', models.CharField(default='JOINED', max_length=255)), + ('old_value', models.TextField(blank=True, null=True, verbose_name='Old Value')), + ('new_value', models.TextField(blank=True, null=True, verbose_name='New Value')), + ('epoch', models.FloatField(null=True)), + ('actor', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='workspace_member_activities', to=settings.AUTH_USER_MODEL)), + ('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')), + ('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='member_activities', to='db.workspace')), + ('workspace_member', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='db.workspacemember')), + ], + options={ + 'verbose_name': 'Workspace Member Activity', + 'verbose_name_plural': 'Workspace Member Activities', + 'db_table': 'workspace_member_activities', + 'ordering': ('-created_at',), + }, + ), + migrations.CreateModel( + name='ProjectMemberActivityModel', + 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)), + ('type', models.CharField(default='PROJECT_JOINED', max_length=255)), + ('old_value', models.TextField(blank=True, null=True)), + ('new_value', models.TextField(blank=True, null=True)), + ('epoch', models.FloatField(null=True)), + ('actor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_member_activities', to=settings.AUTH_USER_MODEL)), + ('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')), + ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_%(class)s', to='db.project')), + ('project_member', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='db.projectmember')), + ('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')), + ('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_%(class)s', to='db.workspace')), + ], + options={ + 'verbose_name': 'Project Member Activity', + 'verbose_name_plural': 'Project Member Activities', + 'db_table': 'project_member_activities', + 'ordering': ('-created_at',), + }, + ), + ] diff --git a/apiserver/plane/ee/models/job.py b/apiserver/plane/ee/models/job.py index 8133921640..bd34b3d0c5 100644 --- a/apiserver/plane/ee/models/job.py +++ b/apiserver/plane/ee/models/job.py @@ -41,7 +41,7 @@ class ImportJob(BaseModel): ERROR = "ERROR", "Error" CANCELLED = "CANCELLED", "Cancelled" - type = models.CharField(max_length=20) + source = models.CharField(max_length=20) config = models.JSONField(default=dict) credential = models.ForeignKey( "ee.WorkspaceCredential", diff --git a/apiserver/plane/ee/models/project.py b/apiserver/plane/ee/models/project.py index 59a64e7a47..26c1040246 100644 --- a/apiserver/plane/ee/models/project.py +++ b/apiserver/plane/ee/models/project.py @@ -210,3 +210,48 @@ class ProjectCommentReaction(ProjectBaseModel): def __str__(self): return f"{self.comment} {self.actor.email}" + + +class ProjectMemberActivityModel(ProjectBaseModel): + class ProjectMemberActivityType(models.TextChoices): + # Project + PROJECT_JOINED = "PROJECT_JOINED", "Project Joined" + PROJECT_LEFT = "PROJECT_LEFT", "Project Left" + PROJECT_INVITED = "PROJECT_INVITED", "Project Invited" + PROJECT_REMOVED = "PROJECT_REMOVED", "Project Removed" + + # Team + TEAM_JOINED = "TEAM_JOINED", "Team Joined" + TEAM_LEFT = "TEAM_LEFT", "Team Left" + TEAM_INVITED = "TEAM_INVITED", "Team Invited" + TEAM_REMOVED = "TEAM_REMOVED", "Team Removed" + + # Role + ROLE_UPDATED = "ROLE_UPDATED", "Role Updated" + + actor = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + related_name="project_member_activities", + ) + project_member = models.ForeignKey( + "db.ProjectMember", + on_delete=models.CASCADE, + related_name="activities", + null=True, + ) + type = models.CharField( + max_length=255, default=ProjectMemberActivityType.PROJECT_JOINED + ) + old_value = models.TextField(blank=True, null=True) + new_value = models.TextField(blank=True, null=True) + epoch = models.FloatField(null=True) + + class Meta: + verbose_name = "Project Member Activity" + verbose_name_plural = "Project Member Activities" + db_table = "project_member_activities" + ordering = ("-created_at",) + + def __str__(self): + return f"{self.project.name} {self.actor}" diff --git a/apiserver/plane/ee/models/workspace.py b/apiserver/plane/ee/models/workspace.py index 92f6e7c942..dcba3b76ad 100644 --- a/apiserver/plane/ee/models/workspace.py +++ b/apiserver/plane/ee/models/workspace.py @@ -179,3 +179,37 @@ class WorkspaceEntityConnection(BaseModel): verbose_name = "Workspace Entity Connection" verbose_name_plural = "Workspace Entity Connections" db_table = "workspace_entity_connections" + + +class WorkspaceMemberActivityModel(BaseModel): + class WorkspaceMemberActivityType(models.TextChoices): + JOINED = "JOINED", "JOINED" + REMOVED = "REMOVED", "Removed" + LEFT = "LEFT", "Left" + ROLE_CHANGED = "ROLE_CHANGED", "Role Changed" + + workspace = models.ForeignKey( + "db.Workspace", on_delete=models.CASCADE, related_name="member_activities" + ) + actor = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.SET_NULL, + null=True, + related_name="workspace_member_activities", + ) + type = models.CharField(max_length=255, default=WorkspaceMemberActivityType.JOINED) + workspace_member = models.ForeignKey( + "db.WorkspaceMember", on_delete=models.CASCADE, related_name="activities" + ) + old_value = models.TextField(verbose_name="Old Value", blank=True, null=True) + new_value = models.TextField(verbose_name="New Value", blank=True, null=True) + epoch = models.FloatField(null=True) + + class Meta: + verbose_name = "Workspace Member Activity" + verbose_name_plural = "Workspace Member Activities" + db_table = "workspace_member_activities" + ordering = ("-created_at",) + + def __str__(self): + return f"{self.workspace.name} {self.type}"