nordabiz/database/migrations/018_announcements.sql
Maciej Pienczyn e14d95394d feat(announcements): System ogłoszeń i aktualności dla członków
- Model Announcement z kategoriami, statusami, slugami URL
- Panel admina /admin/announcements (CRUD, filtry, AJAX)
- Strona /ogloszenia tylko dla zalogowanych członków
- Szczegóły ogłoszenia /ogloszenia/<slug>
- Migracja SQL rozszerzająca istniejącą tabelę
- Testowe ogłoszenia: ARP baza noclegowa, Tytani Przedsiębiorczości
- Pliki PDF regulaminu i harmonogramu konkursu Tytani

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 22:10:54 +01:00

178 lines
6.1 KiB
SQL

-- ============================================================
-- Migration: 018_announcements.sql
-- Description: Rozszerzenie tabeli ogłoszeń o nowe pola
-- Author: Claude
-- Date: 2026-01-26
-- Note: Tabela announcements już istnieje - rozszerzamy ją
-- ============================================================
-- Dodanie nowych kolumn (jeśli nie istnieją)
-- slug: URL-friendly identyfikator
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'slug') THEN
ALTER TABLE announcements ADD COLUMN slug VARCHAR(300);
END IF;
END $$;
-- excerpt: Krótki opis do listy
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'excerpt') THEN
ALTER TABLE announcements ADD COLUMN excerpt VARCHAR(500);
END IF;
END $$;
-- category: Nowa kategoryzacja (general, event, opportunity, member_news, partnership)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'category') THEN
ALTER TABLE announcements ADD COLUMN category VARCHAR(50) DEFAULT 'general';
END IF;
END $$;
-- image_url: Obrazek ogłoszenia
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'image_url') THEN
ALTER TABLE announcements ADD COLUMN image_url VARCHAR(1000);
END IF;
END $$;
-- external_link: Link do zewnętrznego źródła
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'external_link') THEN
ALTER TABLE announcements ADD COLUMN external_link VARCHAR(1000);
END IF;
END $$;
-- status: draft, published, archived (zastępuje is_published)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'status') THEN
ALTER TABLE announcements ADD COLUMN status VARCHAR(20) DEFAULT 'draft';
END IF;
END $$;
-- published_at: Data publikacji
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'published_at') THEN
ALTER TABLE announcements ADD COLUMN published_at TIMESTAMP;
END IF;
END $$;
-- expires_at: Data wygaśnięcia (zastępuje expire_date)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'expires_at') THEN
ALTER TABLE announcements ADD COLUMN expires_at TIMESTAMP;
END IF;
END $$;
-- is_featured: Wyróżnienie
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'is_featured') THEN
ALTER TABLE announcements ADD COLUMN is_featured BOOLEAN DEFAULT FALSE;
END IF;
END $$;
-- views_count: Licznik wyświetleń
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'views_count') THEN
ALTER TABLE announcements ADD COLUMN views_count INTEGER DEFAULT 0;
END IF;
END $$;
-- created_by: ID użytkownika (mapowanie z author_id)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'announcements' AND column_name = 'created_by') THEN
ALTER TABLE announcements ADD COLUMN created_by INTEGER REFERENCES users(id) ON DELETE SET NULL;
END IF;
END $$;
-- Migracja danych ze starych kolumn do nowych
-- Mapowanie announcement_type -> category
UPDATE announcements
SET category = CASE
WHEN announcement_type = 'fees' THEN 'general'
WHEN announcement_type = 'important' THEN 'general'
WHEN announcement_type = 'urgent' THEN 'general'
WHEN announcement_type = 'event' THEN 'event'
ELSE COALESCE(announcement_type, 'general')
END
WHERE category IS NULL OR category = '';
-- Mapowanie is_published -> status
UPDATE announcements
SET status = CASE
WHEN is_published = true THEN 'published'
ELSE 'draft'
END
WHERE status IS NULL OR status = '';
-- Mapowanie expire_date -> expires_at
UPDATE announcements
SET expires_at = expire_date
WHERE expires_at IS NULL AND expire_date IS NOT NULL;
-- Mapowanie publish_date -> published_at
UPDATE announcements
SET published_at = COALESCE(publish_date, created_at)
WHERE published_at IS NULL AND is_published = true;
-- Mapowanie author_id -> created_by
UPDATE announcements
SET created_by = author_id
WHERE created_by IS NULL AND author_id IS NOT NULL;
-- Generowanie slugów dla istniejących ogłoszeń
UPDATE announcements
SET slug = CONCAT(
LOWER(REGEXP_REPLACE(
REGEXP_REPLACE(title, '[^a-zA-Z0-9\s]', '', 'g'),
'\s+', '-', 'g'
)),
'-', id
)
WHERE slug IS NULL OR slug = '';
-- Tworzenie indeksów (jeśli nie istnieją)
CREATE INDEX IF NOT EXISTS idx_announcements_status ON announcements(status);
CREATE INDEX IF NOT EXISTS idx_announcements_slug ON announcements(slug);
CREATE INDEX IF NOT EXISTS idx_announcements_published_at ON announcements(published_at DESC);
CREATE INDEX IF NOT EXISTS idx_announcements_category ON announcements(category);
-- Tworzenie unikalności na slug
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_indexes WHERE indexname = 'idx_announcements_slug_unique') THEN
CREATE UNIQUE INDEX idx_announcements_slug_unique ON announcements(slug) WHERE slug IS NOT NULL;
END IF;
END $$;
-- Uprawnienia
GRANT ALL ON TABLE announcements TO nordabiz_app;
GRANT USAGE, SELECT ON SEQUENCE announcements_id_seq TO nordabiz_app;
-- Komentarze
COMMENT ON COLUMN announcements.slug IS 'URL-friendly slug (np. baza-noclegowa-arp-choczewo)';
COMMENT ON COLUMN announcements.excerpt IS 'Krótki opis do listy (max 500 znaków)';
COMMENT ON COLUMN announcements.category IS 'Kategoria: general, event, opportunity, member_news, partnership';
COMMENT ON COLUMN announcements.status IS 'Status: draft, published, archived';