Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
199 lines
6.2 KiB
Python
199 lines
6.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Send Portal Message
|
|
====================
|
|
|
|
Send a message through the NordaBiznes conversation system using the application layer.
|
|
Creates conversation if needed (with 1:1 dedup), sends message, triggers email notification.
|
|
|
|
Usage:
|
|
DATABASE_URL=... python3 scripts/send_portal_message.py \
|
|
--from-user-id 1 \
|
|
--to-user-id 38 \
|
|
--message "Treść wiadomości"
|
|
|
|
# Or with HTML content from file:
|
|
DATABASE_URL=... python3 scripts/send_portal_message.py \
|
|
--from-user-id 1 \
|
|
--to-user-id 38 \
|
|
--message-file message.html
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import argparse
|
|
from datetime import datetime
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from database import (
|
|
SessionLocal, User, Conversation, ConversationMember, ConvMessage,
|
|
)
|
|
|
|
|
|
def find_or_create_conversation(db, from_user_id, to_user_id):
|
|
"""Find existing 1:1 conversation or create a new one."""
|
|
# Look for existing 1:1 conversation between these two users
|
|
from_convs = db.query(ConversationMember.conversation_id).filter_by(user_id=from_user_id).subquery()
|
|
to_convs = db.query(ConversationMember.conversation_id).filter_by(user_id=to_user_id).subquery()
|
|
|
|
existing = db.query(Conversation).filter(
|
|
Conversation.id.in_(db.query(from_convs.c.conversation_id)),
|
|
Conversation.id.in_(db.query(to_convs.c.conversation_id)),
|
|
Conversation.is_group == False,
|
|
).first()
|
|
|
|
if existing:
|
|
print(f" Existing conversation found: ID {existing.id}")
|
|
return existing
|
|
|
|
# Create new conversation
|
|
conv = Conversation(
|
|
is_group=False,
|
|
owner_id=from_user_id,
|
|
created_at=datetime.now(),
|
|
updated_at=datetime.now(),
|
|
)
|
|
db.add(conv)
|
|
db.flush()
|
|
|
|
db.add(ConversationMember(
|
|
conversation_id=conv.id,
|
|
user_id=from_user_id,
|
|
role='owner',
|
|
joined_at=datetime.now(),
|
|
))
|
|
db.add(ConversationMember(
|
|
conversation_id=conv.id,
|
|
user_id=to_user_id,
|
|
role='member',
|
|
joined_at=datetime.now(),
|
|
))
|
|
db.flush()
|
|
|
|
print(f" New conversation created: ID {conv.id}")
|
|
return conv
|
|
|
|
|
|
def send_message(db, conv, sender_id, content):
|
|
"""Send a message in a conversation."""
|
|
msg = ConvMessage(
|
|
conversation_id=conv.id,
|
|
sender_id=sender_id,
|
|
content=content,
|
|
created_at=datetime.now(),
|
|
)
|
|
db.add(msg)
|
|
db.flush()
|
|
|
|
conv.last_message_id = msg.id
|
|
conv.updated_at = msg.created_at
|
|
|
|
print(f" Message sent: ID {msg.id}, {len(content)} chars")
|
|
return msg
|
|
|
|
|
|
def send_email_notification(db, sender, recipient, conv, msg):
|
|
"""Send email notification to recipient."""
|
|
try:
|
|
from email_service import send_email, build_message_notification_email
|
|
import re
|
|
|
|
if not recipient.email:
|
|
print(f" Email: skipped (no email for {recipient.name})")
|
|
return
|
|
|
|
# Check if user has email notifications enabled
|
|
if hasattr(recipient, 'notify_email_messages') and recipient.notify_email_messages == False:
|
|
print(f" Email: skipped (notifications disabled for {recipient.name})")
|
|
return
|
|
|
|
sender_name = sender.name or sender.email.split('@')[0]
|
|
preview = re.sub(r'<[^>]+>', '', msg.content or '').strip()[:200]
|
|
subject_line = f'Nowa wiadomość od {sender_name} — Norda Biznes'
|
|
|
|
# Build URL
|
|
message_url = f'https://nordabiznes.pl/wiadomosci?conv={conv.id}'
|
|
settings_url = 'https://nordabiznes.pl/konto/prywatnosc'
|
|
|
|
email_html, email_text = build_message_notification_email(
|
|
sender_name=sender_name,
|
|
subject='Nowa wiadomość',
|
|
content_preview=preview,
|
|
message_url=message_url,
|
|
settings_url=settings_url,
|
|
)
|
|
|
|
send_email(
|
|
to=[recipient.email],
|
|
subject=subject_line,
|
|
body_text=email_text,
|
|
body_html=email_html,
|
|
email_type='message_notification',
|
|
user_id=recipient.id,
|
|
recipient_name=recipient.name,
|
|
)
|
|
print(f" Email: sent to {recipient.email}")
|
|
|
|
except Exception as e:
|
|
print(f" Email: failed ({e})")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Send portal message')
|
|
parser.add_argument('--from-user-id', type=int, required=True, help='Sender user ID')
|
|
parser.add_argument('--to-user-id', type=int, required=True, help='Recipient user ID')
|
|
parser.add_argument('--message', type=str, help='Message content (HTML)')
|
|
parser.add_argument('--message-file', type=str, help='File with message content (HTML)')
|
|
parser.add_argument('--no-email', action='store_true', help='Skip email notification')
|
|
parser.add_argument('--dry-run', action='store_true', help='Show what would be done')
|
|
args = parser.parse_args()
|
|
|
|
if not args.message and not args.message_file:
|
|
parser.error('Provide --message or --message-file')
|
|
|
|
content = args.message
|
|
if args.message_file:
|
|
with open(args.message_file) as f:
|
|
content = f.read()
|
|
|
|
db = SessionLocal()
|
|
try:
|
|
sender = db.query(User).get(args.from_user_id)
|
|
recipient = db.query(User).get(args.to_user_id)
|
|
|
|
if not sender:
|
|
print(f"ERROR: Sender user ID {args.from_user_id} not found")
|
|
sys.exit(1)
|
|
if not recipient:
|
|
print(f"ERROR: Recipient user ID {args.to_user_id} not found")
|
|
sys.exit(1)
|
|
|
|
print(f"From: {sender.name} ({sender.email})")
|
|
print(f"To: {recipient.name} ({recipient.email})")
|
|
print(f"Message: {len(content)} chars")
|
|
|
|
if args.dry_run:
|
|
print("\n=== DRY RUN — no changes made ===")
|
|
return
|
|
|
|
conv = find_or_create_conversation(db, args.from_user_id, args.to_user_id)
|
|
msg = send_message(db, conv, args.from_user_id, content)
|
|
db.commit()
|
|
|
|
if not args.no_email:
|
|
send_email_notification(db, sender, recipient, conv, msg)
|
|
|
|
print(f"\nDone. Conversation ID: {conv.id}, Message ID: {msg.id}")
|
|
|
|
except Exception as e:
|
|
db.rollback()
|
|
print(f"ERROR: {e}")
|
|
sys.exit(1)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|