Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 2 additions & 6 deletions src/thunderbird_accounts/mail/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from thunderbird_accounts.mail.models import Account, Email, Domain
from thunderbird_accounts.mail import tasks as mail_tasks
from thunderbird_accounts.mail import utils
from thunderbird_accounts.subscription.decorators import active_subscription_required


def _critical_errors_from_stale_dns_records(stale_dns_records: list[dict]) -> list[DomainVerificationErrors]:
Expand Down Expand Up @@ -69,16 +70,11 @@ def _capture_domain_exception(exception: Exception, domain: Domain, *, phase: st

@login_required
@require_http_methods(['POST'])
@active_subscription_required(error_message=_('An active subscription is required to set an app password.'))
@sensitive_post_parameters('password')
def app_password_set(request: HttpRequest):
"""Sets an app password for a remote Stalwart account"""

if not request.user.has_active_subscription:
return JsonResponse(
{'success': False, 'error': str(_('An active subscription is required to set an app password.'))},
status=403,
)

try:
data = json.loads(request.body)
new_password = data.get('password')
Expand Down
23 changes: 23 additions & 0 deletions src/thunderbird_accounts/subscription/decorators.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from functools import wraps

from django.conf import settings
from django.http import JsonResponse
from django.utils.translation import gettext_lazy as _

try:
from paddle_billing import Client, Options, Environment
Expand Down Expand Up @@ -30,3 +34,22 @@ def _inject_paddle(*args, **kwargs):
return func(*args, **kwargs)

return _inject_paddle


def active_subscription_required(function=None, *, error_message=None, status=403):
"""Require an authenticated user with an active subscription."""

def decorator(view_func):
@wraps(view_func)
def _view_wrapper(request, *args, **kwargs):
if getattr(request.user, 'has_active_subscription', False):
return view_func(request, *args, **kwargs)

message = error_message or _('An active subscription is required.')
return JsonResponse({'success': False, 'error': str(message)}, status=status)
Comment thread
markstos marked this conversation as resolved.
Outdated

return _view_wrapper

if function:
return decorator(function)
return decorator
Loading