B2B ogłoszenia mogły zostać stworzone 3x (user 81 Bormax 14.04.2026
w ciągu 2 sekund) — brak dedup window server-side i disable submit
button. Rozszerzam zabezpieczenie także na announcements i board
meeting form.
- classifieds POST /nowe: odrzuć duplikat z ostatnich 60s (ten sam
author+company+title) → redirect do istniejącego z flash info
- classifieds new.html: disable submitBtn + "Wysyłanie..." po
walidacji; ponowne kliknięcie blokowane event.preventDefault
- announcements_form.html + board/meeting_form.html: jednolity
handler disable wszystkich button[type="submit"] po pierwszym
submit
Forum topic/reply już miały analogiczne zabezpieczenie (bez zmian).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SQLAlchemy ORM tries to UPDATE classified_reads.classified_id = NULL
before deleting the classifieds row, even though the FK has ON DELETE
CASCADE at DB level. The NOT NULL constraint on classified_id then
raises IntegrityError. Same pattern as the forum_reply_reads fix from
2026-02. Manually delete reads, interests, questions, attachments
before db.delete(classified).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously when server validation failed (e.g. missing required field),
the whole form re-rendered with all values cleared — user had to retype
everything. Also Quill empty-content showed an alert dialog.
Now:
- Server-side: form_data + missing_fields passed to template; values
re-populate inputs, missing fields get .field-error class (red border)
- Quill empty: red border on the editor container instead of alert,
cleared as soon as user starts typing
- Other required fields (radio, select, title): same .field-error
treatment plus :invalid CSS for live HTML5 feedback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove _send_registration_notification call on registration
- Remove first-activation admin notification on password reset
- Change MAIL_BCC default from maciej.pienczyn@inpi.pl to empty
Admin can still set MAIL_BCC via env if blanket BCC is desired.
All new member and password-reset info is visible in /admin panel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Backend: reject identical title+content from same author within 60s
(mirrors existing protection on forum_reply)
- Frontend: disable submit button + 'Wysyłanie…' label on first click
Daniel Kochański accidentally created 7 identical 'Local content w praktyce'
topics within 5 seconds. Soft-deleted IDs 25-30 on prod, kept 24.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Admin fees yearly view now shows all active companies (including child brands)
- Child brand rows are indented with striped month cells and "firma córka" badge
- Parent companies show expandable brand list, Stawka column with 200/300 zł logic
- Expected fee per month computed from number of active child brands
- Rate change month shown when brand joins mid-year (e.g. "I-III: 200 zł / od IV: 300 zł")
- Sorting groups children directly under their parent
- Reminder logic skipped for child companies
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Legacy private_messages and group_messages are no longer used.
Badge now only counts from conv_messages table.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Shows expected fee per company (200 zł for 1 brand, 300 zł for 2+)
- Child companies shown with striped "nie dotyczy" tiles
- Rate change month displayed (e.g., "I-III: 200 zł, od IV: 300 zł")
- Expandable brand list under parent company name
- Children grouped after their parent in the table
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add sort keys and data-sort-value attributes to 'Upr. firmowe' and 'Rola' columns
- Add filter tabs for MANAGER, OFFICE_MANAGER, company-role NONE and MANAGER
- Add data-company-role attribute to user rows for JS filtering
- Grant OFFICE_MANAGER access to admin_users, assign-company, reset-password, change-role, get-roles endpoints
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The badge endpoint api_unread_count only counted legacy private_messages
and group_messages. Now also counts unread conv_messages from the new
conversations system, fixing phantom unread counts for users.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace company_id from current_user with active company from session in
the colleagues API endpoint, and autofill guest org from active_company.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Users with multiple companies now see a dropdown to choose which company
a B2B classified ad is posted for. Single-company users get a hidden field.
Server-side validates the selected company_id against user's actual memberships.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add helpers/company_context.py with get_active_company_id() fallback logic
- Add inject_company_context() context processor to app.py (user_companies, active_company, has_multiple_companies)
- Add /api/switch-company/<id> POST endpoint in public blueprint
- Set session['active_company_id'] on login (both standard and 2FA paths)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace textarea with Quill editor in new/edit classified forms
- Sanitize HTML with sanitize_html() on save (XSS prevention)
- Render HTML in classified detail view, strip tags in list view
- New script: classified_expiry_notifier.py sends email 3 days before
expiry with link to extend. Run daily via cron at 8:00.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added to GeoIP tab:
- Last 20 blocked requests with IP, country, path, timestamp
- Top 10 most targeted URL paths with hit counts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Expired classifieds show 'Wygasło' badge on list and detail view
- Closed classifieds show 'Zamknięte' badge on list
- Author can extend by 30 days with one click
- Homepage 'Nowe na portalu' excludes expired classifieds
- List shows all classifieds, active first
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
updated_at now refreshes on: edit, new Q&A question, new Q&A answer.
Does NOT refresh on: page views, interest clicks, close.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed onupdate from Classified.updated_at, set it manually in edit route.
Ensures toggle_interest, close, and views don't alter the date.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use raw SQL UPDATE for views_count to bypass SQLAlchemy onupdate.
Restore updated_at display in homepage cards - now accurate.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
updated_at was being triggered by views_count increment on every page
view, making dates misleading. Reverted to created_at for display and sort.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Forum cards now show date of latest reply (not topic creation).
B2B cards show updated_at (not created_at), sorted by most recent activity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 'Najnowszy wpis na forum' (duplicate with Nowe na portalu)
with 'Nowi użytkownicy portalu' showing 4 latest registered users
with avatars, names, dates and company names.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows 2 latest forum topics + 2 latest B2B classifieds in a 4-column
grid between events and NordaGPT banner. Responsive 2-col on mobile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New edit route with form pre-filled with existing data
- Edit existing attachments (mark for deletion) + add new ones
- Edit button visible to classified author on detail view
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New ClassifiedAttachment model with migration
- FileUploadService extended with 'classified' type
- Dropzone with drag & drop, paste, multi-file preview in creation form
- Image gallery with lightbox in classified detail view
- Max 10 files, 5MB each, JPG/PNG/GIF
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>
The interest endpoint was returning 400 because fetch sent
Content-Type:application/json with an empty body, causing Flask
to fail JSON parsing. Removed the header since no JSON body is
sent. Also reverted unnecessary CSRF blueprint exemption.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
csrf.exempt on the full classifieds blueprint during registration,
same pattern as API blueprint. All classifieds endpoints are behind
@login_required + @member_required so CSRF exemption is safe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The /tablica/<id>/interest AJAX POST was returning 400 because
Flask-WTF CSRF validation rejected the token despite X-CSRFToken
header being present. Endpoint is protected by @login_required
and @member_required, so CSRF exemption is safe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MessageUploadService.__init__() requires app_root but was called
without arguments, causing send_message errors and double-sending
due to JS retry. Now uses current_app.root_path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New roadmap item: automated procurement/tender aggregation from
BIP, e-Zamówienia, TED, municipal websites. Requested by Daniel
Kochański (Stalpunkt). Priority: high.
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>
New /admin/roadmap page showing feature requests from members in
three columns: Planned, In Progress, Done. Cards expand on click
to show implementation details. First item: multi-location support
requested by Daniel Kochański (Stalpunkt).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
JDG companies don't have board members or shareholders. When CEIDG
returns data for a company, automatically remove company_people
records sourced from ekrs.ms.gov.pl.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When fetching company data by NIP, check CEIDG first (JDG) before
trying Biała Lista/KRS. This prevents JDG companies from being
overwritten with spółka data. Also auto-clears KRS fields when
CEIDG confirms the company is a JDG.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Renumbered all versions from v1.53+ down by 1 to eliminate the
v1.51→v1.53 gap. Current latest: v1.62.0.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Link keys must match the <strong>title</strong> text exactly for the
template macro to render "Wypróbuj →" buttons next to each item.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merged same-day releases into v1.57.0. Renumbered v1.58-v1.63.
Added links to homepage and other key pages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New features: company wizard, paid events, homepage redesign, new members
page, group messaging UI, recipient search, group management panel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New PATCH /api/conversations/<id>/members/<uid> endpoint for role changes
- Owner can promote members to admin and demote back to member
- Admin can add/remove members and edit group name (same as owner except role changes)
- Member list shows role labels (Właściciel/Administrator/Członek)
- Fix: state.currentConversation → state.currentConversationId (panel was empty)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When composing a new message to someone you already have a conversation
with, the dedup logic returned the existing conversation without adding
the message. Now it creates the message and publishes SSE notification.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The compose button was just a small pencil icon with no label. Now it shows
"Nowa wiadomość" text (hidden on mobile). Recipient search was broken because
window.__USERS__ was always empty — replaced with /api/users/search API endpoint
that queries active users by name/email with autocomplete suggestions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Event attendee counts were inconsistent - event detail page showed total
(members + guests = 42) but event list and homepage showed only members (39).
Now all views use total_attendee_count including guests (osoby towarzyszące).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Logo images were cached for 30 days by nginx. After selecting a new logo
from the gallery, the browser still showed the old/placeholder image.
- Add cache-bust query param (?v=timestamp) to logo <img> src
- Update company.last_updated when logo is confirmed
- Use Date.now() redirect instead of reload() after confirm
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>