mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 14:26:42 +02:00
feat: integrate uload and picture, unify package naming
- Add uload project with apps/web structure
- Reorganize from flat to monorepo structure
- Remove PocketBase binary and local data
- Update to pnpm and @uload/web namespace
- Add picture project to monorepo
- Remove embedded git repository
- Unify all package names to @{project}/{app} schema:
- @maerchenzauber/* (was @storyteller/*)
- @manacore/* (was manacore-*, manacore)
- @manadeck/* (was web, backend, manadeck)
- @memoro/* (was memoro-web, landing, memoro)
- @picture/* (already unified)
- @uload/web
- Add convenient dev scripts for all apps:
- pnpm dev:{project}:web
- pnpm dev:{project}:landing
- pnpm dev:{project}:mobile
- pnpm dev:{project}:backend
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c6c4c5a552
commit
c712a2504a
1031 changed files with 189301 additions and 290 deletions
202
picture/apps/web/docs/ADVANCED_GENERATION_SETTINGS.md
Normal file
202
picture/apps/web/docs/ADVANCED_GENERATION_SETTINGS.md
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
# Advanced Generation Settings
|
||||
|
||||
## Overview
|
||||
|
||||
The QuickGenerateBar now includes advanced settings that allow users to customize image generation parameters beyond just the prompt and model selection. These settings are accessible via a settings icon (⚙️) in the generation bar.
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Image Count (Batch Generation)
|
||||
- Generate 1-5 images at once with a single prompt
|
||||
- Each image uses a different random seed for variety
|
||||
- Progress indicator shows "Generiere Bild X/Y..." during batch generation
|
||||
- Success toast shows total count: "X Bilder erfolgreich generiert!"
|
||||
|
||||
**Default**: 1 image
|
||||
|
||||
### 2. Aspect Ratio Selector
|
||||
Choose from three preset aspect ratios:
|
||||
- **Quadratisch** (Square): 1024×1024px
|
||||
- **Hochformat** (Portrait): 832×1216px
|
||||
- **Querformat** (Landscape): 1216×832px
|
||||
|
||||
Visual preview boxes show the relative dimensions.
|
||||
|
||||
**Default**: Square (1024×1024)
|
||||
|
||||
### 3. Steps Slider
|
||||
Control the number of diffusion steps (quality vs. speed):
|
||||
- **Range**: 20-150 steps (increments of 5)
|
||||
- Lower values = faster generation, potentially lower quality
|
||||
- Higher values = slower generation, higher quality/detail
|
||||
- Visual labels: "Schnell" (20) → "Höchste Qualität" (150)
|
||||
|
||||
**Default**: 50 steps
|
||||
|
||||
### 4. Guidance Scale Slider
|
||||
Control how closely the AI follows the prompt:
|
||||
- **Range**: 1-20 (increments of 0.5)
|
||||
- Lower values = more creative/artistic interpretation
|
||||
- Higher values = stricter adherence to prompt
|
||||
- Visual labels: "Kreativ" (1) → "Präzise" (20)
|
||||
- Helper text: "Höhere Werte folgen dem Prompt genauer, niedrigere sind kreativer"
|
||||
|
||||
**Default**: 7.5
|
||||
|
||||
## UI/UX Details
|
||||
|
||||
### Settings Button
|
||||
- **Location**: Between prompt input and Generate button
|
||||
- **Icon**: Gear/settings icon (⚙️)
|
||||
- **Badge**: Blue pulsing dot appears when any setting differs from defaults
|
||||
- **State**: Disabled during generation
|
||||
|
||||
### Modal Layout
|
||||
- **Style**: Glass-blur modal (white/95 with backdrop-blur-xl)
|
||||
- **Size**: max-w-2xl centered
|
||||
- **Close**: ESC key or close button (×)
|
||||
- **Actions**: Cancel (gray) or Übernehmen (blue)
|
||||
|
||||
### Visual Feedback
|
||||
The settings button shows a blue pulsing badge when:
|
||||
- Image count > 1
|
||||
- Aspect ratio ≠ Square
|
||||
- Steps ≠ 50
|
||||
- Guidance scale ≠ 7.5
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Files Modified
|
||||
|
||||
1. **`lib/components/generate/AdvancedSettingsModal.svelte`** (NEW)
|
||||
- Self-contained modal component
|
||||
- Local state management with $effect() for props sync
|
||||
- Exports `AdvancedSettings` and `AspectRatio` types
|
||||
|
||||
2. **`lib/components/gallery/QuickGenerateBar.svelte`**
|
||||
- Added `showAdvancedSettings` state
|
||||
- Added `advancedSettings` state with defaults
|
||||
- Added `hasCustomSettings` derived state for badge
|
||||
- Updated `handleQuickGenerate()` to:
|
||||
- Loop through imageCount
|
||||
- Pass width, height, steps, guidance_scale to API
|
||||
- Show progress per image
|
||||
- Added settings button with badge indicator
|
||||
- Integrated AdvancedSettingsModal component
|
||||
|
||||
3. **`lib/api/generate.ts`**
|
||||
- Extended `GenerateImageParams` interface:
|
||||
```typescript
|
||||
export interface GenerateImageParams {
|
||||
prompt: string;
|
||||
model_id: string;
|
||||
negative_prompt?: string;
|
||||
width?: number; // NEW
|
||||
height?: number; // NEW
|
||||
steps?: number; // NEW
|
||||
guidance_scale?: number; // NEW
|
||||
}
|
||||
```
|
||||
|
||||
### API Integration
|
||||
|
||||
The advanced settings are passed directly to the edge function:
|
||||
|
||||
```typescript
|
||||
const result = await generateImage({
|
||||
prompt: prompt.trim(),
|
||||
model_id: selectedModelId,
|
||||
width: advancedSettings.aspectRatio.width,
|
||||
height: advancedSettings.aspectRatio.height,
|
||||
steps: advancedSettings.steps,
|
||||
guidance_scale: advancedSettings.guidanceScale
|
||||
});
|
||||
```
|
||||
|
||||
**Note**: The edge function (`supabase/functions/generate-image/index.ts`) must handle these parameters and pass them to the image generation API (Replicate, Stability AI, etc.).
|
||||
|
||||
### Batch Generation Flow
|
||||
|
||||
When `imageCount > 1`:
|
||||
1. Loop from 0 to imageCount
|
||||
2. For each iteration:
|
||||
- Update progress: `Generiere Bild ${i + 1}/${totalImages}...`
|
||||
- Call `generateImage()` with same params
|
||||
- Poll for completion: `Verarbeite Bild ${i + 1}/${totalImages}...`
|
||||
- Increment completedImages counter
|
||||
3. Show success toast with total count
|
||||
4. Trigger `onGenerated()` callback to refresh gallery
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential additions inspired by mobile app:
|
||||
- [ ] Tag input for organizing generated images
|
||||
- [ ] Negative prompt field
|
||||
- [ ] Seed input for reproducible generations
|
||||
- [ ] Style presets (e.g., "Photorealistic", "Artistic", "Anime")
|
||||
- [ ] Rate limit indicator
|
||||
- [ ] Batch progress tracker with individual image status
|
||||
- [ ] Save/load preset configurations
|
||||
- [ ] Advanced toggle (show/hide extra options)
|
||||
|
||||
## Testing
|
||||
|
||||
### Manual Test Cases
|
||||
|
||||
1. **Default Generation**
|
||||
- Open generate bar
|
||||
- Enter prompt
|
||||
- Click Generate
|
||||
- Verify: 1 square image at default quality
|
||||
|
||||
2. **Custom Aspect Ratio**
|
||||
- Click settings icon
|
||||
- Select Portrait
|
||||
- Click Übernehmen
|
||||
- Verify: Badge appears on settings button
|
||||
- Generate image
|
||||
- Verify: Image is 832×1216
|
||||
|
||||
3. **Batch Generation**
|
||||
- Open settings
|
||||
- Select 3 images
|
||||
- Click Übernehmen
|
||||
- Generate
|
||||
- Verify: Progress shows "Bild 1/3", "Bild 2/3", "Bild 3/3"
|
||||
- Verify: Toast shows "3 Bilder erfolgreich generiert!"
|
||||
- Verify: 3 images appear in gallery
|
||||
|
||||
4. **Settings Persistence**
|
||||
- Set custom values in modal
|
||||
- Close modal
|
||||
- Re-open modal
|
||||
- Verify: Values are still set
|
||||
|
||||
5. **Settings Reset**
|
||||
- Set custom values
|
||||
- Generate image
|
||||
- Verify: Badge still shows on settings button
|
||||
- Open modal
|
||||
- Change all back to defaults
|
||||
- Verify: Badge disappears
|
||||
|
||||
6. **Keyboard Navigation**
|
||||
- Open modal with click
|
||||
- Press ESC
|
||||
- Verify: Modal closes
|
||||
|
||||
## Design Inspiration
|
||||
|
||||
Based on mobile app's `QuickGenerateBar.tsx` which includes:
|
||||
- ImageCountSelector with pill/counter/compact styles
|
||||
- AspectRatioSelector with visual previews
|
||||
- Slider controls for steps and guidance
|
||||
- Tag input for organization
|
||||
- Rate limiting display
|
||||
- Batch progress tracking
|
||||
|
||||
The web implementation follows similar patterns while adapting to:
|
||||
- Desktop-first layout with responsive mobile view
|
||||
- Glass-blur aesthetic matching existing UI
|
||||
- Svelte 5 runes instead of React hooks
|
||||
- Simpler initial feature set (can expand later)
|
||||
120
picture/apps/web/docs/STORAGE_SETUP.md
Normal file
120
picture/apps/web/docs/STORAGE_SETUP.md
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# Storage Bucket Setup für User Uploads
|
||||
|
||||
## Schritt 1: SQL Statement ausführen
|
||||
|
||||
### Option A: Erste Installation (Policies existieren noch nicht)
|
||||
1. Öffne die **Supabase Dashboard**: https://supabase.com/dashboard
|
||||
2. Wähle dein Projekt aus
|
||||
3. Navigiere zu **SQL Editor**
|
||||
4. Kopiere den Inhalt von `setup-storage-bucket.sql`
|
||||
5. Führe das SQL-Script aus
|
||||
|
||||
### Option B: Update (Policies existieren bereits)
|
||||
1. Öffne die **Supabase Dashboard**: https://supabase.com/dashboard
|
||||
2. Wähle dein Projekt aus
|
||||
3. Navigiere zu **SQL Editor**
|
||||
4. Kopiere den Inhalt von `update-storage-policies.sql`
|
||||
5. Führe das SQL-Script aus
|
||||
|
||||
**Falls Fehler "policy already exists"**: Verwende `update-storage-policies.sql` statt `setup-storage-bucket.sql`
|
||||
|
||||
## Schritt 2: Überprüfung
|
||||
|
||||
### Bucket überprüfen
|
||||
Navigiere zu **Storage** im Supabase Dashboard:
|
||||
- Du solltest einen Bucket namens `user-uploads` sehen
|
||||
- Public: ✓ Enabled
|
||||
- File Size Limit: 10 MB
|
||||
- Allowed MIME types: image/jpeg, image/jpg, image/png, image/webp
|
||||
|
||||
### Policies überprüfen
|
||||
Navigiere zu **Storage > Policies**:
|
||||
- Du solltest 4 Policies für `user-uploads` sehen:
|
||||
- ✓ Users can upload their own images (INSERT)
|
||||
- ✓ Public images are publicly accessible (SELECT)
|
||||
- ✓ Users can update their own images (UPDATE)
|
||||
- ✓ Users can delete their own images (DELETE)
|
||||
|
||||
## Schritt 3: Testen
|
||||
|
||||
### Test 1: Upload über die Web-App
|
||||
1. Öffne die Web-App: http://localhost:5173/app/upload
|
||||
2. Wähle ein Bild aus oder nutze Drag & Drop
|
||||
3. Klicke auf "Upload"
|
||||
4. Das Bild sollte erfolgreich hochgeladen werden
|
||||
5. Überprüfe in **Storage > user-uploads** im Supabase Dashboard
|
||||
|
||||
### Test 2: Zugriff auf öffentliche URL
|
||||
1. Nachdem Upload erfolgreich war, kopiere die `public_url` aus der Konsole
|
||||
2. Öffne die URL in einem neuen Browser-Tab
|
||||
3. Das Bild sollte sichtbar sein (ohne Authentifizierung)
|
||||
|
||||
### Test 3: Galerie-Integration
|
||||
1. Navigiere zur Galerie: http://localhost:5173/app/gallery
|
||||
2. Die hochgeladenen Bilder sollten in der Galerie erscheinen
|
||||
3. Klicke auf ein Bild, um die Detail-Ansicht zu öffnen
|
||||
|
||||
## Datei-Struktur im Bucket
|
||||
|
||||
```
|
||||
user-uploads/
|
||||
├── {user_id_1}/
|
||||
│ ├── 1234567890-abc123.jpg
|
||||
│ ├── 1234567891-def456.png
|
||||
│ └── 1234567892-ghi789.webp
|
||||
└── {user_id_2}/
|
||||
├── 1234567893-jkl012.jpg
|
||||
└── 1234567894-mno345.png
|
||||
```
|
||||
|
||||
## Sicherheit
|
||||
|
||||
### ✅ Was ist geschützt:
|
||||
- User können nur in ihren eigenen Ordner hochladen
|
||||
- User können nur ihre eigenen Dateien bearbeiten/löschen
|
||||
- Upload nur für authentifizierte User
|
||||
- Datei-Größe ist auf 10MB begrenzt
|
||||
- Nur erlaubte Bild-Formate (JPG, PNG, WebP)
|
||||
|
||||
### ⚠️ Was ist öffentlich:
|
||||
- Alle hochgeladenen Bilder sind über ihre public_url zugänglich
|
||||
- Jeder mit der URL kann das Bild sehen (auch ohne Account)
|
||||
- Dies ist gewollt für die Galerie-Anzeige
|
||||
|
||||
### 🔒 Optionale Verbesserungen für später:
|
||||
- Private Bilder: Separate Bucket für private Uploads
|
||||
- Signed URLs: Temporäre URLs für sensible Inhalte
|
||||
- CDN: CloudFlare oder AWS CloudFront vor Supabase Storage
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Fehler: "Bucket bereits vorhanden"
|
||||
- Kein Problem! Das Script verwendet `ON CONFLICT DO NOTHING`
|
||||
- Die Policies werden trotzdem erstellt
|
||||
|
||||
### Fehler: "Permission denied"
|
||||
1. Überprüfe ob du als authentifizierter User eingeloggt bist
|
||||
2. Überprüfe die Policies im Supabase Dashboard
|
||||
3. Führe das SQL-Script erneut aus
|
||||
|
||||
### Fehler: "File too large"
|
||||
- Stelle sicher, dass die Datei kleiner als 10MB ist
|
||||
- Die Validierung erfolgt sowohl im Frontend als auch im Backend
|
||||
|
||||
### Bilder werden nicht in der Galerie angezeigt
|
||||
1. Überprüfe ob der Bucket `public` ist
|
||||
2. Überprüfe ob die `public_url` korrekt generiert wird
|
||||
3. Öffne die Browser-Konsole für Fehler-Logs
|
||||
|
||||
## Alternative: UI-basiertes Setup
|
||||
|
||||
Falls du das SQL-Script nicht ausführen möchtest, kannst du den Bucket auch manuell im UI erstellen:
|
||||
|
||||
1. **Storage > Create Bucket**
|
||||
- Name: `user-uploads`
|
||||
- Public: ✓ Enable
|
||||
- File Size Limit: 10485760 (10MB)
|
||||
- Allowed MIME types: image/jpeg, image/jpg, image/png, image/webp
|
||||
|
||||
2. **Storage > Policies > New Policy**
|
||||
- Erstelle die 4 Policies manuell mit den gleichen Bedingungen wie im SQL-Script
|
||||
101
picture/apps/web/docs/setup-storage-bucket.sql
Normal file
101
picture/apps/web/docs/setup-storage-bucket.sql
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
-- ============================================
|
||||
-- Storage Bucket Setup für User Uploads
|
||||
-- ============================================
|
||||
-- Dieses Script muss in der Supabase SQL-Konsole ausgeführt werden
|
||||
|
||||
-- 1. Erstelle Storage Bucket für User Uploads
|
||||
INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)
|
||||
VALUES (
|
||||
'user-uploads',
|
||||
'user-uploads',
|
||||
true, -- Public bucket, damit Bilder über public_url zugänglich sind
|
||||
10485760, -- 10MB in Bytes (10 * 1024 * 1024)
|
||||
ARRAY['image/jpeg', 'image/jpg', 'image/png', 'image/webp']::text[]
|
||||
)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- 2. Storage Policy: Benutzer können nur ihre eigenen Dateien hochladen
|
||||
CREATE POLICY "Users can upload their own images"
|
||||
ON storage.objects
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (
|
||||
bucket_id = 'user-uploads' AND
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
-- 3. Storage Policy: Jeder kann Bilder lesen (public bucket)
|
||||
CREATE POLICY "Public images are publicly accessible"
|
||||
ON storage.objects
|
||||
FOR SELECT
|
||||
TO public
|
||||
USING (bucket_id = 'user-uploads');
|
||||
|
||||
-- 4. Storage Policy: Benutzer können nur ihre eigenen Dateien aktualisieren
|
||||
CREATE POLICY "Users can update their own images"
|
||||
ON storage.objects
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (
|
||||
bucket_id = 'user-uploads' AND
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
)
|
||||
WITH CHECK (
|
||||
bucket_id = 'user-uploads' AND
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
-- 5. Storage Policy: Benutzer können nur ihre eigenen Dateien löschen
|
||||
CREATE POLICY "Users can delete their own images"
|
||||
ON storage.objects
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (
|
||||
bucket_id = 'user-uploads' AND
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
-- ============================================
|
||||
-- Überprüfung der Bucket-Konfiguration
|
||||
-- ============================================
|
||||
-- Führe diese Queries aus, um die Konfiguration zu überprüfen:
|
||||
|
||||
-- Bucket-Details anzeigen
|
||||
SELECT * FROM storage.buckets WHERE id = 'user-uploads';
|
||||
|
||||
-- Alle Policies für den Bucket anzeigen
|
||||
SELECT
|
||||
schemaname,
|
||||
tablename,
|
||||
policyname,
|
||||
permissive,
|
||||
roles,
|
||||
cmd,
|
||||
qual,
|
||||
with_check
|
||||
FROM pg_policies
|
||||
WHERE tablename = 'objects'
|
||||
AND policyname ILIKE '%user%'
|
||||
ORDER BY policyname;
|
||||
|
||||
-- ============================================
|
||||
-- Hinweise
|
||||
-- ============================================
|
||||
--
|
||||
-- 1. Die Datei-Struktur im Bucket ist: user-uploads/{user_id}/{timestamp}-{random}.{ext}
|
||||
-- Dies stellt sicher, dass jeder User nur auf seine eigenen Dateien zugreifen kann.
|
||||
--
|
||||
-- 2. Der Bucket ist PUBLIC, d.h. Bilder sind über die public_url ohne Auth zugänglich.
|
||||
-- Dies ist notwendig, damit Bilder in der Galerie angezeigt werden können.
|
||||
--
|
||||
-- 3. Die Policies stellen sicher, dass:
|
||||
-- - Nur authentifizierte User hochladen können
|
||||
-- - User nur in ihren eigenen Ordner ({user_id}/) hochladen können
|
||||
-- - Jeder User nur seine eigenen Dateien bearbeiten/löschen kann
|
||||
-- - Alle Bilder öffentlich lesbar sind
|
||||
--
|
||||
-- 4. File Size Limit: 10MB pro Datei
|
||||
-- Allowed Types: JPG, JPEG, PNG, WebP
|
||||
--
|
||||
-- 5. Falls der Bucket bereits existiert, wird er nicht neu erstellt (ON CONFLICT DO NOTHING)
|
||||
--
|
||||
92
picture/apps/web/docs/update-storage-policies.sql
Normal file
92
picture/apps/web/docs/update-storage-policies.sql
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
-- ============================================
|
||||
-- Storage Bucket Update - Policies aktualisieren
|
||||
-- ============================================
|
||||
-- Dieses Script aktualisiert die bestehenden Policies
|
||||
|
||||
-- 1. Lösche bestehende Policies (falls vorhanden)
|
||||
DROP POLICY IF EXISTS "Users can upload their own images" ON storage.objects;
|
||||
DROP POLICY IF EXISTS "Public images are publicly accessible" ON storage.objects;
|
||||
DROP POLICY IF EXISTS "Users can update their own images" ON storage.objects;
|
||||
DROP POLICY IF EXISTS "Users can delete their own images" ON storage.objects;
|
||||
|
||||
-- 2. Erstelle Bucket (falls nicht vorhanden)
|
||||
INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)
|
||||
VALUES (
|
||||
'user-uploads',
|
||||
'user-uploads',
|
||||
true,
|
||||
10485760, -- 10MB
|
||||
ARRAY['image/jpeg', 'image/jpg', 'image/png', 'image/webp']::text[]
|
||||
)
|
||||
ON CONFLICT (id)
|
||||
DO UPDATE SET
|
||||
public = EXCLUDED.public,
|
||||
file_size_limit = EXCLUDED.file_size_limit,
|
||||
allowed_mime_types = EXCLUDED.allowed_mime_types;
|
||||
|
||||
-- 3. Erstelle Policies neu
|
||||
CREATE POLICY "Users can upload their own images"
|
||||
ON storage.objects
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (
|
||||
bucket_id = 'user-uploads' AND
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
CREATE POLICY "Public images are publicly accessible"
|
||||
ON storage.objects
|
||||
FOR SELECT
|
||||
TO public
|
||||
USING (bucket_id = 'user-uploads');
|
||||
|
||||
CREATE POLICY "Users can update their own images"
|
||||
ON storage.objects
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (
|
||||
bucket_id = 'user-uploads' AND
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
)
|
||||
WITH CHECK (
|
||||
bucket_id = 'user-uploads' AND
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can delete their own images"
|
||||
ON storage.objects
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (
|
||||
bucket_id = 'user-uploads' AND
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
-- ============================================
|
||||
-- Überprüfung
|
||||
-- ============================================
|
||||
|
||||
-- Bucket-Details
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
public,
|
||||
file_size_limit,
|
||||
allowed_mime_types
|
||||
FROM storage.buckets
|
||||
WHERE id = 'user-uploads';
|
||||
|
||||
-- Policies
|
||||
SELECT
|
||||
policyname,
|
||||
cmd,
|
||||
roles
|
||||
FROM pg_policies
|
||||
WHERE tablename = 'objects'
|
||||
AND (
|
||||
policyname ILIKE '%upload%' OR
|
||||
policyname ILIKE '%public images%' OR
|
||||
policyname ILIKE '%update%' OR
|
||||
policyname ILIKE '%delete%'
|
||||
)
|
||||
ORDER BY policyname;
|
||||
Loading…
Add table
Add a link
Reference in a new issue