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

added orgs to populate db management command, improved org factory #947

Merged
merged 13 commits into from
Sep 7, 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
33 changes: 30 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ If you have questions or would like to communicate with the team, please [join u
- [Learning the tech stack](#learning-the-tech)
- [Development environment](#dev-env)
- [Style guide](#style-guide)
- [Testing](#testing)
- [Linting](#linting)
- [Issues and projects](#issues-projects)
- [Bug reports](#bug-reports)
Expand Down Expand Up @@ -303,6 +304,35 @@ From there you'll be able to visit http://localhost:6006/ to view the documentat

Please see the [activist style guide](https://github.com/activist-org/activist/blob/main/STYLEGUIDE.md) for details about how to follow the code style for the project. We made these guidelines to assure that we as a community write clean, cohesive code that's easy to write and review. Suggestions for the style guide are welcome.

<a id="testing"></a>

## Testing [`⇧`](#contents)

### Backend

Please run the following commands from the project root to test the backend:

```bash
# Start the Docker container:
docker compose --env-file .env.dev up backend --build -d # -d to hide logs

# Enter the backend container:
docker exec -it django_backend sh

# Run backend tests:
pytest

# Once tests are finished:
exit
```

### Frontend

Running frontend tests locally is currently WIP.

> [!NOTE]
> When working on the frontend, activist recommends manual typechecking. From within the `frontend` directory run `yarn run postinstall` followed by `yarn nuxi typecheck` to confirm your changes are type-safe. Existing TS errors may be ignored. PRs to fix these are always welcome!

<a id="linting"></a>

## Linting [`⇧`](#contents)
Expand Down Expand Up @@ -405,9 +435,6 @@ When making a contribution, adhering to the [GitHub flow](https://docs.github.co
git pull --rebase upstream <dev-branch>
```

> [!NOTE]
> When working on the frontend, activist recommends manual typechecking. From within the `frontend` directory run `yarn run postinstall` followed by `yarn nuxi typecheck` to confirm your changes are type-safe. Existing TS errors may be ignored. PRs to fix these are always welcome!

6. Push your topic branch up to your fork:

```bash
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ git remote add upstream https://github.com/activist-org/activist.git
```bash
docker compose --env-file .env.dev up

# Or with new dependencies:
# Or with new dependencies or backend model changes:
# docker compose --env-file .env.dev up --build

# And to stop the containers when you're done working:
Expand Down
2 changes: 0 additions & 2 deletions backend/authentication/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ def verification_partner(
if not create:
# Simple build, do nothing.
return
if extracted:
pass


# MARK: Bridge Tables
Expand Down
2 changes: 1 addition & 1 deletion backend/authentication/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def create_user(


class SupportEntityType(models.Model):
id = models.IntegerField(primary_key=True)
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=255)

def __str__(self) -> str:
Expand Down
11 changes: 5 additions & 6 deletions backend/authentication/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
import uuid


@pytest.mark.django_db
pytestmark = pytest.mark.django_db


def test_str_methods() -> None:
support_entity_type = SupportEntityTypeFactory.build()
support = SupportFactory.build()
Expand All @@ -41,7 +43,6 @@ def test_str_methods() -> None:
assert str(user_topic) == str(user_topic.id)


@pytest.mark.django_db
def test_signup(client: Client) -> None:
"""
Test the signup function.
Expand Down Expand Up @@ -152,14 +153,13 @@ def test_signup(client: Client) -> None:
assert user.verification_code is None


@pytest.mark.django_db
def test_login(client: Client) -> None:
"""
Test login view.

Scenarios:
1. User that signed up with email, that has not confirmed their email
2. User that signed up with email, confimred email address. Is logged in successfully
2. User that signed up with email, confirmed email address. Is logged in successfully
3. User exists but password is incorrect
4. User does not exists and tries to login
"""
Expand All @@ -174,7 +174,7 @@ def test_login(client: Client) -> None:
)
assert response.status_code == 400

# 2. User that signed up with email, confimred email address. Is logged in successfully
# 2. User that signed up with email, confirmed email address. Is logged in successfully
user.is_confirmed = True
user.save()
response = client.post(
Expand Down Expand Up @@ -204,7 +204,6 @@ def test_login(client: Client) -> None:
assert response.status_code == 400


@pytest.mark.django_db
def test_pwreset(client: Client) -> None:
"""
Test password reset view.
Expand Down
3 changes: 2 additions & 1 deletion backend/backend/custom_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
please check the path: backend/backend/settings.py
"""

# Pagination settings
# MARK: Pagination

PAGINATION_PAGE_SIZE = 20
PAGINATION_MAX_PAGE_SIZE = 100
2 changes: 1 addition & 1 deletion backend/backend/exception_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


def bad_request_logger(exception: Any, context: dict[str, Any]) -> Response | None:
# Get the DRF exception handler standard error response
# Get the DRF exception handler standard error response.
response = exception_handler(exception, context)

if response is not None:
Expand Down
40 changes: 35 additions & 5 deletions backend/backend/management/commands/populate_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,58 @@
from django.core.management.base import BaseCommand

from authentication.factories import UserFactory
from authentication.models import UserModel
from entities.factories import GroupFactory, OrganizationFactory
from entities.models import Group, Organization
from events.factories import EventFactory
from events.models import Event


class Options(TypedDict):
users: int
orgs: int
groups: int
events: int


# ATTN: We're not actually putting texts into the DB.
class Command(BaseCommand):
help = "Populate the database with dummy data"

def add_arguments(self, parser: ArgumentParser) -> None:
parser.add_argument("--users", type=int, default=100)
parser.add_argument("--users", type=int, default=10)
parser.add_argument("--orgs", type=int, default=10)
parser.add_argument("--groups", type=int, default=10)
parser.add_argument("--events", type=int, default=10)

def handle(self, *args: str, **options: Unpack[Options]) -> None:
number_of_users = options["users"]
number_of_users = options.get("users")
number_of_orgs = options.get("orgs")
number_of_groups = options.get("groups")
number_of_events = options.get("events")

# 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()

try:
UserFactory.create_batch(number_of_users)
UserFactory.create_batch(size=number_of_users)
OrganizationFactory.create_batch(size=number_of_orgs)
GroupFactory.create_batch(size=number_of_groups)
EventFactory.create_batch(size=number_of_events)
self.stdout.write(
self.style.ERROR(f"Number of users created: {number_of_users}")
self.style.ERROR(
f"Number of users created: {number_of_users}\n"
f"Number of organizations created: {number_of_orgs}\n"
f"Number of groups created: {number_of_groups}\n"
f"Number of events created: {number_of_events}\n"
)
)
except Exception as error:
self.stdout.write(
self.style.ERROR(
f"An error occured during the creation of dummy data: {error}"
f"An error occurred during the creation of dummy data: {error}"
)
)
2 changes: 1 addition & 1 deletion backend/backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
EMAIL_PORT = os.getenv("EMAIL_PORT")
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD")
EMAIL_USE_TLS = bool(os.getenv("EMAIL_USE_TLS") == "True")
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS") == "True"
# DEVELOPMENT ONLY
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

Expand Down
3 changes: 1 addition & 2 deletions backend/backend/tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@

@pytest.fixture
def api_client() -> APIClient:
client = APIClient()
return client
return APIClient()
20 changes: 15 additions & 5 deletions backend/content/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ class Meta:
url = factory.Faker("url")
is_private = factory.Faker("boolean")
created_by = factory.SubFactory("authentication.factories.UserFactory")
creation_date = factory.LazyFunction(datetime.datetime.now)
last_updated = factory.LazyFunction(datetime.datetime.now)
creation_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)
last_updated = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)


class TaskFactory(factory.django.DjangoModelFactory):
Expand All @@ -35,8 +39,12 @@ class Meta:
name = factory.Faker("word")
description = factory.Faker("text")
tags = factory.List([factory.Faker("word") for _ in range(10)])
creation_date = factory.LazyFunction(datetime.datetime.now)
deletion_date = factory.LazyFunction(datetime.datetime.now)
creation_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)
deletion_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)


class TopicFactory(factory.django.DjangoModelFactory):
Expand All @@ -46,7 +54,9 @@ class Meta:
name = factory.Faker("word")
active = factory.Faker("boolean")
description = factory.Faker("text")
creation_date = factory.LazyFunction(datetime.datetime.now)
creation_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)
deprecation_date = factory.Faker("date")


Expand Down
2 changes: 1 addition & 1 deletion backend/content/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def __str__(self) -> str:


class Tag(models.Model):
id = models.IntegerField(primary_key=True)
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
text = models.CharField(max_length=255)
creation_date = models.DateTimeField(auto_now_add=True)

Expand Down
4 changes: 2 additions & 2 deletions backend/content/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ def validate(self, data: Dict[str, Union[str, int]]) -> Dict[str, Union[str, int
with PilImage.open(data["image_location"]) as img:
img.verify()
img_format = img.format.lower()
except Exception:
except Exception as e:
raise serializers.ValidationError(
_("The image is not valid."), code="corrupted_file"
)
) from e

if img_format not in image_extensions:
raise serializers.ValidationError(
Expand Down
3 changes: 2 additions & 1 deletion backend/content/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@

import pytest

pytestmark = pytest.mark.django_db


@pytest.mark.django_db
def test_str_methods() -> None:
resource = ResourceFactory.build()
task = TaskFactory.build()
Expand Down
40 changes: 35 additions & 5 deletions backend/entities/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,26 @@
class OrganizationFactory(factory.django.DjangoModelFactory):
class Meta:
model = Organization
django_get_or_create = ("created_by",)

name = factory.Faker("word")
tagline = factory.Faker("word")
social_links = factory.List([factory.Faker("word") for _ in range(10)])
social_links = ["https://www.instagram.com/activist_org/"]
# Note: Version that accesses the database so we don't create new each time.
# created_by = factory.LazyAttribute(
# lambda x: (
# UserModel.objects.exclude(username="admin").first()
# if UserModel.objects.exclude(username="admin").exists()
# else factory.SubFactory("authentication.factories.UserFactory")
# )
# )
created_by = factory.SubFactory("authentication.factories.UserFactory")
status = factory.SubFactory("entities.factories.StatusTypeFactory", name="Active")
is_high_risk = factory.Faker("boolean")
location = factory.Faker("city")
acceptance_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)


class GroupFactory(factory.django.DjangoModelFactory):
Expand All @@ -43,9 +57,13 @@ class Meta:
org_id = factory.SubFactory(OrganizationFactory)
name = factory.Faker("word")
tagline = factory.Faker("word")
social_links = factory.List([factory.Faker("word") for _ in range(10)])
social_links = ["https://www.instagram.com/activist_org/"]
created_by = factory.SubFactory("authentication.factories.UserFactory")
creation_date = factory.LazyFunction(datetime.datetime.now)
creation_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)
category = factory.Faker("word")
location = factory.Faker("city")


# MARK: Bridge Tables
Expand Down Expand Up @@ -119,8 +137,12 @@ class Meta:
status = factory.SubFactory(OrganizationApplicationStatusFactory)
orgs_in_favor = factory.List([factory.Faker("word") for _ in range(10)])
orgs_against = factory.List([factory.Faker("word") for _ in range(10)])
creation_date = factory.LazyFunction(datetime.datetime.now)
status_updated = factory.LazyFunction(datetime.datetime.now)
creation_date = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)
status_updated = factory.LazyFunction(
lambda: datetime.datetime.now(tz=datetime.timezone.utc)
)


class OrganizationEventFactory(factory.django.DjangoModelFactory):
Expand Down Expand Up @@ -185,3 +207,11 @@ class Meta:

org_id = factory.SubFactory(OrganizationFactory)
topic_id = factory.SubFactory("content.factories.TopicFactory")


class StatusTypeFactory(factory.django.DjangoModelFactory):
class Meta:
model = "entities.StatusType"
django_get_or_create = ("name",)

name = "Active"
2 changes: 1 addition & 1 deletion backend/entities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def __str__(self) -> str:


class OrganizationApplicationStatus(models.Model):
id = models.IntegerField(primary_key=True)
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
status_name = models.CharField(max_length=255)

def __str__(self) -> str:
Expand Down
Loading
Loading