@bygghammar/cms-platform 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/migrations/20260728113741_f9744b19-078b-46e5-b00f-31c84aaf71ab.sql +111 -0
  2. package/migrations/20260728113757_4156a886-21fb-4a1f-9c12-acb7bb145102.sql +5 -0
  3. package/migrations/20260728113823_6e0237e1-99e3-4e1a-8a68-804b7bcdbbb8.sql +1 -0
  4. package/migrations/20260728115305_506d92b4-129f-4d2b-961f-cf76e592677e.sql +92 -0
  5. package/migrations/20260728115320_717d4447-f433-4a1d-89d2-fc8f028d4ac6.sql +1 -0
  6. package/migrations/20260728115347_c77f5a56-19db-4117-bb60-9ad692b817ab.sql +11 -0
  7. package/migrations/20260728132052_b692dcfe-a944-4a19-afd0-187f7600feb8.sql +63 -0
  8. package/migrations/20260728183318_05b05a47-ba05-4a66-ab8f-69f2688fea84.sql +209 -0
  9. package/migrations/20260728193035_84b68d27-c3f3-4516-a3a9-15fc6f476163.sql +17 -0
  10. package/migrations/20260728193707_8438ee2d-d589-4048-86e2-464fd209af80.sql +37 -0
  11. package/migrations/20260729055312_08862d7e-0279-4d4f-8709-a59b9f068c55.sql +5 -0
  12. package/migrations/20260729055348_418b7e36-4877-4304-831f-290ca73e56f3.sql +133 -0
  13. package/migrations/20260729055358_20b467e2-4efd-42c1-bd34-773ed6b77fc5.sql +3 -0
  14. package/migrations/20260729061039_306859eb-a38c-44ef-af1a-6c02a8fd84db.sql +43 -0
  15. package/migrations/20260730065600_54c25861-3355-4600-a72f-3d67b457ecb1.sql +54 -0
  16. package/migrations/20260730071745_d4904314-15ff-4c58-ac66-85e7371e04b5.sql +113 -0
  17. package/migrations/20260730071914_48163aa3-830e-4dcc-bdd4-c35be282ab87.sql +22 -0
  18. package/migrations/20260730085949_bcfc3270-ea80-4617-86a3-2555ed34a280.sql +24 -0
  19. package/migrations/20260730095256_c977c30e-b285-4041-8804-c0bd72b6d9b3.sql +13 -0
  20. package/migrations/20260730100057_e341b887-eb0e-4a74-850e-0ee5ffb70d7a.sql +38 -0
  21. package/migrations/20260730103703_d5c4e1b7-1e2c-4dd0-be4e-185c159ade69.sql +62 -0
  22. package/migrations/20260730105635_3557b7da-919e-48db-8c92-8221d68d3cf9.sql +29 -0
  23. package/migrations/20260730120308_12ff8cfb-43f9-4070-abde-61531ad3b75f.sql +73 -0
  24. package/migrations/20260730125024_1baf8926-12a2-48f4-8edc-7309941309e9.sql +18 -0
  25. package/migrations/20260730173510_feb974d1-510e-4f52-9e20-5fd0582d8952.sql +107 -0
  26. package/migrations/20260730175409_9f60743f-f5e1-418c-a700-c91fb3704db8.sql +9 -0
  27. package/migrations/20260730181224_1c52ff16-c7a2-4ef1-a0a8-e493c2c9106f.sql +7 -0
  28. package/migrations/20260730183129_933adb75-f985-4d82-ad5d-213b69fd42e5.sql +32 -0
  29. package/migrations/20260730183918_7bc7a827-2100-49f1-bc6e-24509249350b.sql +68 -0
  30. package/migrations/20260730202628_7ceade5e-644c-4bc2-91b8-594133329f31.sql +1 -0
  31. package/migrations/20260730211056_57f42049-00b4-473b-a2cd-65a13570b8d2.sql +16 -0
  32. package/migrations/20260730214340_98af2e55-9031-4c11-9659-c47a37a8d6b7.sql +1 -0
  33. package/migrations/20260731091630_8a6f28ce-5833-4901-ab17-27648cef32ec.sql +149 -0
  34. package/migrations/20260731094716_4c68a1df-83ed-4ba8-8019-fa2fe2b9681e.sql +65 -0
  35. package/migrations/20260731191655_fef97c3c-1397-47b4-8b56-afb020298e97.sql +165 -0
  36. package/migrations/20260731192212_95772a2f-19a1-4013-b463-2eb161e96737.sql +135 -0
  37. package/migrations/20260731192815_c490653e-1232-4ad9-a150-3c83d2b90f5e.sql +13 -0
  38. package/migrations/20260731193135_7966e740-5e86-4b14-8e1d-5119069666ba.sql +2 -0
  39. package/migrations/20260731193245_599790d0-ca5e-4b5d-a3e7-d69b2a79e1a3.sql +13 -0
  40. package/migrations/20260731212959_a748cb0d-4dc7-45dc-be90-f6bacbfab26c.sql +9 -0
  41. package/migrations/20260801003057_1195f4c1-fb54-42dc-9718-638a25e6a82e.sql +3 -0
  42. package/migrations/20260801003300_fc591960-cb41-41cf-837d-2eef23b29ca9.sql +40 -0
  43. package/migrations/20260802151445_a56b0023-eaf7-41e2-a7fb-d4beddfc587c.sql +3 -0
  44. package/migrations/20260802202621_d661af8a-8513-4b54-b375-f963ae824c8f.sql +225 -0
  45. package/migrations/20260802202702_c30cd837-744c-4641-85f1-edd3a7ebbcb6.sql +16 -0
  46. package/migrations/20260802202720_4418d18d-c851-42dc-9345-78fc330128ae.sql +2 -0
  47. package/migrations/20260803132514_78ba1f53-c85b-4457-96b1-7d49c5c8b494.sql +34 -0
  48. package/migrations/20260803181201_28c8aa09-baa8-431c-8338-90b1af9c8172.sql +22 -0
  49. package/migrations/20260803201518_6e8a6028-b70f-4a7d-8bc9-95c86304e7ae.sql +12 -0
  50. package/migrations/20260803201535_32a9a213-cb92-4035-b8cd-8211ca34af68.sql +12 -0
  51. package/migrations/20260811103505_29df753d-14fa-4a05-8fea-f4207785fba3.sql +35 -0
  52. package/migrations/20260811112455_217c4028-f587-4c98-9e4f-9e6c452ab761.sql +20 -0
  53. package/migrations/20260811114438_6687d67d-bad3-4803-9638-8b7670d2e5d4.sql +86 -0
  54. package/migrations/20260811130318_7cb95e95-9baa-40af-8f3f-de1d4e09cec4.sql +1 -0
  55. package/migrations/20260811220548_80d99ec2-bd4b-475d-a627-9408bb60ce56.sql +1 -0
  56. package/migrations/20260811222519_6b040f56-4de3-49e0-92e4-d9deec5ead6a.sql +3 -0
  57. package/migrations/20260812000000_seed_voyara_content.sql +390 -0
  58. package/migrations/20260818040722_1bdf1b8f-7fb0-4ae8-8ecf-73f1fadff3c2.sql +2 -0
  59. package/migrations/20260818040808_69a5e832-57e8-4aa7-aff8-7fd7777faa7c.sql +15 -0
  60. package/migrations/20260818040839_e6523163-bbf5-4a39-9233-91759059569a.sql +26 -0
  61. package/package.json +9 -4
  62. package/src/backoffice/media/ReviewImageUpload.tsx +104 -0
  63. package/src/backoffice/seo/PageSeoPanelView.tsx +406 -0
  64. package/src/platform/contract.ts +92 -0
@@ -0,0 +1,16 @@
1
+ CREATE OR REPLACE FUNCTION app.current_user_id()
2
+ RETURNS uuid
3
+ LANGUAGE sql
4
+ STABLE
5
+ SECURITY INVOKER
6
+ SET search_path = auth, public, pg_temp
7
+ AS $$
8
+ SELECT auth.uid()
9
+ $$;
10
+
11
+ REVOKE ALL ON FUNCTION app.has_role(uuid, public.app_role) FROM PUBLIC, anon, authenticated;
12
+ REVOKE ALL ON FUNCTION app.is_staff(uuid) FROM PUBLIC, anon, authenticated;
13
+ GRANT EXECUTE ON FUNCTION app.has_role(uuid, public.app_role) TO service_role;
14
+ GRANT EXECUTE ON FUNCTION app.is_staff(uuid) TO service_role;
15
+
16
+ GRANT EXECUTE ON FUNCTION app.current_user_id() TO anon, authenticated, service_role;
@@ -0,0 +1,2 @@
1
+ REVOKE ALL ON FUNCTION public.ensure_app_user() FROM PUBLIC, anon, authenticated;
2
+ GRANT EXECUTE ON FUNCTION public.ensure_app_user() TO service_role;
@@ -0,0 +1,34 @@
1
+ -- Least-privilege public read on forms.
2
+ -- Visitors must never be able to read private_settings (notification
3
+ -- recipients, webhook secrets, spreadsheet ids). The original migration
4
+ -- granted only a column subset; some environments drifted to a table-wide
5
+ -- grant. Re-assert the column list here so hosted and self-hosted match.
6
+ REVOKE ALL ON public.forms FROM anon;
7
+ GRANT SELECT (id, key, name, form_type, fields, public_settings, is_active, deleted_at)
8
+ ON public.forms TO anon;
9
+
10
+ -- The public renderer needs exactly two values out of private_settings.
11
+ -- Expose them through a security-definer function instead of widening the
12
+ -- column grant.
13
+ CREATE OR REPLACE FUNCTION public.form_public_runtime(_key text)
14
+ RETURNS jsonb
15
+ LANGUAGE sql
16
+ STABLE
17
+ SECURITY DEFINER
18
+ SET search_path = public
19
+ AS $$
20
+ SELECT jsonb_strip_nulls(
21
+ jsonb_build_object(
22
+ 'spamMinSeconds', f.private_settings -> 'spamMinSeconds',
23
+ 'savePartials', f.private_settings -> 'savePartials'
24
+ )
25
+ )
26
+ FROM public.forms f
27
+ WHERE f.key = _key
28
+ AND f.is_active = true
29
+ AND f.deleted_at IS NULL
30
+ LIMIT 1
31
+ $$;
32
+
33
+ REVOKE ALL ON FUNCTION public.form_public_runtime(text) FROM PUBLIC;
34
+ GRANT EXECUTE ON FUNCTION public.form_public_runtime(text) TO anon, authenticated, service_role;
@@ -0,0 +1,22 @@
1
+ CREATE OR REPLACE FUNCTION public.form_public_runtime(_key text)
2
+ RETURNS jsonb
3
+ LANGUAGE sql
4
+ STABLE
5
+ SECURITY DEFINER
6
+ SET search_path = ''
7
+ AS $$
8
+ SELECT pg_catalog.jsonb_strip_nulls(
9
+ pg_catalog.jsonb_build_object(
10
+ 'spamMinSeconds', f.private_settings -> 'spamMinSeconds',
11
+ 'savePartials', f.private_settings -> 'savePartials'
12
+ )
13
+ )
14
+ FROM public.forms f
15
+ WHERE f.key = _key
16
+ AND f.is_active = true
17
+ AND f.deleted_at IS NULL
18
+ LIMIT 1
19
+ $$;
20
+
21
+ REVOKE ALL ON FUNCTION public.form_public_runtime(text) FROM PUBLIC;
22
+ GRANT EXECUTE ON FUNCTION public.form_public_runtime(text) TO anon, authenticated, service_role;
@@ -0,0 +1,12 @@
1
+ -- Neutralised: this migration originally hardcoded an absolute hosted storage
2
+ -- URL for the homepage hero poster. Absolute hosted URLs are not portable and
3
+ -- must never reach a self-hosted database (this directory is replayed by
4
+ -- deploy/initdb/10-schema.sh on a fresh PostgreSQL volume).
5
+ --
6
+ -- The portable replacement lives in db/selfhost/upgrades/0002_optimized_hero_media.sql
7
+ -- and is applied by scripts/install-media-package.ts, which first verifies that
8
+ -- the optimized media actually exists in the media volume.
9
+ --
10
+ -- Hosted behaviour is preserved: the hosted database already ran the original
11
+ -- statement, and its rows were rewritten to site-relative /media/ paths.
12
+ SELECT 1;
@@ -0,0 +1,12 @@
1
+ -- Neutralised: this migration originally hardcoded an absolute hosted storage
2
+ -- URL for the homepage hero poster. Absolute hosted URLs are not portable and
3
+ -- must never reach a self-hosted database (this directory is replayed by
4
+ -- deploy/initdb/10-schema.sh on a fresh PostgreSQL volume).
5
+ --
6
+ -- The portable replacement lives in db/selfhost/upgrades/0002_optimized_hero_media.sql
7
+ -- and is applied by scripts/install-media-package.ts, which first verifies that
8
+ -- the optimized media actually exists in the media volume.
9
+ --
10
+ -- Hosted behaviour is preserved: the hosted database already ran the original
11
+ -- statement, and its rows were rewritten to site-relative /media/ paths.
12
+ SELECT 1;
@@ -0,0 +1,35 @@
1
+ -- These policies and triggers were introduced by earlier migrations. Reassert
2
+ -- their final definitions idempotently so a fresh database can replay the
3
+ -- complete Lovable migration history without failing on duplicate objects.
4
+ DROP POLICY IF EXISTS "Admins can read media" ON storage.objects;
5
+ CREATE POLICY "Admins can read media"
6
+ ON storage.objects FOR SELECT TO authenticated
7
+ USING (bucket_id = 'media' AND public.has_role(auth.uid(), 'admin'));
8
+
9
+ DROP POLICY IF EXISTS "Admins can upload media" ON storage.objects;
10
+ CREATE POLICY "Admins can upload media"
11
+ ON storage.objects FOR INSERT TO authenticated
12
+ WITH CHECK (bucket_id = 'media' AND public.has_role(auth.uid(), 'admin'));
13
+
14
+ DROP POLICY IF EXISTS "Admins can update media" ON storage.objects;
15
+ CREATE POLICY "Admins can update media"
16
+ ON storage.objects FOR UPDATE TO authenticated
17
+ USING (bucket_id = 'media' AND public.has_role(auth.uid(), 'admin'))
18
+ WITH CHECK (bucket_id = 'media' AND public.has_role(auth.uid(), 'admin'));
19
+
20
+ DROP POLICY IF EXISTS "Admins can delete media" ON storage.objects;
21
+ CREATE POLICY "Admins can delete media"
22
+ ON storage.objects FOR DELETE TO authenticated
23
+ USING (bucket_id = 'media' AND public.has_role(auth.uid(), 'admin'));
24
+
25
+ DROP TRIGGER IF EXISTS on_auth_user_created_grant_admin ON auth.users;
26
+ CREATE TRIGGER on_auth_user_created_grant_admin
27
+ AFTER INSERT ON auth.users
28
+ FOR EACH ROW EXECUTE FUNCTION public.grant_initial_admin();
29
+
30
+ DROP TRIGGER IF EXISTS on_auth_user_confirmed_grant_admin ON auth.users;
31
+ CREATE TRIGGER on_auth_user_confirmed_grant_admin
32
+ AFTER UPDATE OF email_confirmed_at ON auth.users
33
+ FOR EACH ROW
34
+ WHEN (OLD.email_confirmed_at IS NULL AND NEW.email_confirmed_at IS NOT NULL)
35
+ EXECUTE FUNCTION public.grant_initial_admin();
@@ -0,0 +1,20 @@
1
+ UPDATE public.page_seo SET seo = jsonb_set(seo, '{title,sv}', to_jsonb(v.title)) FROM (VALUES
2
+ ('home','Nordens största partykryssning och festkryssning | Voyara'),
3
+ ('artister','Artister på vinterns hetaste partykryssning · Voyara'),
4
+ ('hytter','Hytter ombord · Voyara partykryssning'),
5
+ ('mat-och-dryck','Mat och dryck på Voyara · Partykryssning'),
6
+ ('tallinn','Tallinn · Voyara partykryssning'),
7
+ ('sakerhet','Säkerhet och en trygg miljö · Voyara'),
8
+ ('galleri','Galleri · Voyara partykryssning'),
9
+ ('faq','FAQ · Voyara partykryssning'),
10
+ ('boka','Boka nu · Voyara partykryssning'),
11
+ ('samarbete','Samarbete · Voyara partykryssning'),
12
+ ('ambassador','Bli ambassadör · Voyara partykryssning'),
13
+ ('kontakt','Kontakta oss · Voyara'),
14
+ ('intresse','Intresseanmälan · Voyara partykryssning')
15
+ ) AS v(page_key, title) WHERE public.page_seo.page_key = v.page_key;
16
+
17
+ UPDATE public.page_seo SET seo = jsonb_set(seo, '{description,sv}', to_jsonb(v.descr)) FROM (VALUES
18
+ ('home','Välkommen till en festkryssning och partykryssning utöver det vanliga. Artister, DJ:s och shower varje kväll — studenter och alla är välkomna.'),
19
+ ('artister','Välkommen till partykryssningen med de hetaste artisterna. Ett unikt nöjeskoncept i två dagar med uppträdanden båda kvällarna.')
20
+ ) AS v(page_key, descr) WHERE public.page_seo.page_key = v.page_key;
@@ -0,0 +1,86 @@
1
+ begin;
2
+
3
+ with p as (select id from public.pages where key = 'home'),
4
+ cur as (
5
+ select v.blocks from public.page_versions v
6
+ join public.pages pg on pg.current_version_id = v.id
7
+ where pg.key = 'home'
8
+ ),
9
+ tiles as (
10
+ select jsonb_build_object(
11
+ 'id', 'blk-link-tiles-home',
12
+ 'type', 'linkTiles',
13
+ 'name', 'Boka / Elevkårer / Ambassadör',
14
+ 'props', jsonb_build_object(
15
+ 'tone', 'white',
16
+ 'columns', 3,
17
+ 'gap', 'md',
18
+ 'aspect', 'portrait',
19
+ 'overlay', 'brand',
20
+ 'labelAlign', 'left',
21
+ 'rounded', false,
22
+ 'items', jsonb_build_array(
23
+ jsonb_build_object(
24
+ 'id', 'tile-boka',
25
+ 'image', 'https://ybnqylupuisyhuldqrgt.supabase.co/storage/v1/object/public/media/boka-nu.jpg',
26
+ 'label', jsonb_build_object('sv', 'Boka nu'),
27
+ 'alt', jsonb_build_object('sv', 'Publik framför scenen på Voyara partykryssning'),
28
+ 'href', '/boka'
29
+ ),
30
+ jsonb_build_object(
31
+ 'id', 'tile-elevkarer',
32
+ 'image', 'https://ybnqylupuisyhuldqrgt.supabase.co/storage/v1/object/public/media/artister-scen.jpg',
33
+ 'label', jsonb_build_object('sv', 'För elevkårer'),
34
+ 'alt', jsonb_build_object('sv', 'Artist på scen ombord'),
35
+ 'href', '/samarbete'
36
+ ),
37
+ jsonb_build_object(
38
+ 'id', 'tile-ambassador',
39
+ 'image', 'https://ybnqylupuisyhuldqrgt.supabase.co/storage/v1/object/public/media/voyara-publik.jpg',
40
+ 'label', jsonb_build_object('sv', 'Bli ambassadör'),
41
+ 'alt', jsonb_build_object('sv', 'Gäster som festar ombord'),
42
+ 'href', '/ambassador'
43
+ )
44
+ )
45
+ )
46
+ ) as blk
47
+ ),
48
+ newblocks as (
49
+ select (
50
+ select coalesce(jsonb_agg(x.b order by x.idx), '[]'::jsonb)
51
+ from (
52
+ select b, idx::numeric as idx from cur, lateral jsonb_array_elements(cur.blocks) with ordinality t(b, idx)
53
+ where b->>'type' <> 'linkTiles'
54
+ union all
55
+ select (select blk from tiles),
56
+ coalesce((
57
+ select max(idx) + 0.5 from cur, lateral jsonb_array_elements(cur.blocks) with ordinality t(b, idx)
58
+ where b->>'type' = 'courseList'
59
+ ), 999)
60
+ ) x
61
+ ) as blocks
62
+ ),
63
+ ins as (
64
+ insert into public.page_versions (page_id, version_no, blocks, note, created_by_email)
65
+ select p.id,
66
+ coalesce((select max(version_no) from public.page_versions pv where pv.page_id = p.id), 0) + 1,
67
+ (select blocks from newblocks),
68
+ 'Add link tiles row (Boka / Elevkårer / Ambassadör)',
69
+ 'system'
70
+ from p
71
+ returning id, page_id
72
+ ),
73
+ deact as (
74
+ update public.page_publications pp set is_active = false
75
+ where pp.page_id = (select id from p) and pp.is_active
76
+ returning 1
77
+ ),
78
+ pub as (
79
+ insert into public.page_publications (page_id, version_id, note)
80
+ select page_id, id, 'Add link tiles row' from ins
81
+ returning page_id, version_id
82
+ )
83
+ update public.pages pg set current_version_id = pub.version_id, updated_at = now()
84
+ from pub where pg.id = pub.page_id;
85
+
86
+ commit;
@@ -0,0 +1 @@
1
+ UPDATE page_versions v SET blocks = (SELECT jsonb_agg(CASE WHEN b->>'type'='linkTiles' THEN jsonb_set(b, '{props,labelAlign}', '"center"') ELSE b END) FROM jsonb_array_elements(v.blocks) b) FROM pages p WHERE v.id=p.current_version_id AND p.key='home';
@@ -0,0 +1 @@
1
+ UPDATE public.locale_domains SET domain = 'byggis.voyara.se', updated_at = now() WHERE domain = 'www.dev.barskola.nu';
@@ -0,0 +1,3 @@
1
+ UPDATE public.page_versions
2
+ SET blocks = replace(blocks::text, 'booking.summerinvasion.se', 'booking.voyara.se')::jsonb
3
+ WHERE blocks::text LIKE '%booking.summerinvasion.se%';