feat: add deposit and weekend km allowance to vehicles, update migrations and booking flow
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -18,6 +18,7 @@ services:
|
|||||||
- ./supabase/migrations/post-boot.sql:/sql/post-boot.sql:ro
|
- ./supabase/migrations/post-boot.sql:/sql/post-boot.sql:ro
|
||||||
- ./supabase/migrations/02-leads.sql:/sql/02-leads.sql:ro
|
- ./supabase/migrations/02-leads.sql:/sql/02-leads.sql:ro
|
||||||
- ./supabase/migrations/03-booking-flow.sql:/sql/03-booking-flow.sql:ro
|
- ./supabase/migrations/03-booking-flow.sql:/sql/03-booking-flow.sql:ro
|
||||||
|
- ./supabase/migrations/04-kaution-weekend-km.sql:/sql/04-kaution-weekend-km.sql:ro
|
||||||
|
|
||||||
kong:
|
kong:
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ services:
|
|||||||
PGRST_DB_ANON_ROLE: anon
|
PGRST_DB_ANON_ROLE: anon
|
||||||
PGRST_JWT_SECRET: ${JWT_SECRET}
|
PGRST_JWT_SECRET: ${JWT_SECRET}
|
||||||
PGRST_DB_USE_LEGACY_GUCS: "false"
|
PGRST_DB_USE_LEGACY_GUCS: "false"
|
||||||
|
PGRST_DB_CHANNEL_ENABLED: "true"
|
||||||
networks: [mccars]
|
networks: [mccars]
|
||||||
logging: { driver: json-file, options: { max-size: "10m", max-file: "3" } }
|
logging: { driver: json-file, options: { max-size: "10m", max-file: "3" } }
|
||||||
|
|
||||||
@@ -210,6 +211,7 @@ services:
|
|||||||
- /mnt/user/appdata/mc-cars/supabase/migrations/post-boot.sql:/sql/post-boot.sql:ro
|
- /mnt/user/appdata/mc-cars/supabase/migrations/post-boot.sql:/sql/post-boot.sql:ro
|
||||||
- /mnt/user/appdata/mc-cars/supabase/migrations/02-leads.sql:/sql/02-leads.sql:ro
|
- /mnt/user/appdata/mc-cars/supabase/migrations/02-leads.sql:/sql/02-leads.sql:ro
|
||||||
- /mnt/user/appdata/mc-cars/supabase/migrations/03-booking-flow.sql:/sql/03-booking-flow.sql:ro
|
- /mnt/user/appdata/mc-cars/supabase/migrations/03-booking-flow.sql:/sql/03-booking-flow.sql:ro
|
||||||
|
- /mnt/user/appdata/mc-cars/supabase/migrations/04-kaution-weekend-km.sql:/sql/04-kaution-weekend-km.sql:ro
|
||||||
entrypoint: ["sh","-c"]
|
entrypoint: ["sh","-c"]
|
||||||
command:
|
command:
|
||||||
- |
|
- |
|
||||||
@@ -229,6 +231,7 @@ services:
|
|||||||
-f /sql/post-boot.sql
|
-f /sql/post-boot.sql
|
||||||
psql "postgresql://postgres:$$PGPASSWORD@db:5432/postgres" -v ON_ERROR_STOP=1 -f /sql/02-leads.sql
|
psql "postgresql://postgres:$$PGPASSWORD@db:5432/postgres" -v ON_ERROR_STOP=1 -f /sql/02-leads.sql
|
||||||
psql "postgresql://postgres:$$PGPASSWORD@db:5432/postgres" -v ON_ERROR_STOP=1 -f /sql/03-booking-flow.sql
|
psql "postgresql://postgres:$$PGPASSWORD@db:5432/postgres" -v ON_ERROR_STOP=1 -f /sql/03-booking-flow.sql
|
||||||
|
psql "postgresql://postgres:$$PGPASSWORD@db:5432/postgres" -v ON_ERROR_STOP=1 -f /sql/04-kaution-weekend-km.sql
|
||||||
echo "post-init done."
|
echo "post-init done."
|
||||||
restart: "no"
|
restart: "no"
|
||||||
networks: [mccars]
|
networks: [mccars]
|
||||||
|
|||||||
+6
-4
@@ -139,10 +139,7 @@
|
|||||||
<span data-i18n="adminPhotoUpload">Foto hochladen (JPG/PNG/WebP, max 50 MB)</span>
|
<span data-i18n="adminPhotoUpload">Foto hochladen (JPG/PNG/WebP, max 50 MB)</span>
|
||||||
<input type="file" id="photoInput" accept="image/*" />
|
<input type="file" id="photoInput" accept="image/*" />
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<input type="hidden" name="photo_url" />
|
||||||
<span data-i18n="adminPhotoUrl">Foto-URL (wird automatisch gesetzt nach Upload)</span>
|
|
||||||
<input type="url" name="photo_url" placeholder="https://..." />
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div class="row2">
|
<div class="row2">
|
||||||
<label><span data-i18n="adminBrand">Marke</span><input name="brand" required /></label>
|
<label><span data-i18n="adminBrand">Marke</span><input name="brand" required /></label>
|
||||||
@@ -163,6 +160,11 @@
|
|||||||
|
|
||||||
<div class="row3">
|
<div class="row3">
|
||||||
<label><span>Max. km/Tag</span><input type="number" name="max_daily_km" min="0" value="150" /></label>
|
<label><span>Max. km/Tag</span><input type="number" name="max_daily_km" min="0" value="150" /></label>
|
||||||
|
<label><span data-i18n="adminKaution">Kaution (€)</span><input type="number" name="kaution_eur" min="1" value="5000" required /></label>
|
||||||
|
<label><span data-i18n="adminMaxKmWeekend">Max. km/Wochenendtag</span><input type="number" name="max_km_weekend" min="0" placeholder="wie km/Tag" /></label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row2">
|
||||||
<label><span data-i18n="adminSort">Reihenfolge</span><input type="number" name="sort_order" value="100" /></label>
|
<label><span data-i18n="adminSort">Reihenfolge</span><input type="number" name="sort_order" value="100" /></label>
|
||||||
<label><span data-i18n="adminLocation">Standort</span><input name="location" value="Steiermark (TBD)" /></label>
|
<label><span data-i18n="adminLocation">Standort</span><input name="location" value="Steiermark (TBD)" /></label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+11
-1
@@ -230,6 +230,8 @@ function loadForEdit(id) {
|
|||||||
vehicleForm.daily_price_eur.value = v.daily_price_eur;
|
vehicleForm.daily_price_eur.value = v.daily_price_eur;
|
||||||
vehicleForm.weekend_price_eur.value = v.weekend_price_eur || 0;
|
vehicleForm.weekend_price_eur.value = v.weekend_price_eur || 0;
|
||||||
vehicleForm.max_daily_km.value = v.max_daily_km || 150;
|
vehicleForm.max_daily_km.value = v.max_daily_km || 150;
|
||||||
|
vehicleForm.kaution_eur.value = v.kaution_eur || 5000;
|
||||||
|
vehicleForm.max_km_weekend.value = v.max_km_weekend || '';
|
||||||
vehicleForm.sort_order.value = v.sort_order;
|
vehicleForm.sort_order.value = v.sort_order;
|
||||||
vehicleForm.location.value = v.location;
|
vehicleForm.location.value = v.location;
|
||||||
vehicleForm.description_de.value = v.description_de;
|
vehicleForm.description_de.value = v.description_de;
|
||||||
@@ -250,6 +252,8 @@ resetBtn.addEventListener("click", () => {
|
|||||||
vehicleForm.seats.value = 2;
|
vehicleForm.seats.value = 2;
|
||||||
vehicleForm.max_daily_km.value = 150;
|
vehicleForm.max_daily_km.value = 150;
|
||||||
vehicleForm.weekend_price_eur.value = 0;
|
vehicleForm.weekend_price_eur.value = 0;
|
||||||
|
vehicleForm.kaution_eur.value = 5000;
|
||||||
|
vehicleForm.max_km_weekend.value = '';
|
||||||
state.currentPhotoPath = null;
|
state.currentPhotoPath = null;
|
||||||
updatePreview("");
|
updatePreview("");
|
||||||
formTitle.textContent = "Neues Fahrzeug";
|
formTitle.textContent = "Neues Fahrzeug";
|
||||||
@@ -273,6 +277,8 @@ vehicleForm.addEventListener("submit", async (e) => {
|
|||||||
daily_price_eur: +fd.get("daily_price_eur") || 0,
|
daily_price_eur: +fd.get("daily_price_eur") || 0,
|
||||||
weekend_price_eur: +fd.get("weekend_price_eur") || 0,
|
weekend_price_eur: +fd.get("weekend_price_eur") || 0,
|
||||||
max_daily_km: +fd.get("max_daily_km") || 150,
|
max_daily_km: +fd.get("max_daily_km") || 150,
|
||||||
|
kaution_eur: +fd.get("kaution_eur") || 5000,
|
||||||
|
max_km_weekend: fd.get("max_km_weekend") ? +fd.get("max_km_weekend") : null,
|
||||||
sort_order: +fd.get("sort_order") || 100,
|
sort_order: +fd.get("sort_order") || 100,
|
||||||
location: fd.get("location") || "Steiermark (TBD)",
|
location: fd.get("location") || "Steiermark (TBD)",
|
||||||
description_de: fd.get("description_de") || "",
|
description_de: fd.get("description_de") || "",
|
||||||
@@ -316,11 +322,15 @@ photoInput.addEventListener("change", async () => {
|
|||||||
formFeedback.className = "form-feedback";
|
formFeedback.className = "form-feedback";
|
||||||
formFeedback.textContent = "Uploading photo...";
|
formFeedback.textContent = "Uploading photo...";
|
||||||
try {
|
try {
|
||||||
|
// Delete old photo if exists
|
||||||
|
if (state.currentPhotoPath) {
|
||||||
|
await supabase.storage.from("vehicle-photos").remove([state.currentPhotoPath]);
|
||||||
|
}
|
||||||
const ext = (file.name.split(".").pop() || "jpg").toLowerCase();
|
const ext = (file.name.split(".").pop() || "jpg").toLowerCase();
|
||||||
const path = `${crypto.randomUUID()}.${ext}`;
|
const path = `${crypto.randomUUID()}.${ext}`;
|
||||||
const { error: upErr } = await supabase.storage
|
const { error: upErr } = await supabase.storage
|
||||||
.from("vehicle-photos")
|
.from("vehicle-photos")
|
||||||
.upload(path, file, { contentType: file.type, upsert: false });
|
.upload(path, file, { contentType: file.type, upsert: true });
|
||||||
if (upErr) throw upErr;
|
if (upErr) throw upErr;
|
||||||
const { data: pub } = supabase.storage.from("vehicle-photos").getPublicUrl(path);
|
const { data: pub } = supabase.storage.from("vehicle-photos").getPublicUrl(path);
|
||||||
state.currentPhotoPath = path;
|
state.currentPhotoPath = path;
|
||||||
|
|||||||
+12
-2
@@ -196,6 +196,14 @@ function openDetails(id) {
|
|||||||
<div><strong>${v.top_speed_kmh}</strong><span>${t("kmh")}</span></div>
|
<div><strong>${v.top_speed_kmh}</strong><span>${t("kmh")}</span></div>
|
||||||
<div><strong>${escapeHtml(v.acceleration)}</strong><span>${t("accel")}</span></div>
|
<div><strong>${escapeHtml(v.acceleration)}</strong><span>${t("accel")}</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="spec-row" style="margin:1rem 0;">
|
||||||
|
<div><strong>${v.seats}</strong><span>${t("seats")}</span></div>
|
||||||
|
<div><strong>€ ${v.weekend_price_eur || v.daily_price_eur}</strong><span>${t("bpfWeekendRate")}</span></div>
|
||||||
|
<div><strong>${v.max_daily_km || 150}</strong><span>${t("bpfMaxKm")}</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="spec-row" style="margin:1rem 0;grid-template-columns:1fr;">
|
||||||
|
<div><strong>€ ${(v.kaution_eur || 5000).toLocaleString("de-DE")}</strong><span>${t("bpfDeposit")}</span></div>
|
||||||
|
</div>
|
||||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:1rem;">
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:1rem;">
|
||||||
<div class="vehicle-price">€ ${v.daily_price_eur}<span> / ${t("perDay")}</span></div>
|
<div class="vehicle-price">€ ${v.daily_price_eur}<span> / ${t("perDay")}</span></div>
|
||||||
<button class="btn" id="dialogBook">${t("bookNow")}</button>
|
<button class="btn" id="dialogBook">${t("bookNow")}</button>
|
||||||
@@ -364,8 +372,10 @@ function updateSidebar() {
|
|||||||
const subtotal = weekdayCost + weekendCost;
|
const subtotal = weekdayCost + weekendCost;
|
||||||
const vat = Math.round(subtotal * 0.20);
|
const vat = Math.round(subtotal * 0.20);
|
||||||
const total = subtotal + vat;
|
const total = subtotal + vat;
|
||||||
const deposit = Math.round(v.daily_price_eur * 2.5);
|
const deposit = v.kaution_eur || 5000;
|
||||||
const includedKm = (v.max_daily_km || 150) * totalDays;
|
const kmPerWeekendDay = v.max_km_weekend || v.max_daily_km || 150;
|
||||||
|
const kmPerWeekday = v.max_daily_km || 150;
|
||||||
|
const includedKm = (weekdays * kmPerWeekday) + (weekendDays * kmPerWeekendDay);
|
||||||
|
|
||||||
bpfSidebarPlaceholder.style.display = "none";
|
bpfSidebarPlaceholder.style.display = "none";
|
||||||
bpfSidebarContent.style.display = "block";
|
bpfSidebarContent.style.display = "block";
|
||||||
|
|||||||
+4
-2
@@ -133,7 +133,6 @@ export const translations = {
|
|||||||
adminNewVehicle: "Neues Fahrzeug",
|
adminNewVehicle: "Neues Fahrzeug",
|
||||||
adminAllVehicles: "Alle Fahrzeuge",
|
adminAllVehicles: "Alle Fahrzeuge",
|
||||||
adminPhotoUpload: "Foto hochladen (JPG/PNG/WebP, max 50 MB)",
|
adminPhotoUpload: "Foto hochladen (JPG/PNG/WebP, max 50 MB)",
|
||||||
adminPhotoUrl: "Foto-URL (wird automatisch gesetzt nach Upload)",
|
|
||||||
adminBrand: "Marke",
|
adminBrand: "Marke",
|
||||||
adminModel: "Modell",
|
adminModel: "Modell",
|
||||||
adminPower: "PS",
|
adminPower: "PS",
|
||||||
@@ -169,6 +168,8 @@ export const translations = {
|
|||||||
adminReceived: "Eingang",
|
adminReceived: "Eingang",
|
||||||
adminVehicleTab: "Fahrzeug",
|
adminVehicleTab: "Fahrzeug",
|
||||||
adminPeriod: "Zeitraum",
|
adminPeriod: "Zeitraum",
|
||||||
|
adminKaution: "Kaution (€)",
|
||||||
|
adminMaxKmWeekend: "Max. km/Wochenendtag",
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
navCars: "Fleet",
|
navCars: "Fleet",
|
||||||
@@ -303,7 +304,6 @@ export const translations = {
|
|||||||
adminNewVehicle: "New vehicle",
|
adminNewVehicle: "New vehicle",
|
||||||
adminAllVehicles: "All vehicles",
|
adminAllVehicles: "All vehicles",
|
||||||
adminPhotoUpload: "Upload photo (JPG/PNG/WebP, max 50 MB)",
|
adminPhotoUpload: "Upload photo (JPG/PNG/WebP, max 50 MB)",
|
||||||
adminPhotoUrl: "Photo URL (auto-set after upload)",
|
|
||||||
adminBrand: "Brand",
|
adminBrand: "Brand",
|
||||||
adminModel: "Model",
|
adminModel: "Model",
|
||||||
adminPower: "HP",
|
adminPower: "HP",
|
||||||
@@ -339,6 +339,8 @@ export const translations = {
|
|||||||
adminReceived: "Received",
|
adminReceived: "Received",
|
||||||
adminVehicleTab: "Vehicle",
|
adminVehicleTab: "Vehicle",
|
||||||
adminPeriod: "Period",
|
adminPeriod: "Period",
|
||||||
|
adminKaution: "Deposit (€)",
|
||||||
|
adminMaxKmWeekend: "Max. km/weekend day",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ begin
|
|||||||
|
|
||||||
-- Let authenticator impersonate app roles.
|
-- Let authenticator impersonate app roles.
|
||||||
execute 'grant anon, authenticated, service_role to authenticator';
|
execute 'grant anon, authenticated, service_role to authenticator';
|
||||||
|
|
||||||
|
-- Let storage_admin impersonate app roles (needed for RLS on storage.objects).
|
||||||
|
execute 'grant anon, authenticated, service_role to supabase_storage_admin';
|
||||||
end
|
end
|
||||||
$roles$;
|
$roles$;
|
||||||
|
|
||||||
@@ -165,34 +168,9 @@ insert into public.vehicles
|
|||||||
(brand, model, power_hp, top_speed_kmh, acceleration, seats,
|
(brand, model, power_hp, top_speed_kmh, acceleration, seats,
|
||||||
daily_price_eur, location, description_de, description_en, photo_url, sort_order)
|
daily_price_eur, location, description_de, description_en, photo_url, sort_order)
|
||||||
values
|
values
|
||||||
('Porsche','911 GT3', 510, 318, '3.4s', 2, 890, 'Steiermark (TBD)',
|
('Ferrari','296 GTB', 830, 330, '2.9s', 2, 850, 'Steiermark (TBD)',
|
||||||
'Puristischer Hochdrehzahl-Saugmotor und kompromissloser Motorsport-Charakter.',
|
'V6-Hybrid mit 830 PS, atemberaubendes Design und kompromisslose Performance auf Strasse und Rennstrecke.',
|
||||||
'Pure high-revving naturally aspirated engine with uncompromising motorsport character.',
|
'V6 hybrid with 830 hp, breathtaking design and uncompromising performance on road and track.',
|
||||||
'https://images.unsplash.com/photo-1611821064430-0d40291d0f0b?auto=format&fit=crop&w=1400&q=80',
|
'/images/ferrari-main-car.png',
|
||||||
10),
|
10)
|
||||||
('Lamborghini','Huracan EVO', 640, 325, '2.9s', 2, 990, 'Steiermark (TBD)',
|
|
||||||
'V10 mit 640 PS, scharfes Design und kompromisslose Performance auf Strasse und Rennstrecke.',
|
|
||||||
'V10 with 640 hp, sharp design and uncompromising performance on road and track.',
|
|
||||||
'https://images.unsplash.com/photo-1544636331-e26879cd4d9b?auto=format&fit=crop&w=1400&q=80',
|
|
||||||
20),
|
|
||||||
('Audi','RS6 Performance', 630, 305, '3.4s', 5, 540, 'Steiermark (TBD)',
|
|
||||||
'Alltagstauglicher Kombi mit brutaler V8-Biturbo-Power und Allradantrieb.',
|
|
||||||
'Everyday-ready estate with brutal twin-turbo V8 power and quattro AWD.',
|
|
||||||
'https://images.unsplash.com/photo-1606664515524-ed2f786a0bd6?auto=format&fit=crop&w=1400&q=80',
|
|
||||||
30),
|
|
||||||
('BMW','M4 Competition', 530, 290, '3.5s', 4, 430, 'Steiermark (TBD)',
|
|
||||||
'Reihensechszylinder-Biturbo mit praeziser Lenkung und sportlichem Fahrwerk.',
|
|
||||||
'Twin-turbo inline-six with precise steering and sporty chassis.',
|
|
||||||
'https://images.unsplash.com/photo-1555215695-3004980ad54e?auto=format&fit=crop&w=1400&q=80',
|
|
||||||
40),
|
|
||||||
('Nissan','GT-R R35', 570, 315, '2.8s', 4, 510, 'Steiermark (TBD)',
|
|
||||||
'Ikonischer Allrad-Supersportler mit Twin-Turbo V6 und brutalem Antritt.',
|
|
||||||
'Iconic AWD supercar with twin-turbo V6 and ferocious launch.',
|
|
||||||
'https://images.unsplash.com/photo-1626668893632-6f3a4466d22f?auto=format&fit=crop&w=1400&q=80',
|
|
||||||
50),
|
|
||||||
('Mercedes-AMG','G63', 585, 220, '4.5s', 5, 620, 'Steiermark (TBD)',
|
|
||||||
'Legendaere G-Klasse mit V8-Biturbo-Performance und unverkennbarem Design.',
|
|
||||||
'Legendary G-Class with V8 biturbo performance and unmistakable design.',
|
|
||||||
'https://images.unsplash.com/photo-1606611013016-969c19ba27bb?auto=format&fit=crop&w=1400&q=80',
|
|
||||||
60)
|
|
||||||
on conflict do nothing;
|
on conflict do nothing;
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ update public.vehicles
|
|||||||
max_daily_km = 150
|
max_daily_km = 150
|
||||||
where weekend_price_eur = 0;
|
where weekend_price_eur = 0;
|
||||||
|
|
||||||
|
-- Ferrari gets specific pricing
|
||||||
|
update public.vehicles
|
||||||
|
set weekend_price_eur = 1100,
|
||||||
|
max_daily_km = 200
|
||||||
|
where brand = 'Ferrari' and model = '296 GTB';
|
||||||
|
|
||||||
-- -----------------------------------------------------------------------------
|
-- -----------------------------------------------------------------------------
|
||||||
-- 2. Lead attachments: documents uploaded during booking flow
|
-- 2. Lead attachments: documents uploaded during booking flow
|
||||||
-- -----------------------------------------------------------------------------
|
-- -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
-- =============================================================================
|
||||||
|
-- MC Cars - Add per-vehicle kaution (deposit) and max_km_weekend columns.
|
||||||
|
-- Idempotent.
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------------------------
|
||||||
|
-- 1. kaution_eur: deposit per vehicle, NOT NULL, default 5000, must be > 0
|
||||||
|
-- -----------------------------------------------------------------------------
|
||||||
|
alter table public.vehicles add column if not exists kaution_eur integer not null default 5000;
|
||||||
|
|
||||||
|
do $$
|
||||||
|
begin
|
||||||
|
if not exists (
|
||||||
|
select 1 from information_schema.check_constraints
|
||||||
|
where constraint_name = 'vehicles_kaution_positive'
|
||||||
|
) then
|
||||||
|
alter table public.vehicles add constraint vehicles_kaution_positive check (kaution_eur > 0);
|
||||||
|
end if;
|
||||||
|
end $$;
|
||||||
|
|
||||||
|
-- -----------------------------------------------------------------------------
|
||||||
|
-- 2. max_km_weekend: optional per-weekend-day km allowance (NULL = use max_daily_km)
|
||||||
|
-- -----------------------------------------------------------------------------
|
||||||
|
alter table public.vehicles add column if not exists max_km_weekend integer default null;
|
||||||
|
|
||||||
|
-- Signal PostgREST to reload its schema cache
|
||||||
|
notify pgrst, 'reload schema';
|
||||||
@@ -60,9 +60,14 @@ on conflict (id) do update
|
|||||||
file_size_limit = excluded.file_size_limit,
|
file_size_limit = excluded.file_size_limit,
|
||||||
allowed_mime_types = excluded.allowed_mime_types;
|
allowed_mime_types = excluded.allowed_mime_types;
|
||||||
|
|
||||||
|
-- Let storage_admin assume app roles for RLS evaluation (idempotent).
|
||||||
|
grant anon, authenticated, service_role to supabase_storage_admin;
|
||||||
|
|
||||||
grant select on storage.buckets to anon, authenticated;
|
grant select on storage.buckets to anon, authenticated;
|
||||||
|
grant all on storage.buckets to service_role;
|
||||||
grant select on storage.objects to anon;
|
grant select on storage.objects to anon;
|
||||||
grant select, insert, update, delete on storage.objects to authenticated;
|
grant select, insert, update, delete on storage.objects to authenticated;
|
||||||
|
grant all on storage.objects to service_role;
|
||||||
|
|
||||||
drop policy if exists "vehicle_photos_public_read" on storage.objects;
|
drop policy if exists "vehicle_photos_public_read" on storage.objects;
|
||||||
drop policy if exists "vehicle_photos_admin_insert" on storage.objects;
|
drop policy if exists "vehicle_photos_admin_insert" on storage.objects;
|
||||||
|
|||||||
Reference in New Issue
Block a user