Każdy e-mail powiadomieniowy ma teraz:
(1) link w stopce "Wyłącz ten typ powiadomień jednym kliknięciem"
(2) nagłówki List-Unsubscribe + List-Unsubscribe-Post dla klientów
pocztowych (Gmail/Apple Mail pokażą natywny przycisk Unsubscribe)
Implementacja:
- utils/unsubscribe_tokens.py: signed token (itsdangerous, SECRET_KEY)
niosący user_id + notification_type, bez wygasania
- blueprints/unsubscribe: GET /unsubscribe?t=TOKEN → strona potwierdzenia,
POST /unsubscribe → faktyczne wyłączenie flagi notify_email_<type>
- email_service.send_email() dostał parametr notification_type. Jeśli
przekazany razem z user_id, footer + headery są doklejane
- Aktualizowane wywołania: message_notification (messages),
classified_question/answer (B2B Q&A), classified_expiry (skrypt cron)
Prefetch safety: GET pokazuje stronę z przyciskiem "Tak, wyłącz",
wyłączenie następuje po POST. RFC 8058 One-Click (POST bez formularza
z Content-Type application/x-www-form-urlencoded + body
"List-Unsubscribe=One-Click") obsługuje klientów pocztowych.
D.2/D.3 dorzucą kolejne notification_type (forum, broadcast, events).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Google Maps URLs can be 800+ chars of tracking data that poisoned the
forum UI. Extract the place name from /maps/place/NAME/ (or fall back
to coordinates) and render as '📍 Name'. Full URL remains in the href.
Two secondary fixes:
- Edit/quote modals were reading .innerText of the rendered reply,
which baked the current render (including any stale/broken HTML from
older bad renders) back into the textarea. Switched to emitting the
raw DB content via {{ content|tojson }} so what you edit is what you
wrote.
- @mention regex was matching '@54.1234' inside Maps URLs and similar.
Tightened to require a letter start and non-slash/non-word lookbehind
so coords and email-style strings pass through untouched.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Forum reply, @mention and classifieds notification emails used
`background: linear-gradient(...)` for the primary CTA button. Outlook
desktop strips background-image gradients, leaving the white-on-white
text effectively invisible. Added background-color as the first
declaration so Outlook keeps a solid dark-blue button while modern
clients still render the gradient.
Reported by Maciej Koenig: forum reply email appeared to lack the
'Zobacz odpowiedź' link.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two user-reported regressions:
1. B2B classifieds "Dodaj ogłoszenie" button silently no-op'd. Hidden
Quill description textarea had `required` attribute — browser blocked
submit but cannot show validation UI on display:none fields. Removed
`required`, added empty-content guard in submit handler with explicit
alert.
2. Forum auto-linker truncated Google Maps URLs containing two
underscores (e.g. forestry_office...g_ep=). Italic regex `_text_`
matched across the URL, splitting it with <em> tags. Italic/bold
underscore forms now require non-word boundary so URLs and identifiers
like my_var_name pass through untouched.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- parse_mentions_and_notify now sends email to mentioned user
(separate from forum subscription emails — fires on every mention)
- parse_forum_markdown accepts current_user_name; mentions matching
the viewer get extra .forum-mention-self class
- topic.html passes current_user.name to filter; .forum-mention-self
styled with amber background + bold + ring
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three new notification types:
- New question → author gets in-app + email
- Answer to question → questioner gets in-app + email
- Someone interested → author gets in-app only
Previously the B2B board had zero notifications, so authors never
knew someone asked a question about their listing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Email notifications for forum replies were linking to /forum/ID
without the #reply-XX anchor. Now includes reply_id in the URL
so the email "Zobacz odpowiedź" button scrolls directly to the
new reply instead of the top of the topic.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Onboarding steps had hardcoded /company/{id}/edit URLs that don't exist.
Changed to /firma/edytuj/{id} which is the actual company edit route.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Images pasted as base64 had their src stripped by bleach (only http/https
allowed by default). Now data: protocol is whitelisted.
Also allow width/height/style on img for resize support.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously only SUPERADMIN could access audit pages (SEO, GBP,
Social Media, IT). Now MANAGER+ of a company can view audits for
their own company. Route-level can_edit_company() check still
restricts to own company only.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
URLs in messages are now automatically converted to clickable links
opening in a new tab. Works for both old plain-text and new Quill
HTML messages. Uses linkify Jinja2 filter that only processes text
nodes outside existing <a>/<img> tags.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace plain textarea with Quill editor in compose and reply forms
- Support Ctrl+V paste of screenshots directly into message body
- Image toolbar button for file picker upload
- New endpoint POST /api/messages/upload-image for inline images
- Content sanitized via sanitize_html (bleach) with img tag support
- Messages rendered as HTML (|safe) instead of plain text
- Links clickable, images displayed inline in message body
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows detected display-mode, navigator.standalone, and PWA cookies
as a small green text at bottom of screen. Only visible for admin users.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Frontend now sends pwa_display cookie with the actual detected mode
(standalone/minimal-ui/fullscreen/browser/unknown/ios-standalone).
Backend logs this to diagnose why WebAPK detection fails.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cookie pwa_mode=1 is set by JS after page load, so it's not available
on the first request that creates the session. Now also check on
subsequent requests and update is_pwa=True retroactively.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. PWA: frontend sets pwa_mode=1 cookie when in standalone mode,
backend reads it and stores is_pwa=True in user_sessions.
Migration 063 adds is_pwa column.
2. Bot filter: added 13 new patterns (GoogleAssociationService,
Censys, Palo Alto, Netcraft, fasthttp, Apple WebKit prefetch,
etc.) + flag empty/bare "Mozilla/5.0" UA as bot. This eliminates
~800 false sessions from analytics.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Parses emoji-sectioned text (ZARZĄD, WSPÓLNICY, DANE REJESTROWE,
DANE FINANSOWE, PROFIL) into card-based layout with icons, lists,
and highlighted key-value pairs. Plain text gets newline conversion.
HTML from Quill editor passes through unchanged.
Affects 45 companies with emoji format, 63 with plain text.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded email check for audit panels with role-based
SUPERADMIN check. ADMIN retains all management capabilities but
SUPERADMIN adds access to technical audits (SEO, IT, GBP, Social,
Access Control).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
URLs are now linked before being wrapped in <li>/<blockquote>,
and consecutive text lines are joined into paragraphs instead of
getting individual <br> tags.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Normalize \r\n to \n before processing
- Strip leading whitespace from lines (textarea indentation)
- Auto-link bare URLs works correctly inside list items
- Smart <br> insertion: skip block elements (ul, li, blockquote, pre)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Plain https:// URLs are now automatically converted to clickable links.
Markdown [text](url) syntax continues to work without duplication.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add is_bot column to user_sessions with backfill from user_agent patterns
- Update analytics_daily trigger to skip bot sessions
- Recalculate 90 days of analytics_daily without bot contamination
- Replace cumulative failed_login_attempts with time-based audit_logs queries
- Switch engagement score from linear (capped at 100) to log2 scale
- Expand section_map from 9 to 17 categories (~95% traffic coverage)
- Exclude robots.txt, sitemap.xml etc from page view tracking
- Add bot filter to all overview, pages, paths, and engagement queries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shared _email_v3_wrap() helper: branded header with logo, full footer
with address/links. Updated: password reset, welcome, forum reply,
role notification. Action buttons grid layout in /admin/users.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add clickable field coverage bars to filter companies missing specific data
- Add quick-action buttons (Registry/SEO/GBP) per company in dashboard table
- Add stale data detection (>6 months) with yellow badges
- Implement weighted priority score (contacts 34%, audits 17%)
- Add data hints in admin company detail showing where to find missing data
- Add "Available data" section showing Google Business data ready to apply
- Add POST /api/company/<id>/apply-hint endpoint for one-click data fill
- Extend website content updater with phone/email extraction (AI + regex)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract 12-field completeness scoring to utils/data_quality.py service
- Auto-update data_quality_score and data_quality label on company data changes
- Add /admin/data-quality dashboard with field coverage stats, quality distribution, and sortable company table
- Add bulk enrichment with background processing, step selection, and progress tracking
- Flow GBP phone/website to Company record when company fields are empty
- Display Google opening hours on public company profile
- Add BulkEnrichmentJob model and migration 075
- Refactor arm_company.py to support selective steps and progress callbacks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Visual timeline showing company profile completion status:
- 6 steps computed from existing DB data (no new tables)
- Color-coded badges: member/office/auto responsibility
- Collapsible with localStorage persistence
- Green "complete" state when all steps done
- Action links for incomplete member-owned steps
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Audits (SEO, IT, GBP, Social Media) are now visible only to the
designated audit owner (maciej.pienczyn@inpi.pl). All other users,
including admins, see 404 for audit routes and no audit links in
navigation. KRS Audit and Digital Maturity remain unchanged.
Adds /admin/access-overview panel showing the access matrix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- HIGH: Fix SQL injection in ZOPK knowledge service (3 functions) — replace f-strings with parameterized queries
- MEDIUM: Sanitize tsquery/LIKE input in SearchService to prevent injection
- MEDIUM: Add @login_required + @role_required(ADMIN) to /health/full endpoint
- MEDIUM: Add @role_required(ADMIN) to ZOPK knowledge search API
- MEDIUM: Add bleach HTML sanitization on write for announcements, events, board proceedings (stored XSS via |safe)
- MEDIUM: Remove partial API key from Gemini service logs
- MEDIUM: Remove @csrf.exempt from chat endpoints, add X-CSRFToken headers in JS
- MEDIUM: Add missing CSRF tokens to 3 POST forms (data_request, benefits_form, benefits_list)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Email notifications sent to topic subscribers when new reply posted
- Auto-subscribe users when they reply to a topic
- Custom CSS tooltip on "seen by" avatars (replaces native title)
- GET /forum/<id>/unsubscribe endpoint for email unsubscribe links
- Clean up ROADMAP.md (remove unimplemented priorities, add RBAC/Slack)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace ~20 remaining is_admin references across backend, templates and scripts
with proper SystemRole checks. Column is_admin stays as deprecated (synced by
set_role()) until DB migration removes it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add @rada_member_required decorator for access control
- Add BoardDocument model for storing protocols and documents
- Create document upload service (PDF, DOCX, DOC up to 50MB)
- Add /rada/ blueprint with list, upload, download endpoints
- Add "Rada" link in navigation (visible only for board members)
- Add "Rada" badge and toggle button in admin user management
- Create SQL migration to set up board_documents table and assign
is_rada_member=True to 16 board members by email
Storage: /data/board-docs/ (outside webroot for security)
Access: is_rada_member=True OR role >= OFFICE_MANAGER
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace ~170 manual `if not current_user.is_admin` checks with:
- @role_required(SystemRole.ADMIN) for user management, security, ZOPK
- @role_required(SystemRole.OFFICE_MANAGER) for content management
- current_user.can_access_admin_panel() for admin UI access
- current_user.can_moderate_forum() for forum moderation
- current_user.can_edit_company(id) for company permissions
Add @office_manager_required decorator shortcut.
Add SQL migration to sync existing users' role field.
Role hierarchy: UNAFFILIATED(10) < MEMBER(20) < EMPLOYEE(30) < MANAGER(40) < OFFICE_MANAGER(50) < ADMIN(100)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements 6-tier role hierarchy:
- ADMIN (100): Full system access
- OFFICE_MANAGER (50): Admin panel without user management
- MANAGER (40): Full company control + user management
- EMPLOYEE (30): Edit company data (with delegated permissions)
- MEMBER (20): Full content access (forum, contacts, chat)
- UNAFFILIATED (10): Public profiles only
Features:
- SystemRole and CompanyRole enums in database.py
- UserCompanyPermissions model for delegation
- New decorators: @role_required(), @company_permission()
- Auto-detection of MANAGER role from KRS data
- Backward compatible with is_admin flag
Migration: 035_add_role_system.sql
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- notify_all_users_release(): Notify all users about new system version
- notify_all_users_announcement(): Notify all users about new announcement
- Auto-send notifications when admin publishes an announcement
- New admin endpoint POST /admin/notify-release for manual release notifications
- Category-specific icons for announcement notifications
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>