diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 4a14257..bb0e78a 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -33,9 +33,11 @@ jobs: terraform_version: 1.3.0 - name: Terraform Init + if: github.event_name == 'pull_request' run: terraform -chdir=infra init - name: Terraform Plan + if: github.event_name == 'pull_request' run: terraform -chdir=infra plan -var="db_username=${{ secrets.DB_USER_PROD }}" -var="db_password=${{ secrets.DB_PASSWORD }}" - name: Terraform Apply (for push to main) diff --git a/backend/projects/migrations/0006_project_tags.py b/backend/projects/migrations/0006_project_tags.py new file mode 100644 index 0000000..92d41b4 --- /dev/null +++ b/backend/projects/migrations/0006_project_tags.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.6 on 2025-03-25 02:56 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0005_rename_followers_project_followers_count_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='project', + name='tags', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=225), blank=True, null=True, size=None), + ), + ] diff --git a/backend/projects/migrations/0007_project_email_project_full_description_and_more.py b/backend/projects/migrations/0007_project_email_project_full_description_and_more.py new file mode 100644 index 0000000..3baed1c --- /dev/null +++ b/backend/projects/migrations/0007_project_email_project_full_description_and_more.py @@ -0,0 +1,57 @@ +# Generated by Django 5.1.6 on 2025-03-25 04:35 + +import django.contrib.postgres.fields +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0006_project_tags'), + ('userauth', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='project', + name='email', + field=models.EmailField(blank=True, max_length=254, null=True, unique=True), + ), + migrations.AddField( + model_name='project', + name='full_description', + field=models.CharField(blank=True, max_length=1000, null=True), + ), + migrations.AddField( + model_name='project', + name='members', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='member_of_projects', to='userauth.user'), + ), + migrations.AddField( + model_name='project', + name='other_contact', + field=models.CharField(blank=True, max_length=225, null=True), + ), + migrations.AddField( + model_name='project', + name='owner', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='owned_projects', to='userauth.user'), + ), + migrations.AddField( + model_name='project', + name='project_id', + field=models.UUIDField(default=uuid.uuid4, editable=False, null=True), + ), + migrations.AddField( + model_name='project', + name='updates', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=540), blank=True, null=True, size=None), + ), + migrations.AddField( + model_name='project', + name='wanted_description', + field=models.CharField(blank=True, max_length=540, null=True), + ), + ] diff --git a/backend/projects/migrations/0008_populate_uuids.py b/backend/projects/migrations/0008_populate_uuids.py new file mode 100644 index 0000000..eda508e --- /dev/null +++ b/backend/projects/migrations/0008_populate_uuids.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.6 on 2025-03-25 04:36 + +from django.db import migrations +import uuid + +def populate_uuids(apps, schema_editor): + Project = apps.get_model('projects', 'Project') + for project in Project.objects.all(): + project.project_id = uuid.uuid4() + project.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0007_project_email_project_full_description_and_more'), + ] + + operations = [ + migrations.RunPython(populate_uuids), + ] diff --git a/backend/projects/migrations/0009_remove_project_id_alter_project_project_id.py b/backend/projects/migrations/0009_remove_project_id_alter_project_project_id.py new file mode 100644 index 0000000..e8d1dd4 --- /dev/null +++ b/backend/projects/migrations/0009_remove_project_id_alter_project_project_id.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.6 on 2025-03-25 04:38 + +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0008_populate_uuids'), + ] + + operations = [ + migrations.RemoveField( + model_name='project', + name='id', + ), + migrations.AlterField( + model_name='project', + name='project_id', + field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), + ), + ] diff --git a/backend/projects/migrations/0010_rename_tags_project_interest_tags_project_location_and_more.py b/backend/projects/migrations/0010_rename_tags_project_interest_tags_project_location_and_more.py new file mode 100644 index 0000000..9f746eb --- /dev/null +++ b/backend/projects/migrations/0010_rename_tags_project_interest_tags_project_location_and_more.py @@ -0,0 +1,49 @@ +# Generated by Django 5.1.7 on 2025-03-26 04:24 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0009_remove_project_id_alter_project_project_id'), + ] + + operations = [ + migrations.RenameField( + model_name='project', + old_name='tags', + new_name='interest_tags', + ), + migrations.AddField( + model_name='project', + name='location', + field=models.JSONField(blank=True, default=list), + ), + migrations.AddField( + model_name='project', + name='skill_tags', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=225), blank=True, null=True, size=None), + ), + migrations.AlterField( + model_name='project', + name='group', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AlterField( + model_name='project', + name='image_url', + field=models.ImageField(upload_to='projects/'), + ), + migrations.AlterField( + model_name='project', + name='images', + field=models.JSONField(blank=True, default=list), + ), + migrations.AlterField( + model_name='project', + name='match_percentage', + field=models.FloatField(blank=True, null=True), + ), + ] diff --git a/backend/projects/migrations/0011_remove_project_members_project_members.py b/backend/projects/migrations/0011_remove_project_members_project_members.py new file mode 100644 index 0000000..9fb8480 --- /dev/null +++ b/backend/projects/migrations/0011_remove_project_members_project_members.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.7 on 2025-03-26 04:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0010_rename_tags_project_interest_tags_project_location_and_more'), + ('userauth', '0003_rename_tags_user_interest_tags_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='project', + name='members', + ), + migrations.AddField( + model_name='project', + name='members', + field=models.ManyToManyField(blank=True, null=True, related_name='member_of_projects', to='userauth.user'), + ), + ] diff --git a/backend/projects/migrations/0012_alter_project_members.py b/backend/projects/migrations/0012_alter_project_members.py new file mode 100644 index 0000000..46254bb --- /dev/null +++ b/backend/projects/migrations/0012_alter_project_members.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.7 on 2025-03-26 04:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0011_remove_project_members_project_members'), + ('userauth', '0003_rename_tags_user_interest_tags_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='project', + name='members', + field=models.ManyToManyField(blank=True, related_name='member_of_projects', to='userauth.user'), + ), + ] diff --git a/backend/projects/migrations/0013_rename_project_id_project_id.py b/backend/projects/migrations/0013_rename_project_id_project_id.py new file mode 100644 index 0000000..c77e357 --- /dev/null +++ b/backend/projects/migrations/0013_rename_project_id_project_id.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.7 on 2025-03-26 04:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0012_alter_project_members'), + ] + + operations = [ + migrations.RenameField( + model_name='project', + old_name='project_id', + new_name='id', + ), + ] diff --git a/backend/projects/models.py b/backend/projects/models.py index 32148b7..4a3bd66 100644 --- a/backend/projects/models.py +++ b/backend/projects/models.py @@ -1,18 +1,49 @@ from django.db import models from userauth.models import User - +from django.contrib.postgres.fields import ArrayField +import uuid # PROJECTS MODEL class Project(models.Model): - group = models.CharField(max_length=255) - match_percentage = models.FloatField() - title = models.CharField(max_length=255) - institution = models.CharField(max_length=255) - description = models.TextField() + # Auto generated + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + + # REQUIRED + title = models.CharField(max_length=255, blank=False, null=False) + institution = models.CharField(max_length=255, blank=False, null=False) + description = models.TextField(blank=False, null=False) + positions = models.JSONField(default=list) + image_url = models.ImageField(upload_to="projects/", blank=False, null=False) + + # Not Required + group = models.CharField(max_length=255, blank=True, null=True) followers_count = models.IntegerField(default=0) likes_count = models.IntegerField(default=0) - positions = models.JSONField(default=list) - image_url = models.ImageField(upload_to="projects/", blank=True, null=True) - images = models.JSONField(default=list) + match_percentage = models.FloatField(blank=True, null=True) + location = models.JSONField(default=list, blank=True) + images = models.JSONField(default=list, blank=True) + interest_tags = ArrayField(models.CharField(max_length=225), blank=True, null=True) + skill_tags = ArrayField(models.CharField(max_length=225), blank=True, null=True) + full_description = models.CharField(max_length=1000, blank=True, null=True) + email = models.EmailField(unique=True, blank=True, null=True) + other_contact = models.CharField(max_length=225, blank=True, null=True) + updates = ArrayField(models.CharField(max_length=540), blank=True, null=True) + wanted_description = models.CharField(max_length=540, blank=True, null=True) + + members = models.ManyToManyField( + 'userauth.User', + related_name='member_of_projects', + blank=True + ) + + owner = models.ForeignKey( + 'userauth.User', + on_delete=models.CASCADE, + related_name='owned_projects', + null=True, + blank=True + ) + + #discussion = ArrayField(models.CharField(max_length=540), blank=True, null=True) - for future def __str__(self): return self.title diff --git a/backend/projects/urls.py b/backend/projects/urls.py index 82e4b3f..f31094d 100644 --- a/backend/projects/urls.py +++ b/backend/projects/urls.py @@ -4,7 +4,7 @@ urlpatterns = [ path('', get_projects, name='get_projects'), # Fetch all projects path('create/', ProjectCRUDView.as_view(), name='project-create'), # Create project - path('/', ProjectCRUDView.as_view(), name='project-detail'), # Read, Update, Delete project by ID + path('/', ProjectCRUDView.as_view(), name='project-detail'), # Read, Update, Delete project by ID path('like/', toggle_like, name='toggle_like'), path('follow/', toggle_follow, name='toggle_follow') ] diff --git a/backend/userauth/migrations/0002_user_owned_user_projects_alter_user_email.py b/backend/userauth/migrations/0002_user_owned_user_projects_alter_user_email.py new file mode 100644 index 0000000..1916e25 --- /dev/null +++ b/backend/userauth/migrations/0002_user_owned_user_projects_alter_user_email.py @@ -0,0 +1,30 @@ +# Generated by Django 5.1.6 on 2025-03-25 04:35 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0007_project_email_project_full_description_and_more'), + ('userauth', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='owned', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='owners', to='projects.project'), + ), + migrations.AddField( + model_name='user', + name='projects', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='contributors', to='projects.project'), + ), + migrations.AlterField( + model_name='user', + name='email', + field=models.EmailField(blank=True, max_length=254, null=True, unique=True), + ), + ] diff --git a/backend/userauth/migrations/0003_rename_tags_user_interest_tags_and_more.py b/backend/userauth/migrations/0003_rename_tags_user_interest_tags_and_more.py new file mode 100644 index 0000000..75dc002 --- /dev/null +++ b/backend/userauth/migrations/0003_rename_tags_user_interest_tags_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 5.1.7 on 2025-03-26 04:24 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('userauth', '0002_user_owned_user_projects_alter_user_email'), + ] + + operations = [ + migrations.RenameField( + model_name='user', + old_name='tags', + new_name='interest_tags', + ), + migrations.RenameField( + model_name='user', + old_name='position', + new_name='location_preference', + ), + migrations.AddField( + model_name='user', + name='positions', + field=models.JSONField(default=list), + ), + migrations.AddField( + model_name='user', + name='skill_tags', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=225), blank=True, null=True, size=None), + ), + ] diff --git a/backend/userauth/migrations/0004_remove_user_owned_remove_user_projects_user_owned_and_more.py b/backend/userauth/migrations/0004_remove_user_owned_remove_user_projects_user_owned_and_more.py new file mode 100644 index 0000000..e53d9c7 --- /dev/null +++ b/backend/userauth/migrations/0004_remove_user_owned_remove_user_projects_user_owned_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 5.1.7 on 2025-03-26 04:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0012_alter_project_members'), + ('userauth', '0003_rename_tags_user_interest_tags_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='user', + name='owned', + ), + migrations.RemoveField( + model_name='user', + name='projects', + ), + migrations.AddField( + model_name='user', + name='owned', + field=models.ManyToManyField(blank=True, related_name='owners', to='projects.project'), + ), + migrations.AddField( + model_name='user', + name='projects', + field=models.ManyToManyField(blank=True, related_name='contributors', to='projects.project'), + ), + ] diff --git a/backend/userauth/models.py b/backend/userauth/models.py index bd52789..979bd35 100644 --- a/backend/userauth/models.py +++ b/backend/userauth/models.py @@ -4,12 +4,25 @@ class User(models.Model): auth_id = models.IntegerField(default=999) username = models.CharField(max_length=255, unique=True) - email = models.EmailField(unique=True) + email = models.EmailField(unique=True, blank=True, null=True) institution = models.CharField(max_length=255, blank=True, null=True) followers = models.IntegerField(default=0) likes = models.IntegerField(default=0) - position = models.JSONField(default=list) - tags = ArrayField(models.CharField(max_length=225), blank=True, null=True) + positions = models.JSONField(default=list) + interest_tags = ArrayField(models.CharField(max_length=225), blank=True, null=True) + skill_tags = ArrayField(models.CharField(max_length=225), blank=True, null=True) + location_preference = models.JSONField(default=list) + + projects = models.ManyToManyField( + 'projects.Project', + related_name='contributors', + blank=True + ) + owned = models.ManyToManyField( + 'projects.Project', + related_name='owners', + blank=True + ) def __str__(self): return self.username