feat: email notification when receiving private message with opt-out toggle
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
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
- New column: users.notify_email_messages (default true) - Send email via MS Graph when someone receives a private message - Toggle in /konto/prywatnosc to enable/disable email notifications - Email includes message preview, sender name, and direct link Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
576303f1b5
commit
97416ffdc1
@ -777,10 +777,11 @@ def konto_prywatnosc():
|
||||
user.contact_prefer_email = request.form.get('prefer_email') == 'on'
|
||||
user.contact_prefer_phone = request.form.get('prefer_phone') == 'on'
|
||||
user.contact_prefer_portal = request.form.get('prefer_portal') == 'on'
|
||||
user.notify_email_messages = request.form.get('notify_email_messages') == 'on'
|
||||
db.commit()
|
||||
|
||||
logger.info(f"Privacy settings updated for user: {user.email}")
|
||||
flash('Ustawienia prywatnosci zostaly zapisane.', 'success')
|
||||
flash('Ustawienia prywatności zostały zapisane.', 'success')
|
||||
return redirect(url_for('auth.konto_prywatnosc'))
|
||||
|
||||
return render_template('konto/prywatnosc.html',
|
||||
|
||||
@ -14,6 +14,7 @@ from . import bp
|
||||
from database import SessionLocal, User, Company, PrivateMessage, UserNotification, UserBlock, Classified
|
||||
from utils.helpers import sanitize_input
|
||||
from utils.decorators import member_required
|
||||
from email_service import send_email
|
||||
|
||||
|
||||
# ============================================================
|
||||
@ -191,6 +192,36 @@ def messages_send():
|
||||
db.add(notification)
|
||||
db.commit()
|
||||
|
||||
# Send email notification if recipient has it enabled
|
||||
if recipient.notify_email_messages != False and recipient.email:
|
||||
try:
|
||||
message_url = url_for('.messages_view', message_id=message.id, _external=True)
|
||||
settings_url = url_for('auth.konto_prywatnosc', _external=True)
|
||||
subject_line = f'Nowa wiadomość od {sender_name} — Norda Biznes'
|
||||
preview = (content[:200] + '...') if len(content) > 200 else content
|
||||
email_html = f'''
|
||||
<h2>Masz nową wiadomość</h2>
|
||||
<p><strong>{sender_name}</strong> wysłał(a) Ci wiadomość na portalu Norda Biznes.</p>
|
||||
{f'<p><strong>Temat:</strong> {subject}</p>' if subject else ''}
|
||||
<div style="background: #f8fafc; border-left: 4px solid #3b82f6; padding: 16px; margin: 16px 0; border-radius: 4px;">
|
||||
<p style="margin: 0; color: #374151;">{preview}</p>
|
||||
</div>
|
||||
<p><a href="{message_url}" style="display: inline-block; padding: 10px 24px; background: #3b82f6; color: white; text-decoration: none; border-radius: 6px; font-weight: 500;">Odczytaj wiadomość</a></p>
|
||||
<p style="font-size: 12px; color: #9ca3af; margin-top: 24px;">Możesz wyłączyć powiadomienia e-mail w <a href="{settings_url}">ustawieniach prywatności</a>.</p>
|
||||
'''
|
||||
send_email(
|
||||
to=[recipient.email],
|
||||
subject=subject_line,
|
||||
body_text=f'{sender_name} wysłał(a) Ci wiadomość na portalu Norda Biznes. Odczytaj: {message_url}',
|
||||
body_html=email_html,
|
||||
email_type='message_notification',
|
||||
user_id=recipient.id,
|
||||
recipient_name=recipient.name
|
||||
)
|
||||
except Exception as e:
|
||||
import logging
|
||||
logging.getLogger(__name__).warning(f"Failed to send message email notification: {e}")
|
||||
|
||||
flash('Wiadomość wysłana.', 'success')
|
||||
return redirect(url_for('.messages_sent'))
|
||||
finally:
|
||||
|
||||
@ -322,6 +322,9 @@ class User(Base, UserMixin):
|
||||
contact_prefer_portal = Column(Boolean, default=True) # User prefers portal messages
|
||||
contact_note = Column(Text, nullable=True) # Additional note (e.g. best hours)
|
||||
|
||||
# Email notification preferences
|
||||
notify_email_messages = Column(Boolean, default=True) # Email when receiving private message
|
||||
|
||||
# Relationships
|
||||
conversations = relationship('AIChatConversation', back_populates='user', cascade='all, delete-orphan')
|
||||
forum_topics = relationship('ForumTopic', back_populates='author', cascade='all, delete-orphan', primaryjoin='User.id == ForumTopic.author_id')
|
||||
|
||||
16
database/migrations/063_add_notify_email_messages.sql
Normal file
16
database/migrations/063_add_notify_email_messages.sql
Normal file
@ -0,0 +1,16 @@
|
||||
-- Migration 063: Add email notification preference for private messages
|
||||
-- Default TRUE so existing users get notified (they can opt-out)
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'users'
|
||||
AND column_name = 'notify_email_messages'
|
||||
) THEN
|
||||
ALTER TABLE users ADD COLUMN notify_email_messages BOOLEAN DEFAULT TRUE;
|
||||
RAISE NOTICE 'Added notify_email_messages column';
|
||||
ELSE
|
||||
RAISE NOTICE 'notify_email_messages column already exists';
|
||||
END IF;
|
||||
END $$;
|
||||
@ -354,6 +354,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-card">
|
||||
<h2>Powiadomienia e-mail</h2>
|
||||
|
||||
<div class="setting-item">
|
||||
<div class="setting-info">
|
||||
<div class="setting-label">Nowe wiadomości prywatne</div>
|
||||
<div class="setting-description">Otrzymuj e-mail, gdy ktoś wyśle Ci wiadomość prywatną na portalu</div>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" name="notify_email_messages" {% if user.notify_email_messages != False %}checked{% endif %}>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Zapisz ustawienia</button>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user