diff --git a/components/calendar/CalendarEventDetails.vue b/components/calendar/CalendarEventDetails.vue index 76b412c..f138670 100644 --- a/components/calendar/CalendarEventDetails.vue +++ b/components/calendar/CalendarEventDetails.vue @@ -114,9 +114,9 @@ function handleGotoRelativeEvent(position: 'next' | 'prev' = 'next') { -
  • +
  • - {{ cat }} + {{ cat.name }}
  • diff --git a/components/calendar/search/lists/EventCallout.vue b/components/calendar/search/lists/EventCallout.vue index afe2ef7..ed63552 100644 --- a/components/calendar/search/lists/EventCallout.vue +++ b/components/calendar/search/lists/EventCallout.vue @@ -94,9 +94,9 @@ const dateDuration: string | null = props.event.endDate -
  • +
  • - {{ cat }} + {{ cat.name }}
  • diff --git a/models/CalendarEvent.ts b/models/CalendarEvent.ts index d19d06d..64f558b 100644 --- a/models/CalendarEvent.ts +++ b/models/CalendarEvent.ts @@ -8,6 +8,7 @@ export interface CalendarEvent { endDate?: RPGDate description?: string category?: Category + secondaryCategories?: Category[] hidden?: boolean wiki?: string } diff --git a/models/Characters.ts b/models/Characters.ts index 2c6d2a8..b63d103 100644 --- a/models/Characters.ts +++ b/models/Characters.ts @@ -1,3 +1,4 @@ +import type { Category } from './Category' import type { RPGDate } from './Date' export interface Character { @@ -7,8 +8,8 @@ export interface Character { death?: RPGDate hiddenBirth?: boolean hiddenDeath?: boolean - category?: CharacterCategory - secondaryCategories?: CharacterCategory[] + category?: Category + secondaryCategories?: Category[] wiki?: string } export const characterCategories = [ diff --git a/server/api/calendars/query.get.ts b/server/api/calendars/query.get.ts index 3e63866..9d36e57 100644 --- a/server/api/calendars/query.get.ts +++ b/server/api/calendars/query.get.ts @@ -11,7 +11,7 @@ export default defineEventHandler(async (event) => { const query = await getValidatedQuery(event, querySchema.parse) const output = client - .from('world_calendars') + .from('calendars') .select(` id, months:calendar_months (*), @@ -23,7 +23,8 @@ export default defineEventHandler(async (event) => { startDate:start_date, endDate:end_date, wiki, - category:calendar_events_category (*) + category:calendar_event_categories!calendar_events_category_fkey (*), + secondaryCategories:calendar_event_categories!calendar_event_categories_links (*) ) `) .eq('world_id', query.world_id) diff --git a/supabase/migrations/202401_init.sql b/supabase/migrations/202401_init.sql index 74b9c11..47492d4 100644 --- a/supabase/migrations/202401_init.sql +++ b/supabase/migrations/202401_init.sql @@ -45,11 +45,12 @@ create table public.worlds ( comment on table public.worlds is 'Worlds belonging to a single user ; a game master.'; -- World Calendars -create table public.world_calendars ( +create table public.calendars ( id bigint generated by default as identity primary key, + name text 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.'; +comment on table public.calendars is 'Calendar settings and configuration attached to a single world.'; -- Calendar Months create table public.calendar_months ( @@ -57,17 +58,17 @@ create table public.calendar_months ( name text not null, days int not null, position int not null, - calendar_id bigint references public.world_calendars on delete cascade not null + calendar_id bigint references public.calendars on delete cascade not null ); comment on table public.calendar_months is 'A calendar month.'; -- Event categories -create table public.calendar_events_category ( +create table public.calendar_event_categories ( id bigint generated by default as identity primary key, name text not null, unique (name) ); -comment on table public.calendar_events_category is 'Categories describing events'; +comment on table public.calendar_event_categories is 'Categories describing events.'; -- Events create table public.calendar_events ( @@ -76,36 +77,52 @@ create table public.calendar_events ( description text, start_date json not null, end_date json, - category bigint references public.calendar_events_category on delete cascade, + category bigint references public.calendar_event_categories on delete cascade, hidden boolean, wiki text, - calendar_id bigint references public.world_calendars on delete cascade not null + calendar_id bigint references public.calendars on delete cascade not null ); comment on table public.calendar_events is 'Events linked to a world'; +-- Link table for events - categories +create table public.calendar_event_categories_links ( + calendar_event_id bigint references public.calendar_events on delete cascade, + calendar_event_category_id bigint references public.calendar_event_categories on delete cascade, + primary key (calendar_event_id, calendar_event_category_id) +); +comment on table public.calendar_event_categories_links is 'Link tables for multiple event categories.'; + -- Character categories -create table public.characters_category ( +create table public.character_categories ( 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'; +comment on table public.character_categories 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, + 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.character_categories on delete cascade, hidden_birth boolean, hidden_death boolean, - wiki text, - world_id bigint references public.worlds on delete cascade not null + wiki text, + world_id bigint references public.worlds on delete cascade not null ); comment on table public.characters is 'Characters linked to a world'; +-- Link table for events - categories +create table public.character_categories_links ( + character_id bigint references public.characters on delete cascade, + character_category_id bigint references public.character_categories on delete cascade, + primary key (character_id, character_category_id) +); +comment on table public.character_categories_links is 'Link tables for multiple character categories.'; + -- authorize with role-based access control (RBAC) create function public.authorize( requested_permission app_permission @@ -129,12 +146,14 @@ 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.characters_category enable row level security; +alter table public.character_categories enable row level security; +alter table public.character_categories_links enable row level security; alter table public.characters enable row level security; -alter table public.world_calendars enable row level security; +alter table public.calendars enable row level security; alter table public.calendar_months enable row level security; alter table public.calendar_events enable row level security; -alter table public.calendar_events_category enable row level security; +alter table public.calendar_event_categories enable row level security; +alter table public.calendar_event_categories_links enable row level security; -- User policies create policy "Allow logged-in read access" on public.users for select using ( auth.role() = 'authenticated' ); @@ -148,62 +167,62 @@ create policy "Allow individual insert access for GMs" on public.worlds for inse 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 ( +create policy "Allow individual read access for GMs" on public.calendars for select using ( exists ( select 1 from worlds - where worlds.id = world_calendars.world_id + where worlds.id = calendars.world_id ) ); -create policy "Allow individual insert access for GMs" on public.world_calendars for insert with check ( +create policy "Allow individual insert access for GMs" on public.calendars for insert with check ( exists ( select 1 from worlds - where worlds.id = world_calendars.world_id + where worlds.id = calendars.world_id ) ); -create policy "Allow individual update access for GMs" on public.world_calendars for update with check ( +create policy "Allow individual update access for GMs" on public.calendars for update with check ( exists ( select 1 from worlds - where worlds.id = world_calendars.world_id + where worlds.id = calendars.world_id ) ); -- Month policies create policy "Allow individual read access for GMs" on public.calendar_months for select using ( exists ( - select 1 from world_calendars - where world_calendars.id = calendar_months.calendar_id + select 1 from calendars + where calendars.id = calendar_months.calendar_id ) ); create policy "Allow individual insert access for GMs" on public.calendar_months for insert with check ( exists ( - select 1 from world_calendars - where world_calendars.id = calendar_months.calendar_id + select 1 from calendars + where calendars.id = calendar_months.calendar_id ) ); create policy "Allow individual update access for GMs" on public.calendar_months for update with check ( exists ( - select 1 from world_calendars - where world_calendars.id = calendar_months.calendar_id + select 1 from calendars + where calendars.id = calendar_months.calendar_id ) ); -- Event policies create policy "Allow individual read access for GMs" on public.calendar_events for select using ( exists ( - select 1 from world_calendars - where world_calendars.id = calendar_events.calendar_id + select 1 from calendars + where calendars.id = calendar_events.calendar_id ) ); create policy "Allow individual insert access for GMs" on public.calendar_events for insert with check ( exists ( - select 1 from world_calendars - where world_calendars.id = calendar_events.calendar_id + select 1 from calendars + where calendars.id = calendar_events.calendar_id ) ); create policy "Allow individual update access for GMs" on public.calendar_events for update with check ( exists ( - select 1 from world_calendars - where world_calendars.id = calendar_events.calendar_id + select 1 from calendars + where calendars.id = calendar_events.calendar_id ) ); @@ -228,8 +247,11 @@ create policy "Allow individual update access for GMs" on public.characters for ); -- Categories are public to view but not to insert -create policy "Allow logged-in read access" on public.calendar_events_category for select using ( auth.role() = 'authenticated' ); -create policy "Allow logged-in read access" on public.characters_category for select using ( auth.role() = 'authenticated' ); +-- Needs to be refactored maybe, if in the future we want a default set AND user defined ones +create policy "Allow logged-in read access" on public.calendar_event_categories for select using ( auth.role() = 'authenticated' ); +create policy "Allow logged-in read access" on public.calendar_event_categories_links for select using ( auth.role() = 'authenticated' ); +create policy "Allow logged-in read access" on public.character_categories for select using ( auth.role() = 'authenticated' ); +create policy "Allow logged-in read access" on public.character_categories_links for select using ( auth.role() = 'authenticated' ); -- Send "previous data" on change alter table public.users replica identity full; diff --git a/supabase/seed.sql b/supabase/seed.sql index b08cda0..691f65d 100644 --- a/supabase/seed.sql +++ b/supabase/seed.sql @@ -2,44 +2,44 @@ insert into public.role_permissions (role, permission) values ('sa', 'events.see insert into public.role_permissions (role, permission) values ('sa', 'users.ban'); -- Event categories -insert into public.calendar_events_category (name) values ('naissance'); -insert into public.calendar_events_category (name) values ('mort'); -insert into public.calendar_events_category (name) values ('catastrophe'); -insert into public.calendar_events_category (name) values ('catastrophe naturelle'); -insert into public.calendar_events_category (name) values ('inauguration'); -insert into public.calendar_events_category (name) values ('religion'); -insert into public.calendar_events_category (name) values ('invention'); -insert into public.calendar_events_category (name) values ('science'); -insert into public.calendar_events_category (name) values ('bénédiction'); -insert into public.calendar_events_category (name) values ('joueurs'); -insert into public.calendar_events_category (name) values ('découverte'); -insert into public.calendar_events_category (name) values ('exploration'); -insert into public.calendar_events_category (name) values ('construction'); -insert into public.calendar_events_category (name) values ('arcanologie'); -insert into public.calendar_events_category (name) values ('criminalité'); -insert into public.calendar_events_category (name) values ('scandale'); -insert into public.calendar_events_category (name) values ('commerce'); -insert into public.calendar_events_category (name) values ('législation'); +insert into public.calendar_event_categories (name) values ('naissance'); +insert into public.calendar_event_categories (name) values ('mort'); +insert into public.calendar_event_categories (name) values ('catastrophe'); +insert into public.calendar_event_categories (name) values ('catastrophe naturelle'); +insert into public.calendar_event_categories (name) values ('inauguration'); +insert into public.calendar_event_categories (name) values ('religion'); +insert into public.calendar_event_categories (name) values ('invention'); +insert into public.calendar_event_categories (name) values ('science'); +insert into public.calendar_event_categories (name) values ('bénédiction'); +insert into public.calendar_event_categories (name) values ('joueurs'); +insert into public.calendar_event_categories (name) values ('découverte'); +insert into public.calendar_event_categories (name) values ('exploration'); +insert into public.calendar_event_categories (name) values ('construction'); +insert into public.calendar_event_categories (name) values ('arcanologie'); +insert into public.calendar_event_categories (name) values ('criminalité'); +insert into public.calendar_event_categories (name) values ('scandale'); +insert into public.calendar_event_categories (name) values ('commerce'); +insert into public.calendar_event_categories (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'); +insert into public.character_categories (name) values ('joueur'); +insert into public.character_categories (name) values ('comte'); +insert into public.character_categories (name) values ('scientifique'); +insert into public.character_categories (name) values ('mage'); +insert into public.character_categories (name) values ('professeur'); +insert into public.character_categories (name) values ('criminel'); +insert into public.character_categories (name) values ('étincelle'); +insert into public.character_categories (name) values ('buse blanche'); +insert into public.character_categories (name) values ('ecclésiastique'); +insert into public.character_categories (name) values ('militaire'); +insert into public.character_categories (name) values ('activiste'); +insert into public.character_categories (name) values ('commerçant'); -- Worlds -insert into public.worlds (name, description, color) values ('Léïm', 'Monde d''aventures et d''intrigues med-fan', 'black'); +insert into public.worlds (name, description, color) values ('Léïm', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis aliquet congue aliquet. Curabitur eu iaculis diam. Nunc iaculis nibh orci, eu semper nunc congue congue. Praesent euismod tortor eget metus tristique lobortis vel in risus. In volutpat ligula orci, id pharetra lectus egestas at.', 'black'); -- Worlds' calendars -insert into public.world_calendars (world_id) values (1); +insert into public.calendars (world_id, name) values (1, 'Calendrier solaire'); -- Calendar's months insert into public.calendar_months (calendar_id, name, days, position) values (1, 'Jalen', 32, 1);