Warren Chen eb8307cb3b feat: Implement one-click unsubscribe feature and newsletter campaign management
- Added one-click unsubscribe functionality with token generation and verification.
- Introduced a new model for tracking one-click unsubscribe audits.
- Enhanced newsletter campaign management with the ability to send campaigns immediately.
- Implemented a scheduler for dispatching due newsletter campaigns.
- Updated views and templates to support one-click unsubscribe and campaign previews.
- Added management commands for running the newsletter scheduler.
- Removed obsolete SSL certificate file.
- Updated entrypoint script to handle different application roles.
2026-04-02 02:51:39 +09:00

77 lines
2.7 KiB
Python

from django.test import TestCase
from .newsletter import (
extract_token,
generate_one_click_token,
render_placeholders,
render_newsletter_html,
verify_one_click_token,
)
from .security import decrypt_text, encrypt_text
class NewsletterTemplateTests(TestCase):
def test_render_placeholders_replaces_known_keys(self):
template = "confirm={{confirm_url}} email={{email}} token={{token}}"
rendered = render_placeholders(
template,
{
"confirm_url": "https://example.com/confirm?token=abc",
"email": "demo@example.com",
"token": "abc",
},
)
self.assertEqual(
rendered,
"confirm=https://example.com/confirm?token=abc email=demo@example.com token=abc",
)
def test_extract_token_supports_top_level_and_nested_data(self):
self.assertEqual(extract_token({"token": "t1"}), "t1")
self.assertEqual(extract_token({"data": {"unsubscribe_token": "t2"}}), "t2")
self.assertEqual(extract_token({}), "")
def test_encrypt_decrypt_roundtrip(self):
secret = "mailrelay-secret"
encrypted = encrypt_text(secret)
self.assertTrue(encrypted.startswith("enc1:"))
self.assertNotEqual(encrypted, secret)
self.assertEqual(decrypt_text(encrypted), secret)
def test_one_click_token_roundtrip(self):
token = generate_one_click_token(
subscriber_id="sub-1",
list_id="list-1",
site_id="site-1",
campaign_id="cmp-1",
secret="test-secret",
ttl_seconds=60,
)
payload, error = verify_one_click_token(token, "test-secret")
self.assertIsNone(error)
self.assertEqual(payload["subscriber_id"], "sub-1")
self.assertEqual(payload["list_id"], "list-1")
def test_one_click_token_invalid_signature(self):
token = generate_one_click_token(
subscriber_id="sub-1",
list_id="list-1",
site_id="site-1",
campaign_id="cmp-1",
secret="test-secret",
ttl_seconds=60,
)
payload, error = verify_one_click_token(token, "other-secret")
self.assertIsNone(payload)
self.assertEqual(error, "invalid")
def test_render_newsletter_html_absolutizes_relative_links(self):
rendered = render_newsletter_html(
'<p><a href="/a">A</a><img src="/media/x.jpg"></p>',
values={},
site_base_url="https://news.example.com",
)
self.assertIn('href="https://news.example.com/a"', rendered)
self.assertIn('src="https://news.example.com/media/x.jpg"', rendered)