Remodeled database and api to prepare for move

This commit is contained in:
Alexis
2024-05-15 17:18:17 +02:00
parent 3a8e8b0947
commit 49e523485b
21 changed files with 479 additions and 274 deletions

View File

@@ -0,0 +1,12 @@
<script lang="ts" setup>
const route = useRoute()
const worldId = route.params.id
const { data: calendar } = await useLazyFetch(`/api/calendars/query?world_id=${worldId}`)
</script>
<template>
<pre>
{{ calendar }}
</pre>
</template>

View File

@@ -0,0 +1,55 @@
<script lang="ts" setup>
const user = useSupabaseUser()
const { data: worlds } = await useLazyFetch('/api/worlds')
</script>
<template>
<main class="p-8">
<Heading>{{ user?.user_metadata.full_name }}</Heading>
<section v-if="worlds?.data" class="mt-4">
<h2 class="mb-4 text-lg font-bold">
Mondes
</h2>
<ul class="grid md:grid-cols-3 gap-2">
<li v-for="(world, i) in worlds.data" :key="i">
<UiCard
class="w-full transition-all"
:link="`/calendar/${world.id}`"
:class="{
'hover:bg-slate-50 dark:hover:bg-sky-950 dark:focus-within:outline-sky-900': !world.color,
'bg-red-100 dark:bg-red-950 border-red-200 hover:bg-red-50 dark:hover:bg-red-900 dark:border-red-900 dark:focus-within:outline-red-900': world.color === 'red',
'bg-orange-100 dark:bg-orange-950 border-orange-200 hover:bg-orange-50 dark:hover:bg-orange-900 dark:border-orange-900 dark:focus-within:outline-orange-900': world.color === 'orange',
'bg-amber-100 dark:bg-amber-950 border-amber-200 hover:bg-amber-50 dark:hover:bg-amber-900 dark:border-amber-900 dark:focus-within:outline-amber-900': world.color === 'amber',
'bg-yellow-100 dark:bg-yellow-950 border-yellow-200 hover:bg-yellow-50 dark:hover:bg-yellow-900 dark:border-yellow-900 dark:focus-within:outline-yellow-900': world.color === 'yellow',
'bg-lime-100 dark:bg-lime-950 border-lime-200 hover:bg-lime-50 dark:hover:bg-lime-900 dark:border-lime-900 dark:focus-within:outline-lime-900': world.color === 'lime',
' bg-green-100 dark:bg-green-950 border-green-200 hover:bg-green-50 dark:hover:bg-green-900 dark:border-green-900 dark:focus-within:outline-green-900': world.color === 'green',
'bg-emerald-100 dark:bg-emerald-950 border-emerald-200 hover:bg-emerald-50 dark:hover:bg-emerald-900 dark:border-emerald-900 dark:focus-within:outline-emerald-900': world.color === 'emerald',
'bg-teal-100 dark:bg-teal-950 border-teal-200 hover:bg-teal-50 dark:hover:bg-teal-900 dark:border-teal-900 dark:focus-within:outline-teal-900': world.color === 'teal',
'bg-cyan-100 dark:bg-cyan-950 border-cyan-200 hover:bg-cyan-50 dark:hover:bg-cyan-900 dark:border-cyan-900 dark:focus-within:outline-cyan-900': world.color === 'cyan',
'bg-sky-100 dark:bg-sky-950 border-sky-200 hover:bg-sky-50 dark:hover:bg-sky-900 dark:border-sky-900 dark:focus-within:outline-sky-900': world.color === 'sky',
'bg-blue-100 dark:bg-blue-950 border-blue-200 hover:bg-blue-50 dark:hover:bg-blue-900 dark:border-blue-900 dark:focus-within:outline-blue-900': world.color === 'blue',
'bg-indigo-100 dark:bg-indigo-950 border-indigo-200 hover:bg-indigo-50 dark:hover:bg-indigo-900 dark:border-indigo-900 dark:focus-within:outline-indigo-900': world.color === 'indigo',
'bg-violet-100 dark:bg-violet-950 border-violet-200 hover:bg-violet-50 dark:hover:bg-violet-900 dark:border-violet-900 dark:focus-within:outline-violet-900': world.color === 'violet',
'bg-purple-100 dark:bg-purple-950 border-purple-200 hover:bg-purple-50 dark:hover:bg-purple-900 dark:border-purple-900 dark:focus-within:outline-purple-900': world.color === 'purple',
'bg-fuchsia-100 dark:bg-fuchsia-950 border-fuchsia-200 hover:bg-fuchsia-50 dark:hover:bg-fuchsia-900 dark:border-fuchsia-900 dark:focus-within:outline-fuchsia-900': world.color === 'fuchsia',
'bg-pink-100 dark:bg-pink-950 border-pink-200 hover:bg-pink-50 dark:hover:bg-pink-900 dark:border-pink-900 dark:focus-within:outline-pink-900': world.color === 'pink',
'bg-pink-100 dark:bg-rose-950 border-rose-200 hover:bg-rose-50 dark:hover:bg-rose-900 dark:border-rose-900 dark:focus-within:outline-rose-900': world.color === 'rose',
'text-slate-100 bg-slate-900 border-slate-700 hover:bg-slate-700 dark:hover:bg-slate-800 dark:border-slate-900 dark:focus-within:outline-slate-900': world.color === 'black',
' hover:bg-slate-50 dark:hover:text-slate-900 dark:hover:bg-slate-300 dark:border-slate-500 dark:focus-within:outline-slate-100': world.color === 'white',
}"
>
<UiCardHeader>
<UiCardTitle>{{ world.name }}</UiCardTitle>
</UiCardHeader>
<UiCardContent>
<p class="italic">{{ world.description }}</p>
</UiCardContent>
</UiCard>
</li>
</ul>
</section>
</main>
</template>

View File

@@ -1,9 +0,0 @@
<script lang="ts" setup>
const user = useSupabaseUser()
</script>
<template>
<div class="p-8">
<Heading>{{ user?.user_metadata.full_name }}</Heading>
</div>
</template>

View File

@@ -12,7 +12,7 @@ const props = defineProps<{
<div
:class="
cn('rounded-lg border bg-card text-card-foreground shadow-sm transition-all', props.class, {
'relative outline outline-2 outline-offset-4 outline-transparent hover:bg-sky-950 hover:-translate-y-[.2rem] focus-within:outline-sky-900':
'relative outline outline-2 outline-offset-4 outline-transparent hover:-translate-y-[.2rem]':
props.link
})
"

6
models/CalendarConfig.ts Normal file
View File

@@ -0,0 +1,6 @@
export interface CalendarConfig {
months: string[]
monthsPerYear: number
daysPerMonth: number
// todayDate: any
}

7
models/World.ts Normal file
View File

@@ -0,0 +1,7 @@
export interface World {
id: number
uuid: string
name: string
description?: string
color?: string
}

View File

@@ -28,7 +28,8 @@
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
"vue": "^3.4.27",
"vue-router": "^4.3.2"
"vue-router": "^4.3.2",
"zod": "^3.23.8"
},
"devDependencies": {
"@nuxtjs/color-mode": "^3.4.1",

30
pages/calendar/[id].vue Normal file
View File

@@ -0,0 +1,30 @@
<script lang="ts" setup>
import type { MenuItem } from '~/components/global/SidebarProps';
const user = useSupabaseUser()
useHead({
title: 'Calendrier'
})
definePageMeta({
middleware: ['auth-guard']
})
// Redirect user back home when they log out on the page
watch(user, (n, _o) => {
if (!n) {
navigateTo('/')
}
})
const sidebarMenu: MenuItem[] = []
</script>
<template>
<div class="h-full grid grid-cols-[auto_1fr]">
<Sidebar :menu-items="sidebarMenu" />
<CalendarDashboard />
</div>
</template>

View File

@@ -13,7 +13,7 @@ const sidebarMenu: MenuItem[] = []
<Sidebar :menu-items="sidebarMenu" is-home />
<div class="h-full grid place-items-center">
<UiCard class="w-1/3 min-w-72" link="/calendar">
<UiCard class="w-1/3 min-w-72 hover:bg-sky-950 focus-within:outline-sky-900" link="/calendar">
<UiCardHeader>
<UiCardTitle>Calendrier</UiCardTitle>
<UiCardDescription>

View File

@@ -21,9 +21,9 @@ const sidebarMenu: MenuItem[] = []
</script>
<template>
<main class="h-full grid grid-cols-[auto_1fr]">
<div class="h-full grid grid-cols-[auto_1fr]">
<Sidebar :menu-items="sidebarMenu" />
<ProfileLayout />
</main>
<ProfileDashboard />
</div>
</template>

8
pnpm-lock.yaml generated
View File

@@ -56,6 +56,9 @@ importers:
vue-router:
specifier: ^4.3.2
version: 4.3.2(vue@3.4.27(typescript@5.4.5))
zod:
specifier: ^3.23.8
version: 3.23.8
devDependencies:
'@nuxtjs/color-mode':
specifier: ^3.4.1
@@ -4734,6 +4737,9 @@ packages:
resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
engines: {node: '>= 14'}
zod@3.23.8:
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
snapshots:
'@alloc/quick-lru@5.2.0': {}
@@ -10202,3 +10208,5 @@ snapshots:
archiver-utils: 5.0.2
compress-commons: 6.0.2
readable-stream: 4.5.2
zod@3.23.8: {}

View File

@@ -0,0 +1,23 @@
import { serverSupabaseClient } from "#supabase/server";
import { z } from 'zod'
const querySchema = z.object({
world_id: z.number({ coerce: true }).positive().int()
})
export default defineEventHandler(async (event) => {
const client = await serverSupabaseClient(event)
const query = await getValidatedQuery(event, querySchema.parse)
const output = client
.from('world_calendars')
.select(`
id,
months,
days_per_year,
events (*)
`)
.eq('world_id', query.world_id)
return output
})

View File

@@ -1,252 +0,0 @@
export default defineEventHandler(() => {
return [
/**
* Player characters
*/
// "Les Milles Cages"
{
name: 'Sulvan Trois-Barbes',
birth: { day: 20, month: 3, year: 3169 },
wiki: 'https://alexcreates.fr/leim/index.php/Sulvan_Trois-Barbes',
category: 'joueur',
secondaryCategories: ['criminel', 'étincelle']
},
{
name: 'Vascylly',
birth: { day: 3, month: 5, year: 3181 },
wiki: 'https://alexcreates.fr/leim/index.php/Vascylly',
category: 'joueur',
secondaryCategories: ['mage']
},
{
name: 'Tara Belyus',
birth: { day: 14, month: 9, year: 3186 },
category: 'joueur',
secondaryCategories: ['mage']
},
// "Les Cloches de Cantane"
{
name: 'Malik',
birth: { day: 22, month: 8, year: 3181 },
category: 'joueur',
secondaryCategories: ['scientifique']
},
{
name: 'Elie',
birth: { day: 5, month: 6, year: 3192 },
category: 'joueur',
secondaryCategories: ['ecclésiastique']
},
{
name: 'Clayron',
birth: { day: 3, month: 5, year: 3178 },
category: 'joueur',
secondaryCategories: ['sentinelle']
},
/**
* NPC
*/
// Counts of the Alliance
{
name: 'Alfrid de Lagarde',
birth: { day: 29, month: 7, year: 3193 },
wiki: 'https://alexcreates.fr/leim/index.php/Alfrid_de_Lagarde',
category: 'comte',
secondaryCategories: ['sentinelle']
},
{
name: 'Alaric de Lagarde',
birth: { day: 23, month: 8, year: 3192 },
wiki: 'https://alexcreates.fr/leim/index.php/Alaric_de_Lagarde',
category: 'comte',
secondaryCategories: ['sentinelle']
},
{
name: 'Anastael III de Quillon',
birth: { day: 1, month: 5, year: 3184 },
wiki: 'https://alexcreates.fr/leim/index.php/Anastael_III_de_Quillon',
category: 'comte',
secondaryCategories: ['sentinelle', 'buse blanche']
},
{
name: 'Antoine de Mireloin',
birth: { day: 31, month: 5, year: 3190 },
wiki: 'https://alexcreates.fr/leim/index.php/Antoine_de_Mireloin',
category: 'comte'
},
{
name: 'Armance Ronchère',
birth: { day: 1, month: 1, year: 3132 },
wiki: 'https://alexcreates.fr/leim/index.php/Armance_Ronchère',
category: 'comte'
},
{
name: 'Baranne Rougefer',
birth: { day: 1, month: 0, year: 3175 },
wiki: 'https://alexcreates.fr/leim/index.php/Baranne_Rougefer',
category: 'comte',
secondaryCategories: ['sentinelle']
},
{
name: 'Béatrice II de Grandlac',
birth: { day: 21, month: 4, year: 3158 },
wiki: 'https://alexcreates.fr/leim/index.php/Béatrice_II_de_Grandlac',
category: 'comte',
secondaryCategories: ['mage']
},
{
name: 'Favio Asharos-Losantelle',
birth: { day: 17, month: 3, year: 3091 },
wiki: 'https://alexcreates.fr/leim/index.php/Favio_Asharos-Losantelle',
category: 'comte',
secondaryCategories: ['mage']
},
{
name: 'Firmin de Montardieu',
birth: { day: 9, month: 2, year: 3203 },
wiki: 'https://alexcreates.fr/leim/index.php/Firmin_de_Montardieu',
category: 'comte'
},
{
name: 'Laura de Montardieu',
birth: { day: 32, month: 3, year: 3167 },
death: { day: 1, month: 4, year: 3217 },
hiddenDeath: true,
wiki: 'https://alexcreates.fr/leim/index.php/Laura_de_Montardieu',
category: 'comte'
},
{
name: 'Lazarus Tymos',
birth: { day: 29, month: 9, year: 3145 },
wiki: 'https://alexcreates.fr/leim/index.php/Lazarus_Tymos',
category: 'comte',
secondaryCategories: ['mage', 'buse blanche']
},
{
name: 'Marion de Corambre',
birth: { day: 14, month: 7, year: 3190 },
wiki: 'https://alexcreates.fr/leim/index.php/Marion_de_Corambre',
category: 'comte',
secondaryCategories: ['scientifique', 'ecclésiastique']
},
{
name: 'Relforg Pergaré',
birth: { day: 18, month: 9, year: 3182 },
wiki: 'https://alexcreates.fr/leim/index.php/Relforg_Pergaré',
category: 'comte'
},
{
name: 'Vilgarde de Ternâcre',
birth: { day: 3, month: 3, year: 2998 },
wiki: 'https://alexcreates.fr/leim/index.php/Vilgarde_de_Ternâcre',
category: 'comte'
},
{
name: 'Ysildy Milopée',
birth: { day: 3, month: 1, year: 3187 },
wiki: 'https://alexcreates.fr/leim/index.php/Ysildy_Milopée',
category: 'comte',
secondaryCategories: ['mage', 'scientifique', 'professeur']
},
// Sparks
{
name: 'Izàc Tymos',
birth: { day: 13, month: 6, year: 3192 },
wiki: 'https://alexcreates.fr/leim/index.php/Izàc_Tymos',
category: 'mage',
secondaryCategories: ['étincelle', 'criminel', 'professeur', 'scientifique']
},
{
name: 'Tvernée',
birth: { day: 19, month: 2, year: 3205 },
wiki: 'https://alexcreates.fr/leim/index.php/Tvernée',
category: 'étincelle',
secondaryCategories: ['criminel']
},
// Pirates
{
name: 'Räzal',
birth: { day: 13, month: 8, year: 3178 },
wiki: 'https://alexcreates.fr/leim/index.php/Räzal'
},
// Legends
{
name: 'Jorhas Kirendre',
birth: { day: 2, month: 9, year: -452 },
death: { day: 2, month: 2, year: -419 },
category: 'sentinelle',
wiki: 'https://alexcreates.fr/leim/index.php/Jorhas_Kirendre'
},
// "Les Milles Cages"
{
name: 'Ernestin Pomel',
birth: { day: 11, month: 2, year: 3179 },
wiki: 'https://alexcreates.fr/leim/index.php/Ernestin_Pomel',
category: 'mage'
},
{
name: 'Quacille Lévios',
birth: { day: 3, month: 6, year: 3162 },
wiki: 'https://alexcreates.fr/leim/index.php/Quacille_Lévios',
category: 'professeur',
secondaryCategories: ['mage']
},
{
name: 'Morel Lévios',
birth: { day: 26, month: 3, year: 3157 },
wiki: 'https://alexcreates.fr/leim/index.php/Morel_Lévios',
category: 'sentinelle',
secondaryCategories: ['mage', 'buse blanche']
},
{
name: 'Anastael Simon',
birth: { day: 32, month: 2, year: 3166 },
wiki: 'https://alexcreates.fr/leim/index.php/Anastael_Simon',
category: 'étincelle',
secondaryCategories: ['mage']
},
{
name: 'Grestain',
birth: { day: 9, month: 2, year: 3162 },
wiki: 'https://alexcreates.fr/leim/index.php/Grestain',
category: 'criminel',
secondaryCategories: ['mage']
},
{
name: 'Lucien Malanth',
birth: { day: 31, month: 4, year: 3167 },
wiki: 'https://alexcreates.fr/leim/index.php/Lucien_Malanth',
category: 'criminel',
secondaryCategories: ['mage']
},
{
name: 'Tivian Rodhus',
birth: { day: 13, month: 3, year: 3157 },
wiki: 'https://alexcreates.fr/leim/index.php/Tivian_Rodhus',
category: 'professeur',
secondaryCategories: ['mage', 'criminel']
},
// "Les Cloches de Cantane"
{
name: 'Bénédicte Vaht',
description: "Moine d'Ikami ayant entrepris la construction du Pilier Blanc de Cantane",
birth: { day: 28, month: 6, year: 3139 },
category: 'ecclésiastique'
},
{
name: 'Taleb Vaht',
description:
"Fils de Bénédicte, il s'est engagé auprès des Étincelles comme alchimiste artificier.",
birth: { day: 9, month: 1, year: 3180 },
death: { day: 28, month: 7, year: 3209 },
category: 'étincelle',
secondaryCategories: ['scientifique']
}
]
})

View File

@@ -0,0 +1,18 @@
import { serverSupabaseClient } from "#supabase/server";
import type { Character } from "~/models/Characters";
export default defineEventHandler(async (event) => {
const client = await serverSupabaseClient(event)
return client.from('characters')
.select(`
id,
name,
description,
birth,
death,
wiki,
characters_category (id, name)
`)
.returns<Character[]>()
})

View File

@@ -0,0 +1,29 @@
import { serverSupabaseClient } from "#supabase/server";
import { z } from 'zod'
const querySchema = z.object({
world_id: z.number({ coerce: true }).positive().int()
})
export default defineEventHandler(async (event) => {
const client = await serverSupabaseClient(event)
const query = await getValidatedQuery(event, querySchema.parse)
const output = client
.from('characters')
.select(`
id,
name,
description,
birth,
death,
wiki,
characters_category (id, name)
`)
if (query.world_id) {
output.eq('world_id', query.world_id)
}
return output
})

View File

@@ -0,0 +1,23 @@
import { serverSupabaseClient } from "#supabase/server";
import { z } from 'zod'
const querySchema = z.object({
world_id: z.number({ coerce: true }).positive().int()
})
export default defineEventHandler(async (event) => {
const client = await serverSupabaseClient(event)
const query = await getValidatedQuery(event, querySchema.parse)
const output = client
.from('events')
.select(`
id,
title,
description,
world_calendars (id, world_id)
`)
.eq('world_calendars.world_id', query.world_id)
return output
})

View File

@@ -0,0 +1,10 @@
import { serverSupabaseClient } from "#supabase/server";
import type { World } from "~/models/World";
export default defineEventHandler(async (event) => {
const client = await serverSupabaseClient(event)
return client.from('worlds')
.select(`id, name, description, color`)
.returns<World[]>()
})

View File

@@ -4,9 +4,11 @@
-- Custom types
create type public.app_permission as enum ('events.see.hidden', 'users.ban');
create type public.app_role as enum ('sa', 'gm');
create type public.app_role as enum ('sa', 'admin', 'moderator', 'user');
create type public.app_colors as enum ('red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose', 'black', 'white');
-- USERS
-- DATA STRUCTURES
-- Users
create table public.users (
id uuid references auth.users not null primary key, -- UUID from auth.users
username text
@@ -14,16 +16,16 @@ create table public.users (
comment on table public.users is 'Profile data for each user.';
comment on column public.users.id is 'References the internal Supabase Auth user.';
-- USER ROLES
-- Roles
create table public.user_roles (
id bigint generated by default as identity primary key,
user_id uuid references public.users on delete cascade not null,
role app_role not null,
user_id uuid references public.users on delete cascade not null,
unique (user_id, role)
);
comment on table public.user_roles is 'Application roles for each user.';
-- ROLE PERMISSIONS
-- Permissions
create table public.role_permissions (
id bigint generated by default as identity primary key,
role app_role not null,
@@ -32,6 +34,70 @@ create table public.role_permissions (
);
comment on table public.role_permissions is 'Application permissions for each role.';
-- Worlds
create table public.worlds (
id bigint generated by default as identity primary key,
name text not null,
description text,
color app_colors,
gm_id uuid references public.users on delete cascade
);
comment on table public.worlds is 'Worlds belonging to a single user ; a game master.';
-- World Calendars
create table public.world_calendars (
id bigint generated by default as identity primary key,
months text array,
days_per_year int not null,
world_id bigint references public.worlds on delete cascade not null
);
comment on table public.world_calendars is 'Calendar settings and configuration attached to a single world.';
-- Event categories
create table public.events_category (
id bigint generated by default as identity primary key,
name text not null,
unique (name)
);
comment on table public.events_category is 'Categories describing events';
-- Events
create table public.events (
id bigint generated by default as identity primary key,
title text not null,
description text,
start_date json not null,
end_date json,
category bigint references public.events_category on delete cascade,
hidden boolean,
wiki text,
calendar_id bigint references public.world_calendars on delete cascade not null
);
comment on table public.events is 'Events linked to a world';
-- Character categories
create table public.characters_category (
id bigint generated by default as identity primary key,
name text not null,
unique (name)
);
comment on table public.characters_category is 'Categories describing characters';
-- Characters
create table public.characters (
id bigint generated by default as identity primary key,
name text not null,
description text,
birth json not null,
death json,
category bigint references public.characters_category on delete cascade,
hidden_birth boolean,
hidden_death boolean,
wiki text,
world_id bigint references public.worlds on delete cascade not null
);
comment on table public.characters is 'Characters linked to a world';
-- authorize with role-based access control (RBAC)
create function public.authorize(
requested_permission app_permission
@@ -54,11 +120,84 @@ $$ language plpgsql security definer set search_path = public;
alter table public.users enable row level security;
alter table public.user_roles enable row level security;
alter table public.role_permissions enable row level security;
alter table public.worlds enable row level security;
alter table public.world_calendars enable row level security;
alter table public.events_category enable row level security;
alter table public.characters_category enable row level security;
alter table public.characters enable row level security;
alter table public.events enable row level security;
-- User policies
create policy "Allow logged-in read access" on public.users for select using ( auth.role() = 'authenticated' );
create policy "Allow individual insert access" on public.users for insert with check ( auth.uid() = id );
create policy "Allow individual update access" on public.users for update using ( auth.uid() = id );
create policy "Allow individual read access" on public.user_roles for select using ( auth.uid() = user_id );
-- World policies
create policy "Allow individual read access for GMs" on public.worlds for select using ( ( auth.uid() = gm_id ) );
create policy "Allow individual insert access for GMs" on public.worlds for insert with check ( auth.uid() = gm_id );
create policy "Allow individual update access for GMs" on public.worlds for update using ( auth.uid() = gm_id );
-- Calendar policies
create policy "Allow individual read access for GMs" on public.world_calendars for select using (
exists (
select 1 from worlds
where worlds.id = world_calendars.world_id
)
);
create policy "Allow individual insert access for GMs" on public.world_calendars for insert with check (
exists (
select 1 from worlds
where worlds.id = world_calendars.world_id
)
);
create policy "Allow individual update access for GMs" on public.world_calendars for update with check (
exists (
select 1 from worlds
where worlds.id = world_calendars.world_id
)
);
-- Event policies
create policy "Allow individual read access for GMs" on public.events for select using (
exists (
select 1 from world_calendars
where world_calendars.id = events.calendar_id
)
);
create policy "Allow individual insert access for GMs" on public.events for insert with check (
exists (
select 1 from world_calendars
where world_calendars.id = events.calendar_id
)
);
create policy "Allow individual update access for GMs" on public.events for update with check (
exists (
select 1 from world_calendars
where world_calendars.id = events.calendar_id
)
);
-- Character policies
create policy "Allow individual read access for GMs" on public.characters for select using (
exists (
select 1 from worlds
where worlds.id = characters.world_id
)
);
create policy "Allow individual insert access for GMs" on public.characters for insert with check (
exists (
select 1 from worlds
where worlds.id = characters.world_id
)
);
create policy "Allow individual update access for GMs" on public.characters for update with check (
exists (
select 1 from worlds
where worlds.id = characters.world_id
)
);
-- Send "previous data" on change
alter table public.users replica identity full;
@@ -69,6 +208,8 @@ declare is_admin boolean;
begin
insert into public.users (id, username)
values (new.id, new.email);
insert into public.user_roles (role, user_id)
values ('user', new.id);
return new;
end;

View File

@@ -1,4 +1,107 @@
insert into public.role_permissions (role, permission) values ('gm', 'events.see.hidden');
insert into public.role_permissions (role, permission) values ('sa', 'events.see.hidden');
insert into public.role_permissions (role, permission) values ('sa', 'users.ban');
-- Event categories
insert into public.events_category (name) values ('naissance');
insert into public.events_category (name) values ('mort');
insert into public.events_category (name) values ('catastrophe');
insert into public.events_category (name) values ('catastrophe naturelle');
insert into public.events_category (name) values ('inauguration');
insert into public.events_category (name) values ('religion');
insert into public.events_category (name) values ('invention');
insert into public.events_category (name) values ('science');
insert into public.events_category (name) values ('bénédiction');
insert into public.events_category (name) values ('joueurs');
insert into public.events_category (name) values ('découverte');
insert into public.events_category (name) values ('exploration');
insert into public.events_category (name) values ('construction');
insert into public.events_category (name) values ('arcanologie');
insert into public.events_category (name) values ('criminalité');
insert into public.events_category (name) values ('scandale');
insert into public.events_category (name) values ('commerce');
insert into public.events_category (name) values ('législation');
-- Character categories
insert into public.characters_category (name) values ('joueur');
insert into public.characters_category (name) values ('comte');
insert into public.characters_category (name) values ('scientifique');
insert into public.characters_category (name) values ('mage');
insert into public.characters_category (name) values ('professeur');
insert into public.characters_category (name) values ('criminel');
insert into public.characters_category (name) values ('étincelle');
insert into public.characters_category (name) values ('buse blanche');
insert into public.characters_category (name) values ('ecclésiastique');
insert into public.characters_category (name) values ('militaire');
insert into public.characters_category (name) values ('activiste');
insert into public.characters_category (name) values ('commerçant');
-- Worlds
insert into public.worlds (name, description, color) values ('Léïm', 'Monde d''aventures et d''intrigues med-fan', 'black');
-- Worlds' calendars
insert into public.world_calendars (world_id, months, days_per_year) values (1, ARRAY['Jalen', 'Malsen', 'Verlys', 'Nalys', 'Verdore', 'Sidore', 'Lyllion', 'Rion', 'Farene', 'Dalvene'], 320);
-- Events
insert into public.events (title, description, start_date, category, hidden, wiki, calendar_id) values (
'Laurdieu devient la première cité de l''empire de Kaliatos',
'L''empire de Kaliatos établi sa capitale dans la cité de Laurdieu, qui connaitra une prospérité nouvelle au sein d''Aldys.',
'{ "day": 3, "month": 4, "year": -1932 }',
18,
true,
'https://alexcreates.fr/leim/index.php/Laurdieu',
1
);
insert into public.events (title, description, start_date, category, hidden, wiki, calendar_id) values (
'Apparition d''Asménys',
'La défunte chanteuse Asménys apparaît à un barde pendant son jeune public, démarrant la religion des Prêtresses d''Asménys.',
'{ "day": 19, "month": 7, "year": -1358 }',
6,
true,
'https://alexcreates.fr/leim/index.php/Pr%C3%AAtresses_d%27Asm%C3%A9nys',
1
);
insert into public.events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
'La Rupture',
'Les Abysses se déversent à la surface de Léim, à travers plusieurs brèches. Plusieurs hordes de démons se rapprochent des villes, et ce qu''on appellera l''Âge des Abysses commencent alors sur la planète entière.',
'{ "day": 26, "month": 5, "year": -756 }',
'{ "day": 4, "month": 9, "year": 29 }',
3,
true,
'https://alexcreates.fr/leim/index.php/Seconde_Rupture',
1
);
insert into public.events (title, description, start_date, end_date, category, hidden, wiki, calendar_id) values (
'Marche du sang',
'L''empereur de Kaliatos ordonne personnellement la traque de Jorhas Kirendre pour connivence avec les démons. Plusieurs bataillons sont affectés à la chasse de Jorhas, qui se terminera par son incarcération ainsi que la mort de plusieurs centaines de soldats.',
'{ "day": 18, "month": 9, "year": -420 }',
'{ "day": 27, "month": 1, "year": -419 }',
15,
true,
'https://alexcreates.fr/leim/index.php/Jorhas_Kirendre',
1
);
insert into public.events (title, description, start_date, category, hidden, wiki, calendar_id) values (
'Exécution de Tyhos',
'Le léviathan Tyhos rend l''âme après un combat de plusieurs années contre Lystos, le dieu du Soleil.',
'{ "day": 1, "month": 0, "year": 0 }',
9,
true,
'https://alexcreates.fr/leim/index.php/Tyhos',
1
);
insert into public.events (title, start_date, category, wiki, calendar_id) values (
'Traité de Kadel',
'{ "day": 29, "month": 4, "year": 100 }',
5,
'https://alexcreates.fr/leim/index.php/Alliance_Kald%C3%A9lienne#Trait%C3%A9_de_Kadel',
1
);
insert into public.events (title, description, start_date, category, hidden, wiki, calendar_id) values (
'Découverte des Plaines de Poussières',
'Les troupes de la reconquête aldienne explorent le littoral d''une immense étendue grise et inerte.',
'{ "day": 17, "month": 7, "year": 305 }',
11,
true,
'https://alexcreates.fr/leim/index.php/Plaines_de_poussi%C3%A8re',
1
);