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
- Add Benefit and BenefitClick models for tracking affiliate offers - Create /korzysci blueprint with admin-only access (test mode) - Add admin panel at /admin/benefits for managing offers - Include WisprFlow as first benefit with branded link ref.wisprflow.ai/norda - Add QR code support for printed materials - Track clicks with user attribution and analytics Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
111 lines
3.0 KiB
Python
111 lines
3.0 KiB
Python
"""
|
|
Benefits Routes
|
|
===============
|
|
|
|
Korzyści członkowskie - oferty afiliacyjne dla członków Izby NORDA.
|
|
|
|
TRYB TESTOWY: Dostęp tylko dla administratorów.
|
|
Po uruchomieniu produkcyjnym zmienić na @member_required.
|
|
"""
|
|
|
|
from flask import render_template, redirect, request, flash, url_for, abort
|
|
from flask_login import login_required, current_user
|
|
|
|
from . import bp
|
|
from database import SessionLocal, Benefit, BenefitClick, SystemRole
|
|
from utils.decorators import role_required
|
|
|
|
|
|
@bp.route('/')
|
|
@login_required
|
|
@role_required(SystemRole.ADMIN) # TESTOWY: tylko admin
|
|
def benefits_list():
|
|
"""Lista korzyści członkowskich."""
|
|
db = SessionLocal()
|
|
try:
|
|
benefits = db.query(Benefit).filter(
|
|
Benefit.is_active == True
|
|
).order_by(
|
|
Benefit.is_featured.desc(),
|
|
Benefit.display_order,
|
|
Benefit.name
|
|
).all()
|
|
|
|
# Grupuj po kategorii
|
|
categories = {}
|
|
for benefit in benefits:
|
|
cat = benefit.category or 'other'
|
|
if cat not in categories:
|
|
categories[cat] = []
|
|
categories[cat].append(benefit)
|
|
|
|
return render_template(
|
|
'benefits/benefits_list.html',
|
|
benefits=benefits,
|
|
categories=categories,
|
|
category_choices=dict(Benefit.CATEGORY_CHOICES)
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@bp.route('/<slug>')
|
|
@login_required
|
|
@role_required(SystemRole.ADMIN) # TESTOWY: tylko admin
|
|
def benefit_detail(slug):
|
|
"""Szczegóły korzyści i przekierowanie na link afiliacyjny."""
|
|
db = SessionLocal()
|
|
try:
|
|
benefit = db.query(Benefit).filter(
|
|
Benefit.slug == slug,
|
|
Benefit.is_active == True
|
|
).first()
|
|
|
|
if not benefit:
|
|
abort(404)
|
|
|
|
return render_template(
|
|
'benefits/benefit_detail.html',
|
|
benefit=benefit
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@bp.route('/<slug>/go')
|
|
@login_required
|
|
@role_required(SystemRole.ADMIN) # TESTOWY: tylko admin
|
|
def benefit_redirect(slug):
|
|
"""Przekierowanie na link afiliacyjny z logowaniem kliknięcia."""
|
|
db = SessionLocal()
|
|
try:
|
|
benefit = db.query(Benefit).filter(
|
|
Benefit.slug == slug,
|
|
Benefit.is_active == True
|
|
).first()
|
|
|
|
if not benefit:
|
|
abort(404)
|
|
|
|
if not benefit.affiliate_url:
|
|
flash('Link do tej oferty nie jest jeszcze dostępny.', 'warning')
|
|
return redirect(url_for('benefits.benefits_list'))
|
|
|
|
# Loguj kliknięcie
|
|
click = BenefitClick(
|
|
benefit_id=benefit.id,
|
|
user_id=current_user.id if current_user.is_authenticated else None,
|
|
ip_address=request.remote_addr,
|
|
user_agent=request.headers.get('User-Agent', '')[:500]
|
|
)
|
|
db.add(click)
|
|
|
|
# Zwiększ licznik
|
|
benefit.click_count = (benefit.click_count or 0) + 1
|
|
|
|
db.commit()
|
|
|
|
return redirect(benefit.affiliate_url)
|
|
finally:
|
|
db.close()
|