Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#938 Expand fixtures to produce human relatable results #977

Merged
merged 7 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ git remote add upstream https://github.com/activist-org/activist.git
# docker compose --env-file .env.dev down
```

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

> [!NOTE]
> Feel free to contact the team in the [Development room on Matrix](https://matrix.to/#/!CRgLpGeOBNwxYCtqmK:matrix.org?via=matrix.org&via=acter.global&via=chat.0x7cd.xyz) if you're having problems getting your environment setup!
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ git remote add upstream https://github.com/activist-org/activist.git
# docker compose --env-file .env.dev down
```

6. You can then visit <http://localhost:3000> to see the development frontend build once the container is up and running.
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.

> [!NOTE]
> Feel free to contact the team in the [Development room on Matrix](https://matrix.to/#/!CRgLpGeOBNwxYCtqmK:matrix.org?via=matrix.org&via=acter.global&via=chat.0x7cd.xyz) if you're having problems getting your environment setup! If you're having issues with Docker and just want to get the frontend or backend up and running, please see [the section on this in the contributing guide](https://github.com/activist-org/activist/blob/main/CONTRIBUTING.md#using-yarn-or-python).
Expand Down
2 changes: 1 addition & 1 deletion backend/authentication/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class UserAdmin(BaseUserAdmin):
add_form = UserCreationForm

# The fields to be used in displaying the User model.
list_display = ["email", "is_admin"]
list_display = ["username", "email", "is_admin"]
list_filter = ["is_admin"]
fieldsets = [
(None, {"fields": ["email", "password"]}),
Expand Down
1 change: 1 addition & 0 deletions backend/authentication/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Meta:

username = factory.Faker("user_name")
name = factory.Faker("name")
location = factory.Faker("city")
description = factory.Faker("text", max_nb_chars=500)
verified = factory.Faker("boolean")
verification_method = factory.Faker("word")
Expand Down
1 change: 1 addition & 0 deletions backend/authentication/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class UserModel(AbstractUser, PermissionsMixin):
username = models.CharField(max_length=255, unique=True)
name = models.CharField(max_length=255, blank=True)
password = models.CharField(max_length=255)
location = models.CharField(max_length=100, blank=True)
description = models.TextField(max_length=500, blank=True)
verified = models.BooleanField(default=False)
verification_method = models.CharField(max_length=30, blank=True)
Expand Down
81 changes: 35 additions & 46 deletions backend/backend/management/commands/populate_db.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import random
from argparse import ArgumentParser
from typing import TypedDict, Unpack

from django.core.management.base import BaseCommand

from authentication.factories import UserFactory
from authentication.factories import UserFactory, UserTopicFactory
from authentication.models import UserModel
from content.models import Topic
from entities.factories import (
GroupFactory,
GroupTextFactory,
Expand All @@ -18,99 +20,86 @@

class Options(TypedDict):
users: int
orgs: int
groups: int
events: int
orgs_per_user: int
groups_per_org: int
events_per_org: int


class Command(BaseCommand):
help = "Populate the database with dummy data"

def add_arguments(self, parser: ArgumentParser) -> None:
parser.add_argument("--users", type=int, default=10)
parser.add_argument("--opu", type=int, default=1) # orgs per user
parser.add_argument("--gpo", type=int, default=1) # groups per org
parser.add_argument("--epo", type=int, default=1) # events per org
parser.add_argument("--orgs-per-user", type=int, default=1)
parser.add_argument("--groups-per-org", type=int, default=1)
parser.add_argument("--events-per-org", type=int, default=1)

def handle(self, *args: str, **options: Unpack[Options]) -> None:
n_users = options.get("users")
n_orgs_per_user = options.get("opu")
n_groups_per_org = options.get("gpo")
n_events_per_org = options.get("epo")
num_users = options["users"]
num_orgs_per_user = options["orgs_per_user"]
num_groups_per_org = options["groups_per_org"]
num_events_per_org = options["events_per_org"]

# Clear all tables before creating new data.
UserModel.objects.exclude(username="admin").delete()
Organization.objects.all().delete()
Group.objects.all().delete()
Event.objects.all().delete()

topics = Topic.objects.all()

try:
users = [
UserFactory(username=f"activist_{i}", name=f"Activist {i}")
for i in range(n_users)
for i in range(num_users)
]

for i, user in enumerate(users):
user_location = "Berlin"
user_topic = "Climate"
for u, user in enumerate(users):
user_topic = random.choice(topics)
UserTopicFactory(user_id=user, topic_id=user_topic)

for _ in range(n_orgs_per_user):
for o in range(num_orgs_per_user):
user_org = OrganizationFactory(
name=f"{user_location} {user_topic} Organization {i}",
name=f"{user_topic.name} Organization (U{u}:O{o})",
created_by=user,
)

OrganizationTextFactory(
org_id=user_org,
iso="en",
primary=True,
description="This is an org",
get_involved="Get involved!",
donate_prompt="Donate!",
)
OrganizationTextFactory(org_id=user_org, iso="wt", primary=True)

for g in range(n_groups_per_org):
for g in range(num_groups_per_org):
user_org_group = GroupFactory(
org_id=user_org,
name=f"{user_location} {user_topic} Group {i}-{g}",
name=f"{user_topic.name} Group (U{u}:O{o}:G{g})",
created_by=user,
)

GroupTextFactory(
group_id=user_org_group,
iso="en",
primary=True,
description="This is a group",
get_involved="Get involved!",
donate_prompt="Donate!",
group_id=user_org_group, iso="en", primary=True
)

for e in range(n_events_per_org):
for e in range(num_events_per_org):
user_org_event = EventFactory(
name=f"{user_location} {user_topic} Event {i}-{e}",
name=f"{user_topic.name} Event (U{u}:O{o}:E{e})",
type=random.choice(["learn", "action"]),
created_by=user,
)

EventTextFactory(
event_id=user_org_event,
iso="en",
primary=True,
description="This is a group",
get_involved="Get involved!",
event_id=user_org_event, iso="en", primary=True
)

self.stdout.write(
self.style.ERROR(
f"Number of users created: {n_users}\n"
f"Number of organizations created: {n_users * n_orgs_per_user}\n"
f"Number of groups created: {n_users * n_orgs_per_user * n_groups_per_org}\n"
f"Number of events created: {n_users * n_orgs_per_user * n_events_per_org}\n"
f"Number of users created: {num_users}\n"
f"Number of organizations created: {num_users * num_orgs_per_user}\n"
f"Number of groups created: {num_users * num_orgs_per_user * num_groups_per_org}\n"
f"Number of events created: {num_users * num_orgs_per_user * num_events_per_org}\n"
)
)

except Exception as error:
except TypeError as error:
self.stdout.write(
self.style.ERROR(
f"An error occurred during the creation of dummy data: {error}"
f"A type error occurred during the creation of dummy data: {error}. Make sure to use dashes for populate_db arguments and that they're of the appropriate types."
)
)
2 changes: 1 addition & 1 deletion backend/backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
"rest_framework.throttling.AnonRateThrottle",
"rest_framework.throttling.UserRateThrottle",
],
"DEFAULT_THROTTLE_RATES": {"anon": "7/min", "user": "10/min"},
"DEFAULT_THROTTLE_RATES": {"anon": "40/min", "user": "60/min"},
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"DEFAULT_PAGINATION_ORDERS_OBJECTS": False,
Expand Down
4 changes: 2 additions & 2 deletions backend/content/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,13 @@ class Meta:
fields = "__all__"

def validate(self, data: Dict[str, Union[str, int]]) -> Dict[str, Union[str, int]]:
if data["active"] is True and data["deprecation_date"] is not None:
if data["active"] is True and data.get("deprecation_date") is not None:
raise serializers.ValidationError(
_("Active topics cannot have a deprecation date."),
code="active_topic_with_deprecation_error",
)

if data["active"] is False and data["deprecation_date"] is None:
if data["active"] is False and data.get("deprecation_date") is None:
raise serializers.ValidationError(
_("Deprecated topics must have a deprecation date."),
code="inactive_topic_no_deprecation_error",
Expand Down
12 changes: 6 additions & 6 deletions backend/entities/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ class Meta:
group_id = factory.SubFactory(GroupFactory)
iso = factory.Faker("word")
primary = factory.Faker("boolean")
description = factory.Faker("text")
get_involved = factory.Faker("text")
donate_prompt = factory.Faker("text")
description = factory.Faker(provider="text", locale="la", max_nb_chars=1000)
get_involved = factory.Faker(provider="text", locale="la")
donate_prompt = factory.Faker(provider="text", locale="la")


class GroupTopicFactory(factory.django.DjangoModelFactory):
Expand Down Expand Up @@ -190,9 +190,9 @@ class Meta:
org_id = factory.SubFactory(OrganizationFactory)
iso = "en"
primary = factory.Faker("boolean")
description = factory.Faker("text")
get_involved = factory.Faker("text")
donate_prompt = factory.Faker("text")
description = factory.Faker(provider="text", locale="la", max_nb_chars=1000)
get_involved = factory.Faker(provider="text", locale="la")
donate_prompt = factory.Faker(provider="text", locale="la")


class OrganizationTopicFactory(factory.django.DjangoModelFactory):
Expand Down
5 changes: 3 additions & 2 deletions backend/entities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.db import models

from authentication import enums
from utils.models import ISO_CHOICES

# MARK: Main Tables

Expand Down Expand Up @@ -129,7 +130,7 @@ def __str__(self) -> str:

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

class OrganizationText(models.Model):
org_id = models.ForeignKey(Organization, on_delete=models.CASCADE)
iso = models.CharField(max_length=2)
iso = models.CharField(max_length=2, choices=ISO_CHOICES)
primary = models.BooleanField(default=False)
description = models.TextField(max_length=2500)
get_involved = models.TextField(max_length=500, blank=True)
Expand Down
4 changes: 3 additions & 1 deletion backend/entities/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,19 @@ def validate(self, data: dict[str, Any]) -> dict[str, Any]:
raise serializers.ValidationError(
"You must accept the terms of service to create an organization."
)
return data

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

return org


Expand Down
Loading
Loading