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

Add header path to shortlinks per new TRAI SMS rules from Oct 1 #2123

Merged
merged 1 commit into from
Oct 4, 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
24 changes: 23 additions & 1 deletion funnel/views/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,20 +718,42 @@ def cleanurl_filter(url: str | furl) -> str:


@app.template_filter('shortlink')
def shortlink(url: str, actor: Account | None = None, shorter: bool = True) -> str:
def shortlink(
url: str,
actor: Account | None = None,
shorter: bool = True,
header: str | None = None,
) -> str:
"""
Return a short link suitable for sharing, in a template filter.

Caller must perform a database commit.

:param url: URL to shorten
:param actor: Optional actor to save against the shortlink
:param shorter: Use a shorter shortlink, ideal for SMS or a small database
:param header: Insert a brand header into the shortlink, for SMS DLT
"""
sl = Shortlink.new(url, reuse=True, shorter=shorter, actor=actor)
db.session.add(sl)
g.require_db_commit = True
if header is not None:
return app_url_for(
shortlinkapp, 'link', name=sl.name, header=header, _external=True
)
return app_url_for(shortlinkapp, 'link', name=sl.name, _external=True)


def sms_shortlink(url: str) -> str:
"""SMS version of :func:`shortlink`.

:param url: URL to shorten
"""
return shortlink(
url, shorter=True, header=app.config.get('SMS_DLT_SHORTURL_HEADER')
)


# MARK: Request/response handlers ------------------------------------------------------


Expand Down
4 changes: 2 additions & 2 deletions funnel/views/notifications/comment_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
Proposal,
)
from ...transports.sms import SmsPriority, SmsTemplate
from ..helpers import shortlink
from ..helpers import sms_shortlink
from ..notification import RenderNotification
from .mixins import TemplateVarMixin

Expand Down Expand Up @@ -252,7 +252,7 @@ def email_content(self) -> str:
)

def sms(self) -> SmsTemplate:
url = shortlink(
url = sms_shortlink(
self.comment.url_for(_external=True, **self.tracking_tags('sms'))
)
if self.document_type == 'comment':
Expand Down
17 changes: 7 additions & 10 deletions funnel/views/notifications/project_starting_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
Session,
)
from ...transports.sms import SmsPriority, SmsTemplate
from ..helpers import shortlink
from ..helpers import sms_shortlink
from ..notification import RenderNotification
from .mixins import TemplateVarMixin

Expand Down Expand Up @@ -117,9 +117,8 @@ def email_content(self) -> str:
def sms(self) -> SmsTemplate:
return ProjectStartingTemplate(
project=self.project,
url=shortlink(
self.project.url_for(_external=True, **self.tracking_tags('sms')),
shorter=True,
url=sms_shortlink(
self.project.url_for(_external=True, **self.tracking_tags('sms'))
),
)

Expand Down Expand Up @@ -156,16 +155,14 @@ def sms(self) -> SmsTemplate:
return ProjectStartingTomorrowVenueTemplate(
account=self.project.account,
venue=venue,
url=shortlink(
self.project.url_for(_external=True, **self.tracking_tags('sms')),
shorter=True,
url=sms_shortlink(
self.project.url_for(_external=True, **self.tracking_tags('sms'))
),
)
return ProjectStartingTomorrowLocationTemplate(
account=self.project.account,
location=self.project.location,
url=shortlink(
self.project.url_for(_external=True, **self.tracking_tags('sms')),
shorter=True,
url=sms_shortlink(
self.project.url_for(_external=True, **self.tracking_tags('sms'))
),
)
12 changes: 5 additions & 7 deletions funnel/views/notifications/proposal_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
sa_orm,
)
from ...transports.sms import SmsPriority, SmsTemplate
from ..helpers import shortlink
from ..helpers import sms_shortlink
from ..notification import RenderNotification
from .mixins import TemplateVarMixin

Expand Down Expand Up @@ -110,9 +110,8 @@ def sms(self) -> ProposalReceivedTemplate:
return ProposalReceivedTemplate(
project=self.project,
actor=self.proposal.first_user,
url=shortlink(
self.proposal.url_for(_external=True, **self.tracking_tags('sms')),
shorter=True,
url=sms_shortlink(
self.proposal.url_for(_external=True, **self.tracking_tags('sms'))
),
)

Expand Down Expand Up @@ -152,8 +151,7 @@ def email_content(self) -> str:
def sms(self) -> ProposalSubmittedTemplate:
return ProposalSubmittedTemplate(
project=self.proposal.project,
url=shortlink(
self.proposal.url_for(_external=True, **self.tracking_tags('sms')),
shorter=True,
url=sms_shortlink(
self.proposal.url_for(_external=True, **self.tracking_tags('sms'))
),
)
6 changes: 3 additions & 3 deletions funnel/views/notifications/rsvp_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
)
from ...transports import email
from ...transports.sms import SmsPriority, SmsTemplate
from ..helpers import shortlink
from ..helpers import sms_shortlink
from ..notification import RenderNotification
from ..schedule import schedule_ical
from .mixins import TemplateVarMixin
Expand Down Expand Up @@ -128,8 +128,8 @@ def sms(
) -> RegistrationConfirmationTemplate | RegistrationConfirmationWithNextTemplate:
project = self.rsvp.project
next_at = project.next_starting_at()
url = shortlink(
project.url_for(_external=True, **self.tracking_tags('sms')), shorter=True
url = sms_shortlink(
project.url_for(_external=True, **self.tracking_tags('sms'))
)
if next_at:
return RegistrationConfirmationWithNextTemplate(
Expand Down
12 changes: 5 additions & 7 deletions funnel/views/notifications/update_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from ...models import Account, Project, ProjectUpdateNotification, Update
from ...transports.sms import SmsPriority, SmsTemplate
from ..helpers import shortlink
from ..helpers import sms_shortlink
from ..notification import RenderNotification
from .mixins import TemplateVarMixin

Expand Down Expand Up @@ -90,16 +90,14 @@ def sms(self) -> UpdateMergedTitleTemplate | UpdateSplitTitleTemplate:
if len(self.update.project.title_parts) == 1:
return UpdateMergedTitleTemplate(
project=self.update.project,
url=shortlink(
self.update.url_for(_external=True, **self.tracking_tags('sms')),
shorter=True,
url=sms_shortlink(
self.update.url_for(_external=True, **self.tracking_tags('sms'))
),
)
return UpdateSplitTitleTemplate(
project_title=self.update.project,
account_title=self.update.project.account,
url=shortlink(
self.update.url_for(_external=True, **self.tracking_tags('sms')),
shorter=True,
url=sms_shortlink(
self.update.url_for(_external=True, **self.tracking_tags('sms'))
),
)
13 changes: 8 additions & 5 deletions funnel/views/shortlink.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

from __future__ import annotations

from datetime import datetime, timedelta
from datetime import timedelta

from flask import abort, redirect

from coaster.utils import utcnow

from .. import app, shortlinkapp, unsubscribeapp
from ..models import Shortlink
from ..typing import Response
Expand All @@ -18,8 +20,9 @@ def shortlink_index() -> Response:
return redirect(app_url_for(app, 'index'), 301)


@shortlinkapp.route('/<name>')
def link(name: str) -> Response:
@shortlinkapp.route('/<header>/<name>') # 'header' is required for SMS DLT URLs
@shortlinkapp.route('/<name>', defaults={'header': None})
def link(name: str, header: str | None = None) -> Response: # noqa: ARG001
"""Redirect from a shortlink to the full link."""
sl = Shortlink.get(name, True)
if sl is None:
Expand All @@ -29,10 +32,10 @@ def link(name: str) -> Response:
response = redirect(str(sl.url), 301)
response.cache_control.private = True
response.cache_control.max_age = 90
response.expires = datetime.utcnow() + timedelta(seconds=90)
response.expires = utcnow() + timedelta(seconds=90)

# These two borrowed from Bitly and TinyURL's response headers. They tell the
# browser to reproduce the HTTP Referer header that was sent to this endpoint, to
# browser to reproduce the HTTP `Referer` header that was sent to this endpoint, to
# send it again to the destination URL

# Needs Werkzeug >= 2.0.2
Expand Down
1 change: 1 addition & 0 deletions sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ FLASK_SMS_TWILIO_FROM=null

#: DLT registered entity id and template ids (required for SMS to Indian numbers)
FLASK_SMS_DLT_ENTITY_ID=null
FLASK_SMS_DLT_SHORTURL_HEADER=null
FLASK_SMS_DLT_TEMPLATE_IDS__web_otp_template=null
FLASK_SMS_DLT_TEMPLATE_IDS__project_starting_template=null
FLASK_SMS_DLT_TEMPLATE_IDS__project_starting_tomorrow_venue_template=null
Expand Down
Loading