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

Updates outputs from the backend to camelCase for easy ingestion #1004

Merged
merged 11 commits into from
Nov 13, 2024
Merged
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ git remote add upstream https://github.com/activist-org/activist.git
4. Start your docker images with the following:

```bash
# --build only necessary with new dependencies or backend model changes
# --build only necessary 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
4 changes: 4 additions & 0 deletions backend/authentication/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ class Meta:
# MARK: Methods


class DeleteUserResponseSerializer(serializers.Serializer):
message = serializers.CharField(max_length=200)


class SignupSerializer(serializers.ModelSerializer[UserModel]):
password_confirmed = serializers.CharField(write_only=True)

Expand Down
2 changes: 2 additions & 0 deletions backend/authentication/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
UserTopic,
)
from .serializers import (
DeleteUserResponseSerializer,
LoginSerializer,
PasswordResetSerializer,
SignupSerializer,
Expand Down Expand Up @@ -239,6 +240,7 @@ def post(self, request: Request) -> Response:
class DeleteUserView(APIView):
queryset = UserModel.objects.all()
permission_classes = (IsAuthenticated,)
serializer_class = DeleteUserResponseSerializer

def delete(self, request: Request, pk: UUID | str) -> Response:
user = UserModel.objects.get(pk=pk)
Expand Down
54 changes: 41 additions & 13 deletions backend/backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
django_stubs_ext.monkeypatch(extra_classes=(viewsets.ModelViewSet,))
dotenv.load_dotenv()

# MARK: DB

DATABASE_HOST = os.getenv("DATABASE_HOST")
DATABASE_NAME = os.getenv("DATABASE_NAME")
Expand All @@ -45,26 +46,29 @@
"DJANGO_CSRF_TRUSTED_ORIGINS", "http://localhost"
).split(" ")

# Application definition
# MARK: Apps

INSTALLED_APPS = [
"rest_framework",
"rest_framework.authtoken",
"corsheaders",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"djangorestframework_camel_case",
"drf_spectacular",
"rest_framework",
"rest_framework.authtoken",
"backend",
"authentication",
"entities",
"content",
"events",
"drf_spectacular",
"corsheaders",
]

# MARK: Middleware

MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
Expand All @@ -75,14 +79,19 @@
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
"djangorestframework_camel_case.middleware.CamelCaseMiddleWare",
]

# MARK: URLs

CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
]

ROOT_URLCONF = "backend.urls"

# MARK: Templates

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
Expand All @@ -100,7 +109,7 @@
]


# Database
# MARK: Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {
Expand All @@ -115,7 +124,7 @@
}


# Password validation
# MARK: Pass Validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
Expand All @@ -135,7 +144,7 @@

AUTH_USER_MODEL = "authentication.UserModel"

# Internationalization
# MARK: I18n
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = "en-us"
Expand All @@ -147,18 +156,18 @@
USE_TZ = True


# Static files (CSS, JavaScript, Images)
# MARK: Static Files
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_ROOT = BASE_DIR / "static/"
STATIC_URL = "static/"

# Default primary key field type
# MARK: Primary Key
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# Email Settings
# MARK: Email
# https://docs.djangoproject.com/en/5.0/topics/email/

EMAIL_HOST = os.getenv("EMAIL_HOST")
Expand All @@ -169,6 +178,8 @@
# DEVELOPMENT ONLY
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

# MARK: REST Framework

REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": [
"rest_framework.throttling.AnonRateThrottle",
Expand All @@ -183,19 +194,36 @@
"rest_framework.authentication.TokenAuthentication",
],
"EXCEPTION_HANDLER": "backend.exception_handler.bad_request_logger",
"DEFAULT_RENDERER_CLASSES": (
"djangorestframework_camel_case.render.CamelCaseJSONRenderer",
"djangorestframework_camel_case.render.CamelCaseBrowsableAPIRenderer",
),
"DEFAULT_PARSER_CLASSES": (
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@to-sta, this is where I have the parser classes being defined as in the djangorestframework-camel-case docs, but we're still getting snake_case in responses in the frontend.

"djangorestframework_camel_case.parser.CamelCaseFormParser",
"djangorestframework_camel_case.parser.CamelCaseMultiPartParser",
"djangorestframework_camel_case.parser.CamelCaseJSONParser",
),
}

# MARK: Spectacular

SPECTACULAR_SETTINGS = {
"TITLE": "activist.org API",
"DESCRIPTION": "Open-source, nonprofit activism platform",
"DESCRIPTION": "An open-source activism platform",
"VERSION": "0.1.0",
"SERVE_INCLUDE_SCHEMA": False,
"CAMELIZE_NAMES": False,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see another comment where you noted you were still getting snake_case responses. Could this have something to do with it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good check :) This is specifically for the table names within the Swagger UI, not the results of the backend itself. Keeping the table names snake_case makes sense to me as they should have consistent identifiers.

"POSTPROCESSING_HOOKS": [
"drf_spectacular.hooks.postprocess_schema_enums",
"drf_spectacular.contrib.djangorestframework_camel_case.camelize_serializer_fields",
],
"SWAGGER_UI_FAVICON_HREF": "https://github.com/activist-org/activist/blob/main/backend/static/swagger_favicon.png?raw=true",
}

# Workaround #471 / monkeypatch() is overriding the REST_FRAMEWORK dict.
api_settings.reload()

# Logging Configuration
# MARK: Logging
# https://docs.djangoproject.com/en/4.2/topics/logging/

LOGGING = {
Expand Down
1 change: 1 addition & 0 deletions backend/entities/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Meta:
name = factory.Faker("word")
tagline = factory.Faker("word")
social_links = ["https://www.instagram.com/activist_org/"]
get_involved_url = "https://activist.org/"
created_by = factory.SubFactory("authentication.factories.UserFactory")
terms_checked = factory.Faker("boolean")
status = factory.SubFactory("entities.factories.StatusTypeFactory", name="Active")
Expand Down
2 changes: 1 addition & 1 deletion backend/entities/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Meta:


class OrganizationTextSerializer(serializers.ModelSerializer[OrganizationText]):
orgID = serializers.StringRelatedField(source="org_id.id")
org_id = serializers.StringRelatedField(source="org_id.id")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I needed to ignore a mypy type warning here in my PR


class Meta:
model = OrganizationText
Expand Down
8 changes: 4 additions & 4 deletions backend/requirements-dev.in
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# In order to add, delete or modify a dependency, please update
# the reference here and then run:
# the reference here and then the following in ./backend:
#
# - `pip-compile --rebuild requirements.in`
# - `pip-compile --rebuild requirements-dev.in`
# - pip-compile --rebuild requirements.in
# - pip-compile --rebuild requirements-dev.in
#
# Make sure we use production deps for constraining installed dev packages. This
# is important as otherwise we could be running tests with different versions
# than production.
#

-r requirements.txt

factory-boy
Expand Down
2 changes: 2 additions & 0 deletions backend/requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ djangorestframework==3.15.2
# via
# -r requirements.txt
# drf-spectacular
djangorestframework-camel-case==1.4.2
# via -r requirements.txt
djangorestframework-stubs==3.14.4
# via -r requirements.txt
drf-spectacular==0.26.5
Expand Down
8 changes: 4 additions & 4 deletions backend/requirements.in
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# In order to add, delete or modify a dependency, please update
# the reference here and then run:
#
# - `pip-compile --rebuild requirements.in`
# - `pip-compile --rebuild requirements-dev.in`
# the reference here and then run the following in ./backend:
#
# - pip-compile --rebuild requirements.in
# - pip-compile --rebuild requirements-dev.in

Django
django-cors-headers
django-stubs
django-stubs-ext
djangorestframework
djangorestframework-camel-case
djangorestframework-stubs
drf-spectacular
gunicorn
Expand Down
2 changes: 2 additions & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ djangorestframework==3.15.2
# via
# -r requirements.in
# drf-spectacular
djangorestframework-camel-case==1.4.2
# via -r requirements.in
djangorestframework-stubs==3.14.4
# via -r requirements.in
drf-spectacular==0.26.5
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/EmptyState.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
class="flex w-full flex-col items-center bg-light-layer-0 text-light-text dark:bg-dark-layer-0 dark:text-dark-text"
>
<PageContent
:imgURL="BOOTSTRAP_CLOUD_MOON_URL"
:imgUrl="BOOTSTRAP_CLOUD_MOON_URL"
imgAltText="components.empty_state.img_alt_text"
>
<div>
Expand Down
14 changes: 7 additions & 7 deletions frontend/components/card/CardConnect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ const props = defineProps<{
}>();

const { userIsSignedIn } = useUser();
const paramsID = useRoute().params.id;
const paramsIDGroup = useRoute().params.groupID;
const paramsId = useRoute().params.id;
const paramsIdGroup = useRoute().params.groupId;

const id = typeof paramsID === "string" ? paramsID : undefined;
const idGroup = typeof paramsIDGroup === "string" ? paramsIDGroup : undefined;
const id = typeof paramsId === "string" ? paramsId : undefined;
const idGroup = typeof paramsIdGroup === "string" ? paramsIdGroup : undefined;

const organizationStore = useOrganizationStore();
const groupStore = useGroupStore();
Expand All @@ -135,13 +135,13 @@ let group: Group;
let event: Event;

if (props.pageType == "organization") {
await organizationStore.fetchByID(id);
await organizationStore.fetchById(id);
organization = organizationStore.organization;
} else if (props.pageType == "group") {
await groupStore.fetchByID(idGroup);
await groupStore.fetchById(idGroup);
group = groupStore.group;
} else if (props.pageType == "event") {
await eventStore.fetchByID(id);
await eventStore.fetchById(id);
event = eventStore.event;
}

Expand Down
6 changes: 3 additions & 3 deletions frontend/components/card/CardDocsEntry.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
<img
v-if="$colorMode.value == 'light'"
:class="imgDimensions"
:src="imgURL + '_' + 'dark.png'"
:src="imgUrl + '_' + 'dark.png'"
:alt="$t(imgAltText)"
/>
<img
v-else
:class="imgDimensions"
:src="imgURL + '_' + 'light.png'"
:src="imgUrl + '_' + 'light.png'"
:alt="$t(imgAltText)"
/>
</div>
Expand All @@ -34,7 +34,7 @@ const localPath = useLocalePath();

defineProps<{
url: string;
imgURL: string;
imgUrl: string;
imgDimensions: string;
imgAltText: string;
title: string;
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/card/CardOrgApplicationVote.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class="mr-5 fill-light-text dark:fill-dark-text"
>
<Icon
v-if="organization.iconURL === undefined"
v-if="organization.iconUrl === undefined"
name="IconOrganization"
size="3em"
/>
Expand All @@ -16,7 +16,7 @@
class="rounded border border-light-section-div dark:border-dark-section-div"
>
<img
:src="organization.iconURL"
:src="organization.iconUrl"
class="h-full w-12"
:alt="
$t('_global.entity_logo', {
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/card/about/CardAboutEvent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const idParam = useRoute().params.id;
const id = typeof idParam === "string" ? idParam : undefined;

const eventStore = useEventStore();
await eventStore.fetchByID(id);
await eventStore.fetchById(id);

const { event } = eventStore;

Expand Down
2 changes: 1 addition & 1 deletion frontend/components/card/about/CardAboutGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const idParam = useRoute().params.id;
const id = typeof idParam === "string" ? idParam : undefined;

const groupStore = useGroupStore();
await groupStore.fetchByID(id);
await groupStore.fetchById(id);

const { group } = groupStore;

Expand Down
2 changes: 1 addition & 1 deletion frontend/components/card/about/CardAboutOrganization.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const idParam = useRoute().params.id;
const id = typeof idParam === "string" ? idParam : undefined;

const organizationStore = useOrganizationStore();
await organizationStore.fetchByID(id);
await organizationStore.fetchById(id);

const { organization } = organizationStore;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
/>
<div class="flex space-x-2 pt-2 lg:absolute lg:right-0 lg:pt-0">
<BtnRouteInternal
v-if="group.getInvolvedURL"
v-if="group.getInvolvedUrl"
:cta="true"
:linkTo="group.getInvolvedURL"
:linkTo="group.getInvolvedUrl"
label="_global.join_group"
fontSize="sm"
:rightIcon="IconMap.ARROW_RIGHT"
Expand Down
Loading
Loading