Skip to content

Conversation

@Saksham-Sirohi
Copy link
Contributor

@Saksham-Sirohi Saksham-Sirohi commented Jul 29, 2025

Fixes google calander starred export failure
Fixes #172

Summary by Sourcery

Support token-based iCal exports for starred sessions to enable Google Calendar integration without forcing user login.

New Features:

  • Generate and validate signed ICS tokens with 15-day expiry for user-specific calendar exports
  • Add an export-tokenized URL route and corresponding ExporterView logic to serve starred sessions via signed tokens

Enhancements:

  • Store and auto-refresh session tokens when they have less than 4 days remaining
  • Update ExporterView to handle token-based access alongside the existing authenticated flow

@sourcery-ai
Copy link

sourcery-ai bot commented Jul 29, 2025

Reviewer's Guide

This PR implements a signed‐token mechanism for “my starred” ICS exports to resolve Google Calendar failures by embedding user‐scoped, expiring tokens in URLs, extending the ExporterView to consume these tokens without requiring a login, managing token issuance and renewal in session, and exposing a new tokenized export route.

Sequence diagram for tokenized ICS export for Google Calendar

sequenceDiagram
    actor User
    participant Browser
    participant ExporterView
    participant Session
    participant GoogleCalendar

    User->>Browser: Clicks 'Export to Google Calendar'
    Browser->>ExporterView: GET /export.my-google-calendar
    ExporterView->>Session: Check for existing token
    alt Token valid and not expiring soon
        ExporterView->>Browser: Respond with webcal:// URL containing token
    else Token missing or expiring soon
        ExporterView->>ExporterView: Generate new token
        ExporterView->>Session: Store new token
        ExporterView->>Browser: Respond with webcal:// URL containing new token
    end
    Browser->>GoogleCalendar: Subscribes using webcal:// URL with token
    GoogleCalendar->>ExporterView: GET /export/schedule-my.ics/<token>/
    ExporterView->>ExporterView: Parse and validate token
    alt Token valid
        ExporterView->>ExporterView: Fetch starred sessions for user
        ExporterView->>GoogleCalendar: Return ICS file
    else Token invalid
        ExporterView->>GoogleCalendar: Return 404
    end
Loading

Entity relationship diagram for tokenized ICS export

erDiagram
    USER ||--o{ SUBMISSIONFAVOURITE : has
    SUBMISSIONFAVOURITE {
        int id
        int user
        int submission_id
    }
    ICS_TOKEN {
        int user_id
        int exp
    }
Loading

Class diagram for updated ExporterView and ScheduleMixin

classDiagram
    class ScheduleMixin {
        +generate_ics_token(user_id)
        +parse_ics_token(token)
        +check_token_expiry(token)
    }
    class ExporterView {
        +get_context_data(**kwargs)
        +get_exporter(public=True)
        +get(request, *args, **kwargs)
    }
    ExporterView --|> ScheduleMixin
Loading

File-Level Changes

Change Details Files
Added utilities for generating and validating signed ICS tokens
  • generate_ics_token method with 15-day expiry
  • parse_ics_token method to extract and verify user_id
  • check_token_expiry method to detect invalid or soon-expiring tokens
src/pretalx/agenda/views/schedule.py
Extended ExporterView to accept and apply tokenized exports
  • Support export-tokenized in get_exporter URL resolution
  • In get(), detect token in kwargs and parse it for “-my” exporters
  • Assign talk_ids from SubmissionFavourite using parsed user_id
src/pretalx/agenda/views/schedule.py
Managed token lifecycle for Google Calendar export links
  • On export.my-google-calendar, check session for an existing token
  • Use check_token_expiry to decide if renewal is needed
  • Generate new token via generate_ics_token and store it in session
  • Build tokenized webcal URL instead of public ICS
src/pretalx/agenda/views/schedule.py
Added tokenized export URL pattern
  • Introduced export/// path named export-tokenized
src/pretalx/agenda/urls.py

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @Saksham-Sirohi - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `src/pretalx/agenda/views/schedule.py:90` </location>
<code_context>
+            return None
+    
+    @staticmethod
+    def check_token_expiry(token):
+        """Check if a token exists and has more than 4 days until expiry
+        
+        Returns:
+        - None if token is invalid
+        - False if token is valid but expiring soon (< 4 days)
+        - True if token is valid and not expiring soon (>= 4 days)
+        """
+        try:
+            value = signing.loads(token, salt="my-starred-ics")
+            expiry_date = timezone.datetime.fromtimestamp(value["exp"], tz=timezone.utc)
+            days_until_expiry = (expiry_date - timezone.now()).days
+            
+            # Token is valid but check if it's expiring soon
+            if days_until_expiry < 4:
+                return False  # Valid but expiring soon
+            return True  # Valid and not expiring soon
+        except Exception:
+            return None  # Invalid token

</code_context>

<issue_to_address>
Token expiry calculation may be inaccurate due to use of .days.

Using .days truncates partial days, which may cause tokens to be flagged as 'expiring soon' prematurely. For more accurate results, use total_seconds() or compare the timedelta directly to timedelta(days=4).
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
    @staticmethod
    def check_token_expiry(token):
        """Check if a token exists and has more than 4 days until expiry

        Returns:
        - None if token is invalid
        - False if token is valid but expiring soon (< 4 days)
        - True if token is valid and not expiring soon (>= 4 days)
        """
        try:
            value = signing.loads(token, salt="my-starred-ics")
            expiry_date = timezone.datetime.fromtimestamp(value["exp"], tz=timezone.utc)
            days_until_expiry = (expiry_date - timezone.now()).days

            # Token is valid but check if it's expiring soon
            if days_until_expiry < 4:
                return False  # Valid but expiring soon
            return True  # Valid and not expiring soon
        except Exception:
            return None  # Invalid token
=======
    @staticmethod
    def check_token_expiry(token):
        """Check if a token exists and has more than 4 days until expiry

        Returns:
        - None if token is invalid
        - False if token is valid but expiring soon (< 4 days)
        - True if token is valid and not expiring soon (>= 4 days)
        """
        try:
            value = signing.loads(token, salt="my-starred-ics")
            expiry_date = timezone.datetime.fromtimestamp(value["exp"], tz=timezone.utc)
            time_until_expiry = expiry_date - timezone.now()

            # Token is valid but check if it's expiring soon
            if time_until_expiry < timedelta(days=4):
                return False  # Valid but expiring soon
            return True  # Valid and not expiring soon
        except Exception:
            return None  # Invalid token
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@mariobehling mariobehling changed the title chore: fixed google calander star sessions fix: Google calendar my starred sessions Jul 30, 2025
@Saksham-Sirohi Saksham-Sirohi requested a review from hongquan July 30, 2025 08:14
@Saksham-Sirohi
Copy link
Contributor Author

Please test the changes. The starred webcal file can now be accessed without authentication or tokens, as intended. This will require verification in a working environment. All other export formats remain unchanged and continue to function as before.

@Saksham-Sirohi Saksham-Sirohi force-pushed the starred-google-calander-fix branch from 8c2864c to 8b7057f Compare July 30, 2025 18:36
@mariobehling mariobehling merged commit 1ff4afa into fossasia:development Jul 31, 2025
3 of 5 checks passed
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.

Add Google to Add to Calendar options

3 participants