Skip to content

push notifications#8

Open
gnunixon wants to merge 5 commits intoinfraguys:masterfrom
gnunixon:feature/push-notifications
Open

push notifications#8
gnunixon wants to merge 5 commits intoinfraguys:masterfrom
gnunixon:feature/push-notifications

Conversation

@gnunixon
Copy link
Copy Markdown

No description provided.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @gnunixon, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces comprehensive support for push notifications within the system. It establishes new data models for managing device installations and their delivery statuses, integrates with Firebase Cloud Messaging (FCM) for sending notifications, and provides API endpoints for users to register and update their device information. This enhancement enables the system to send targeted and dynamic push notifications to users across various platforms.

Highlights

  • Push Notification Statuses: Introduced a new PushDeliveryStatus enum to standardize the tracking of push notification delivery outcomes, including success, permanent failure, and retryable failure states.
  • Device Installation Management: Implemented an Installation model to store user device details necessary for push notifications, such as installation_id, user_id, push_token, platform, and last_seen_at. An InstallationController was also added to manage these records via API, allowing for creation and intelligent updates of existing installations.
  • Firebase Cloud Messaging (FCM) Integration: Developed an FCMProtocol to handle sending push notifications through Firebase Cloud Messaging. This includes logic for constructing FCM payloads, sending messages to individual tokens, processing batch results, and categorizing delivery errors into permanent or retryable failures based on FCM error codes.
  • Templated Push Content: Added RenderedPushContent and PushContent models to define and render dynamic push notification content, supporting Jinja2 templating for title, body, and data fields.
Changelog
  • genesis_notification/common/constants.py
    • Added PushDeliveryStatus enum for tracking notification delivery states.
  • genesis_notification/dm/models.py
    • Added dataclass and requests imports.
    • Imported PushDeliveryStatus from constants.
    • Introduced Installation model for device registration.
    • Defined FCM_PERMANENT_ERRORS and FCM_RETRYABLE_ERRORS sets.
    • Created PushDeliveryResult and PushBatchResult dataclasses for delivery outcomes.
    • Implemented FCMProtocol for Firebase Cloud Messaging integration, including methods for sending, batch processing, and error handling.
    • Added FCMProtocol to the Provider's selectable types.
    • Introduced RenderedPushContent and PushContent models for templated push notification content.
    • Added PushContent to the Template's selectable content types.
  • genesis_notification/user_api/api/controllers.py
    • Added datetime and genesis_notification.common.constants imports.
    • Created InstallationController to manage Installation resources, including logic to update existing installations or create new ones.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces push notification capabilities by adding an FCM provider, device installation tracking, and the necessary API endpoints. While the feature is a valuable addition, the current implementation has several critical issues that must be addressed. These include a major security vulnerability in credential storage, incomplete placeholder code that will cause runtime failures, and bugs related to undefined methods and model attributes. Additionally, there are significant opportunities for performance improvements in batch processing and database interactions. I've left detailed comments on these points.

Comment on lines +155 to +158
service_account_json = properties.property(
types.String(),
required=True,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

Storing the service_account_json as a plain string is a critical security vulnerability. This JSON contains sensitive credentials, including private keys. If the database is compromised, these credentials will be exposed. Credentials should be stored in a secure secret manager (like AWS Secrets Manager, HashiCorp Vault, etc.) and referenced here by an identifier, not stored directly.

Comment on lines +73 to +75
existing.app_version = resource.get("app_version", "")
existing.os_version = resource.get("os_version", "")
existing.device_model = resource.get("device_model", "")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

The Installation model does not have app_version, os_version, or device_model attributes. Attempting to set them here will cause an AttributeError at runtime. You should either add these fields to the Installation model in genesis_notification/dm/models.py or remove these lines.

Comment on lines +232 to +243
def _process_batch_result(self, batch_result):

for r in batch_result.permanent_failures():

inst = Installation.objects.get_one(
filters={"installation_id": r.installation_id}
)

if inst:
inst.status = c.AlwaysActiveStatus.INACTIVE.value
inst.save()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This method executes a database query for each permanently failed installation within a loop, which is inefficient (N+1 query problem). This should be optimized to use a single query to fetch all relevant installations and then update them. A bulk update operation would be even more efficient if your ORM supports it.

Suggested change
def _process_batch_result(self, batch_result):
for r in batch_result.permanent_failures():
inst = Installation.objects.get_one(
filters={"installation_id": r.installation_id}
)
if inst:
inst.status = c.AlwaysActiveStatus.INACTIVE.value
inst.save()
def _process_batch_result(self, batch_result):
failures = batch_result.permanent_failures()
if not failures:
return
failed_installation_ids = [r.installation_id for r in failures]
# Assuming the ORM supports an IN filter and bulk updates.
# This is an example of how it could be optimized.
Installation.objects.filter(
installation_id__in=failed_installation_ids
).update(status=c.AlwaysActiveStatus.INACTIVE.value)

Comment on lines +537 to +540
data={
k: jinja2.Template(str(v)).render(**params)
for k, v in self.data.items()
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The use of str(v) to convert all data values to strings before templating can lead to loss of data types and unexpected behavior, especially for booleans and numbers. It's better to only template values that are already strings and pass other types through as-is.

Suggested change
data={
k: jinja2.Template(str(v)).render(**params)
for k, v in self.data.items()
},
data={
k: jinja2.Template(v).render(**params) if isinstance(v, str) else v
for k, v in self.data.items()
},

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant