feat: add user engagement tracking (login_count, last_active_at, page_views_count)
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 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-03-13 19:08:45 +01:00
parent ace9c15cd7
commit 825c79c399
4 changed files with 43 additions and 3 deletions

17
app.py
View File

@ -617,10 +617,12 @@ def check_geoip():
@app.before_request
def update_last_active():
"""Update last_login periodically (every 5 min) so profile shows fresh activity."""
"""Update last_active_at and page_views_count for engagement tracking."""
if not current_user.is_authenticated:
return
if request.path.startswith('/static') or request.path == '/health':
if request.path.startswith('/static') or request.path == '/health' or request.path == '/favicon.ico':
return
if request.path.startswith('/api'):
return
from flask import session as flask_session
import time
@ -629,11 +631,15 @@ def update_last_active():
if now - last_update < 300: # 5 minutes
return
flask_session['_last_active_update'] = now
# Count page views in session, flush to DB every 5 min
pv = flask_session.get('_pv_buffer', 0)
flask_session['_pv_buffer'] = 0
try:
db = SessionLocal()
user = db.query(User).filter_by(id=current_user.id).first()
if user:
user.last_login = datetime.now()
user.last_active_at = datetime.now()
user.page_views_count = (user.page_views_count or 0) + pv
db.commit()
db.close()
except Exception:
@ -663,6 +669,11 @@ def track_page_view():
if request.path == '/favicon.ico':
return
# Buffer page views for authenticated users (flushed in update_last_active)
if current_user.is_authenticated:
from flask import session as flask_session
flask_session['_pv_buffer'] = flask_session.get('_pv_buffer', 0) + 1
try:
session_db_id = get_or_create_analytics_session()
if not session_db_id:

View File

@ -380,6 +380,7 @@ def login():
# No 2FA - login directly
login_user(user, remember=remember)
user.last_login = datetime.now()
user.login_count = (user.login_count or 0) + 1
_auto_link_person(db, user)
# Log successful login to audit
@ -478,6 +479,7 @@ def verify_2fa():
login_user(user, remember=remember)
session['2fa_verified'] = True
user.last_login = datetime.now()
user.login_count = (user.login_count or 0) + 1
_auto_link_person(db, user)
# Log successful 2FA login to audit
@ -1251,6 +1253,7 @@ def verify_email(token):
if not current_user.is_authenticated:
login_user(user, remember=True)
user.last_login = datetime.now()
user.login_count = (user.login_count or 0) + 1
db.commit()
flash('Witamy ponownie! Zostales automatycznie zalogowany.', 'info')
return redirect(url_for('dashboard'))
@ -1265,6 +1268,7 @@ def verify_email(token):
# Auto-login the user after verification
login_user(user, remember=True)
user.last_login = datetime.now()
user.login_count = (user.login_count or 0) + 1
# Log successful verification and login
client_ip = request.headers.get('X-Forwarded-For', request.remote_addr)

View File

@ -298,8 +298,13 @@ class User(Base, UserMixin):
# Timestamps
created_at = Column(DateTime, default=datetime.now)
last_login = Column(DateTime)
last_active_at = Column(DateTime)
verified_at = Column(DateTime)
# Engagement metrics
login_count = Column(Integer, default=0)
page_views_count = Column(Integer, default=0)
# Verification token
verification_token = Column(String(255))
verification_token_expires = Column(DateTime)

View File

@ -0,0 +1,20 @@
-- Add user engagement tracking columns
-- 2026-03-13
ALTER TABLE users ADD COLUMN IF NOT EXISTS login_count INTEGER DEFAULT 0;
ALTER TABLE users ADD COLUMN IF NOT EXISTS last_active_at TIMESTAMP;
ALTER TABLE users ADD COLUMN IF NOT EXISTS page_views_count INTEGER DEFAULT 0;
-- Backfill login_count from audit_logs
UPDATE users u
SET login_count = COALESCE(sub.cnt, 0)
FROM (
SELECT user_id, COUNT(*) as cnt
FROM audit_logs
WHERE action = 'login'
GROUP BY user_id
) sub
WHERE u.id = sub.user_id;
-- Backfill last_active_at from last_login
UPDATE users SET last_active_at = last_login WHERE last_login IS NOT NULL;