Skip to content

Commit

Permalink
Merge branch 'main' into 1006
Browse files Browse the repository at this point in the history
  • Loading branch information
mattburnett-repo committed Dec 7, 2024
2 parents 84a1934 + 03f961e commit 2728aa2
Show file tree
Hide file tree
Showing 38 changed files with 872 additions and 1,018 deletions.
14 changes: 12 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ git remote add upstream https://github.com/activist-org/activist.git

6. You can visit <http://localhost:3000/> to see the development frontend once the container is up and running. From there click `View organizations` or `View events` to explore the platform.

7. To view the backend admin UI and Swagger UI, visit <http://localhost:8000/> and <http://localhost:8000/v1/schema/swagger-ui/> respectively.
7. To view the backend admin UI and Swagger UI, visit <http://localhost:8000/admin> and <http://localhost:8000/v1/schema/swagger-ui/> respectively.

8. If you'd like to sign in to the frontend via <http://localhost:3000/auth/sign-in> or the Django admin panel via <http://localhost:8000/admin>, then you can use the fixtures `admin` user with the password `admin`.
Expand All @@ -238,11 +238,21 @@ The frontend currently uses [Yarn 1](https://classic.yarnpkg.com/lang/en/docs/in
# In the root activist directory:
cd frontend
yarn install
yarn run dev
yarn run dev:local
```

You can then visit http://localhost:3000/ to see the development frontend build once the server is up and running.

You can also build the production version locally:

```bash
# In activist/frontend:
yarn build:local
# Run the production build:
node .output/server/index.mjs
```

</p>
</details>

Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,16 @@ git remote add upstream https://github.com/activist-org/activist.git
# docker compose --env-file .env.dev down
```

Sometimes changes to the database can cause the database population to fail in your environment. If this happens, you can destroy the deployment and rebuild it:

```bash
# Destroy your current docker-compose deployment:
docker-compose rm -f -v --env-file .env.dev
```

6. You can then visit <http://localhost:3000> to see the development frontend build once the container is up and running. From there click `View organizations` or `View events` to explore the platform.

7. To view the backend admin UI and Swagger UI, visit <http://localhost:8000/> and <http://localhost:8000/v1/schema/swagger-ui/> respectively.
7. To view the backend admin UI and Swagger UI, visit <http://localhost:8000/admin> and <http://localhost:8000/v1/schema/swagger-ui/> respectively.

8. If you'd like to sign in to the frontend via <http://localhost:3000/auth/sign-in> or the Django admin panel via <http://localhost:8000/admin>, then you can use the fixtures `admin` user with the password `admin`.
Expand Down
48 changes: 26 additions & 22 deletions backend/backend/management/commands/populate_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from entities.factories import (
GroupFactory,
GroupTextFactory,
OrganizationEventFactory,
OrganizationFactory,
OrganizationTextFactory,
)
Expand Down Expand Up @@ -60,42 +59,47 @@ def handle(self, *args: str, **options: Unpack[Options]) -> None:
UserTopicFactory(user_id=user, topic_id=user_topic)

for o in range(num_orgs_per_user):
for e in range(num_events_per_org):
event_type = random.choice(["learn", "action"])
event_type_verb = (
"Learning about"
if event_type == "learn"
else "Fighting for"
)

event_texts = EventTextFactory(iso="en", primary=True)

user_org_event = EventFactory(
name=f"{user_topic.name} Event o{o}:e{e}",
tagline=f"{event_type_verb} {user_topic.name}",
type=event_type,
texts=event_texts,
created_by=user,
)

org_texts = OrganizationTextFactory(iso="wt", primary=True)

user_org = OrganizationFactory(
created_by=user,
org_name=f"organization_u{u}_o{o}",
texts=org_texts,
name=f"{user_topic.name} Organization",
tagline=f"Fighting for {user_topic.name.lower()}",
)

OrganizationTextFactory(org_id=user_org, iso="wt", primary=True)
user_org.events.set([user_org_event])

for g in range(num_groups_per_org):
user_org_group = GroupFactory(
group_texts = GroupTextFactory(iso="en", primary=True)

_ = GroupFactory(
created_by=user,
group_name=f"group_u{u}_o{o}_g{g}",
org_id=user_org,
texts=group_texts,
name=f"{user_topic.name} Group",
)

GroupTextFactory(
group_id=user_org_group, iso="en", primary=True
)

for e in range(num_events_per_org):
user_org_event = EventFactory(
created_by=user,
name=f"{user_topic.name} Event o{o}:e{e}",
type=random.choice(["learn", "action"]),
)

EventTextFactory(
event_id=user_org_event, iso="en", primary=True
)

OrganizationEventFactory(
org_id=user_org, event_id=user_org_event
)

self.stdout.write(
self.style.ERROR(
f"Number of users created: {num_users}\n"
Expand Down
2 changes: 1 addition & 1 deletion backend/content/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class Meta:
created_by = factory.SubFactory("authentication.factories.UserFactory")
name = factory.Faker("name")
description = factory.Faker("text")
location_id = factory.SubFactory(EntityLocationFactory)
location = factory.SubFactory(EntityLocationFactory)
url = factory.Faker("url")
is_private = factory.Faker("boolean")
terms_checked = factory.Faker("boolean")
Expand Down
2 changes: 1 addition & 1 deletion backend/content/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class Resource(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(max_length=500)
category = models.CharField(max_length=255, blank=True)
location_id = models.OneToOneField(
location = models.OneToOneField(
"content.Location", on_delete=models.CASCADE, null=False, blank=False
)
url = models.URLField(max_length=255)
Expand Down
2 changes: 1 addition & 1 deletion backend/entities/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class OrganizationAdmin(admin.ModelAdmin[Organization]):


class OrganizationTextAdmin(admin.ModelAdmin[OrganizationText]):
list_display = ["id", "org_id"]
list_display = ["id"]


admin.site.register(Group, GroupAdmin)
Expand Down
8 changes: 3 additions & 5 deletions backend/entities/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Meta:
terms_checked = factory.Faker("boolean")
status = factory.SubFactory("entities.factories.StatusTypeFactory", name="Active")
is_high_risk = factory.Faker("boolean")
location_id = factory.SubFactory("content.factories.EntityLocationFactory")
location = factory.SubFactory("content.factories.EntityLocationFactory")
acceptance_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)
Expand All @@ -56,7 +56,7 @@ class Meta:
)
terms_checked = factory.Faker("boolean")
category = factory.Faker("word")
location_id = factory.SubFactory("content.factories.EntityLocationFactory")
location = factory.SubFactory("content.factories.EntityLocationFactory")


# MARK: Bridge Tables
Expand Down Expand Up @@ -99,8 +99,7 @@ class GroupTextFactory(factory.django.DjangoModelFactory):
class Meta:
model = GroupText

group_id = factory.SubFactory(GroupFactory)
iso = factory.Faker("word")
iso = "en"
primary = factory.Faker("boolean")
description = factory.Faker(provider="text", locale="la", max_nb_chars=1000)
get_involved = factory.Faker(provider="text", locale="la")
Expand Down Expand Up @@ -186,7 +185,6 @@ class OrganizationTextFactory(factory.django.DjangoModelFactory):
class Meta:
model = OrganizationText

org_id = factory.SubFactory(OrganizationFactory)
iso = "en"
primary = factory.Faker("boolean")
description = factory.Faker(provider="text", locale="la", max_nb_chars=1000)
Expand Down
18 changes: 13 additions & 5 deletions backend/entities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Organization(models.Model):
icon_url = models.OneToOneField(
"content.Image", on_delete=models.CASCADE, blank=True, null=True
)
location_id = models.OneToOneField(
location = models.OneToOneField(
"content.Location", on_delete=models.CASCADE, null=False, blank=False
)
get_involved_url = models.URLField(blank=True)
Expand All @@ -41,9 +41,11 @@ class Organization(models.Model):
status_updated = models.DateTimeField(auto_now=True, null=True)
acceptance_date = models.DateTimeField(blank=True, null=True)
deletion_date = models.DateTimeField(blank=True, null=True)
org_text = models.ForeignKey(
texts = models.ForeignKey(
"OrganizationText", on_delete=models.CASCADE, blank=True, null=True
)
events = models.ManyToManyField("events.Event", blank=True)
resources = models.ManyToManyField("content.Resource", blank=True)

def __str__(self) -> str:
return self.name
Expand All @@ -56,13 +58,18 @@ class Group(models.Model):
group_name = models.CharField(max_length=255)
name = models.CharField(max_length=255)
tagline = models.CharField(max_length=255, blank=True)
location_id = models.OneToOneField(
location = models.OneToOneField(
"content.Location", on_delete=models.CASCADE, null=False, blank=False
)
category = models.CharField(max_length=255)
get_involved_url = models.URLField(blank=True)
terms_checked = models.BooleanField(default=False)
creation_date = models.DateTimeField(auto_now_add=True)
texts = models.ForeignKey(
"GroupText", on_delete=models.CASCADE, blank=True, null=True
)
events = models.ManyToManyField("events.Event", blank=True)
resources = models.ManyToManyField("content.Resource", blank=True)

def __str__(self) -> str:
return self.name
Expand Down Expand Up @@ -135,7 +142,7 @@ def __str__(self) -> str:


class GroupText(models.Model):
group_id = models.ForeignKey(Group, on_delete=models.CASCADE)
group_id = models.ForeignKey(Group, on_delete=models.CASCADE, null=True)
iso = models.CharField(max_length=3, choices=ISO_CHOICES)
primary = models.BooleanField(default=False)
description = models.TextField(max_length=500)
Expand Down Expand Up @@ -243,6 +250,7 @@ def __str__(self) -> str:


class OrganizationTask(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
org_id = models.ForeignKey(Organization, on_delete=models.CASCADE)
task_id = models.ForeignKey("content.Task", on_delete=models.CASCADE)
group_id = models.ForeignKey(
Expand All @@ -254,7 +262,7 @@ def __str__(self) -> str:


class OrganizationText(models.Model):
org_id = models.ForeignKey(Organization, on_delete=models.CASCADE)
org_id = models.ForeignKey(Organization, on_delete=models.CASCADE, null=True)
iso = models.CharField(max_length=3, choices=ISO_CHOICES)
primary = models.BooleanField(default=False)
description = models.TextField(max_length=2500)
Expand Down
73 changes: 41 additions & 32 deletions backend/entities/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from rest_framework import serializers

from content.serializers import LocationSerializer, ResourceSerializer
from events.serializers import EventSerializer

from .models import (
Expand Down Expand Up @@ -38,23 +39,55 @@
# MARK: Main Tables


class GroupTextSerializer(serializers.ModelSerializer[GroupText]):
class Meta:
model = GroupText
fields = "__all__"


class GroupSerializer(serializers.ModelSerializer[Group]):
texts = GroupTextSerializer()
location = LocationSerializer(read_only=True)
events = EventSerializer(many=True, read_only=True)
resources = ResourceSerializer(many=True, read_only=True)

class Meta:
model = Group
extra_kwargs = {
"created_by": {"read_only": True},
}

fields = "__all__"

def validate(self, data: dict[str, Any]) -> dict[str, Any]:
if data.get("terms_checked") is False:
raise serializers.ValidationError(
"You must accept the terms of service to create a group."
)

return data

def create(self, validated_data: dict[str, Any]) -> Group:
group = Group.objects.create(**validated_data)

class OrganizationTextSerializer(serializers.ModelSerializer[OrganizationText]):
# mypy thinks a generic type argument is needed for StringRelatedField.
org_id = serializers.StringRelatedField(source="org_id.id") # type: ignore[var-annotated]
if group:
texts = GroupText.objects.create(group_id=group)
group.texts = texts

return group


class OrganizationTextSerializer(serializers.ModelSerializer[OrganizationText]):
class Meta:
model = OrganizationText
fields = "__all__"


class OrganizationSerializer(serializers.ModelSerializer[Organization]):
org_text = OrganizationTextSerializer(read_only=True)
texts = OrganizationTextSerializer()
location = LocationSerializer(read_only=True)
events = EventSerializer(many=True, read_only=True)
resources = ResourceSerializer(many=True, read_only=True)

class Meta:
model = Organization
Expand All @@ -65,22 +98,7 @@ class Meta:
"acceptance_date": {"read_only": True},
}

fields = [
"id",
"created_by",
"org_name",
"name",
"tagline",
"icon_url",
"location_id",
"get_involved_url",
"terms_checked",
"is_high_risk",
"status",
"status_updated",
"acceptance_date",
"org_text",
]
fields = "__all__"

def validate(self, data: dict[str, Any]) -> dict[str, Any]:
if data.get("terms_checked") is False:
Expand All @@ -91,14 +109,11 @@ def validate(self, data: dict[str, Any]) -> dict[str, Any]:
return data

def create(self, validated_data: dict[str, Any]) -> Organization:
description = validated_data.pop("description", None)
org = Organization.objects.create(**validated_data)

if org and description:
org_text = OrganizationText.objects.create(
org_id=org, description=description
)
org.org_text = org_text
if org:
texts = OrganizationText.objects.create(org_id=org)
org.texts = texts

return org

Expand Down Expand Up @@ -148,12 +163,6 @@ class Meta:
fields = "__all__"


class GroupTextSerializer(serializers.ModelSerializer[GroupText]):
class Meta:
model = GroupText
fields = "__all__"


class GroupTopicSerializer(serializers.ModelSerializer[GroupTopic]):
class Meta:
model = GroupTopic
Expand Down
Loading

0 comments on commit 2728aa2

Please sign in to comment.