···8899## Routes
10101111-| Route | Description | Method |
1212-| --------------------------- | ---------------------------------------- | ----------- |
1313-| /api/user/signup | Register a new user account | POST (Form) |
1414-| /api/user/login | Login with your user account | POST (Form) |
1515-| /api/occurrence/new | Register new occurrence | POST (Form) |
1616-| /api/user/{id}/occurrences | Get all occurrences applied by this user | GET |
1717-| /api/user/{id}/crew_members | List fellow brigade members of this user | GET |
1818-| /api/brigade/{id}/members | List brigade members | GET |
1111+| Route | Description | Method |
1212+| --------------------------- | -------------------------------------------- | ----------- |
1313+| /api/user/signup | Register a new user account | POST (Form) |
1414+| /api/user/login | Login with your user account | POST (Form) |
1515+| /api/occurrence/new | Register new occurrence | POST (Form) |
1616+| /api/dashboard/stats | Retrieves useful information from the server | GET |
1717+| /api/user/{id}/occurrences | Get all occurrences applied by this user | GET |
1818+| /api/user/{id}/crew_members | List fellow brigade members of this user | GET |
1919+| /api/brigade/{id}/members | List brigade members | GET |
19202021## Entity RelationShip Diagram
2122···7980 TEXT description
8081 POINT location
8182 TEXT reference_point
8282- NUMERIC(2) loss_percentage
8383+ TEXT vehicle_code
8484+ UUID[] participants_id
8385 TIMESTAMP created_at
8486 TIMESTAMP updated_at
8587 TIMESTAMP resolved_at
8888+ }
8989+9090+ occurrence_brigade_member }o--o{ user_account : participant
9191+ occurrence_brigade_member }o--o{ brigade : participates_of
9292+ occurrence_brigade_member {
9393+ UUID id
9494+ UUID user_id
9595+ UUID brigade_id
8696 }
8797```
8898
···11--- DROP -------------------------------------------------------------------
21BEGIN;
33-44-DROP INDEX IF EXISTS public.idx_brigade_membership_brigade_id;
55-DROP INDEX IF EXISTS public.idx_brigade_membership_user_id;
66-DROP INDEX IF EXISTS public.idx_occurrence_applicant_id;
77-DROP INDEX IF EXISTS public.idx_user_registration;
88-DROP INDEX IF EXISTS public.idx_user_id;
99-DROP INDEX IF EXISTS public.idx_occurrence_id;
1010-DROP INDEX IF EXISTS public.idx_occurrence_brigade_member_user_id;
1111-DROP INDEX IF EXISTS public.idx_occurrence_brigade_member_occurrence_id;
1212-1313--- pgt-ignore-start lint/safety/banDropTable: We are resetting the Database
1414-DROP TABLE IF EXISTS public.occurrence;
1515-DROP TABLE IF EXISTS public.occurrence_category;
1616-DROP TABLE IF EXISTS public.occurrence_brigade_member;
1717-DROP TABLE IF EXISTS public.brigade_membership;
1818-DROP TABLE IF EXISTS public.brigade;
1919-DROP TABLE IF EXISTS public.user_account;
2020-DROP TABLE IF EXISTS public.user_role;
2121--- pgt-ignore-end lint/safety/banDropTable
2222-2323--- CREATE -----------------------------------------------------------------
242253CREATE TABLE IF NOT EXISTS public.user_role (
264 id UUID PRIMARY KEY DEFAULT UUIDV7(),
-4
priv/sql/create/triggers.sql
···11-DROP FUNCTION IF EXISTS public.dump_occurrence_participants;
22-DROP TRIGGER IF EXISTS tgr_insert_member_participation ON occurrence;
33-44---
51CREATE OR REPLACE FUNCTION public.dump_occurrence_participants()
62RETURNS TRIGGER AS $$
73BEGIN
+21
priv/sql/create/views.sql
···11+CREATE OR REPLACE VIEW vw_count_active_occurrences AS
22+SELECT COUNT(oc.id) AS count
33+FROM public.occurrence AS oc
44+WHERE oc.resolved_at IS NULL;
55+66+-----------------------------------------------------
77+CREATE OR REPLACE VIEW vw_count_recent_occurrences AS
88+SELECT COUNT(oc.id) AS count
99+FROM public.occurrence AS oc
1010+WHERE oc.created_at >= (NOW() - '1 day'::INTERVAL);
1111+1212+----------------------------------------------------
1313+CREATE OR REPLACE VIEW vw_count_total_occurrences AS
1414+SELECT COUNT(oc.id) AS count
1515+FROM public.occurrence AS oc;
1616+1717+------------------------------------------------------
1818+CREATE OR REPLACE VIEW vw_count_active_brigades AS
1919+SELECT COUNT(id)
2020+FROM public.brigade
2121+WHERE is_active = TRUE;
+27
priv/sql/drop.sql
···11+--------------------------------------------------------------------------------
22+DROP VIEW IF EXISTS vw_count_active_occurrences;
33+DROP VIEW IF EXISTS vw_count_recent_occurrences;
44+DROP VIEW IF EXISTS vw_count_total_occurrences;
55+DROP VIEW IF EXISTS vw_count_active_brigades;
66+77+--------------------------------------------------------------------------------
88+DROP TRIGGER IF EXISTS tgr_insert_member_participation ON occurrence;
99+DROP FUNCTION IF EXISTS public.dump_occurrence_participants;
1010+--------------------------------------------------------------------------------
1111+1212+DROP INDEX IF EXISTS public.idx_brigade_membership_brigade_id;
1313+DROP INDEX IF EXISTS public.idx_brigade_membership_user_id;
1414+DROP INDEX IF EXISTS public.idx_occurrence_applicant_id;
1515+DROP INDEX IF EXISTS public.idx_user_registration;
1616+DROP INDEX IF EXISTS public.idx_occurrence_brigade_member_user_id;
1717+DROP INDEX IF EXISTS public.idx_occurrence_brigade_member_occurrence_id;
1818+1919+-- pgt-ignore-start lint/safety/banDropTable: We are resetting the Database
2020+DROP TABLE IF EXISTS public.occurrence;
2121+DROP TABLE IF EXISTS public.occurrence_category;
2222+DROP TABLE IF EXISTS public.occurrence_brigade_member;
2323+DROP TABLE IF EXISTS public.brigade_membership;
2424+DROP TABLE IF EXISTS public.brigade;
2525+DROP TABLE IF EXISTS public.user_account;
2626+DROP TABLE IF EXISTS public.user_role;
2727+-- pgt-ignore-end lint/safety/banDropTable
···99import pog
1010import youid/uuid.{type Uuid}
11111212-/// A row you get from running the `count_active_brigades` query
1313-/// defined in `./src/app/routes/brigade/sql/count_active_brigades.sql`.
1414-///
1515-/// > 🐿️ This type definition was generated automatically using v4.4.1 of the
1616-/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
1717-///
1818-pub type CountActiveBrigadesRow {
1919- CountActiveBrigadesRow(count: Int)
2020-}
2121-2222-/// Counts the number of active brigades in the database.
2323-///
2424-/// > 🐿️ This function was generated automatically using v4.4.1 of
2525-/// > the [squirrel package](https://github.com/giacomocavalieri/squirrel).
2626-///
2727-pub fn count_active_brigades(
2828- db: pog.Connection,
2929-) -> Result(pog.Returned(CountActiveBrigadesRow), pog.QueryError) {
3030- let decoder = {
3131- use count <- decode.field(0, decode.int)
3232- decode.success(CountActiveBrigadesRow(count:))
3333- }
3434-3535- "-- Counts the number of active brigades in the database.
3636-SELECT COUNT(id)
3737-FROM public.brigade
3838-WHERE is_active = TRUE;
3939-"
4040- |> pog.query
4141- |> pog.returning(decoder)
4242- |> pog.execute(db)
4343-}
4444-4512/// A row you get from running the `get_brigade_members` query
4613/// defined in `./src/app/routes/brigade/sql/get_brigade_members.sql`.
4714///
···11+//// This module contains the code to run the sql queries defined in
22+//// `./src/app/routes/dashboard/sql`.
33+//// > 🐿️ This module was generated automatically using v4.4.1 of
44+//// > the [squirrel package](https://github.com/giacomocavalieri/squirrel).
55+////
66+77+import gleam/dynamic/decode
88+import pog
99+1010+/// A row you get from running the `get_dashboard_stats` query
1111+/// defined in `./src/app/routes/dashboard/sql/get_dashboard_stats.sql`.
1212+///
1313+/// > 🐿️ This type definition was generated automatically using v4.4.1 of the
1414+/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
1515+///
1616+pub type GetDashboardStatsRow {
1717+ GetDashboardStatsRow(
1818+ active_brigades_count: Int,
1919+ total_occurrences_count: Int,
2020+ active_occurrences_count: Int,
2121+ recent_occurrences_count: Int,
2222+ )
2323+}
2424+2525+///
2626+///
2727+/// > 🐿️ This function was generated automatically using v4.4.1 of
2828+/// > the [squirrel package](https://github.com/giacomocavalieri/squirrel).
2929+///
3030+pub fn get_dashboard_stats(
3131+ db: pog.Connection,
3232+) -> Result(pog.Returned(GetDashboardStatsRow), pog.QueryError) {
3333+ let decoder = {
3434+ use active_brigades_count <- decode.field(0, decode.int)
3535+ use total_occurrences_count <- decode.field(1, decode.int)
3636+ use active_occurrences_count <- decode.field(2, decode.int)
3737+ use recent_occurrences_count <- decode.field(3, decode.int)
3838+ decode.success(GetDashboardStatsRow(
3939+ active_brigades_count:,
4040+ total_occurrences_count:,
4141+ active_occurrences_count:,
4242+ recent_occurrences_count:,
4343+ ))
4444+ }
4545+4646+ "--
4747+SELECT
4848+ (
4949+ SELECT count
5050+ FROM public.vw_count_active_brigades
5151+ ) AS active_brigades_count,
5252+ (
5353+ SELECT count
5454+ FROM public.vw_count_total_occurrences
5555+ ) AS total_occurrences_count,
5656+ (
5757+ SELECT count
5858+ FROM public.vw_count_active_occurrences
5959+ ) AS active_occurrences_count,
6060+ (
6161+ SELECT count FROM
6262+ public.vw_count_recent_occurrences
6363+ ) AS recent_occurrences_count;
6464+"
6565+ |> pog.query
6666+ |> pog.returning(decoder)
6767+ |> pog.execute(db)
6868+}
···33//// It returns a list of occurrences (incidents/reports) that were submitted
44//// by the specified user, including detailed information about each occurrence.
5566-import app/routes/user/sql
66+import app/routes/occurrence/sql
77import app/web
88import gleam/float
99import gleam/http
-76
src/app/routes/user/sql.gleam
···6677import gleam/dynamic/decode
88import gleam/option.{type Option}
99-import gleam/time/timestamp.{type Timestamp}
109import pog
1110import youid/uuid.{type Uuid}
1211···10099"
101100 |> pog.query
102101 |> pog.parameter(pog.text(arg_1))
103103- |> pog.returning(decoder)
104104- |> pog.execute(db)
105105-}
106106-107107-/// A row you get from running the `get_occurences_by_applicant` query
108108-/// defined in `./src/app/routes/user/sql/get_occurences_by_applicant.sql`.
109109-///
110110-/// > 🐿️ This type definition was generated automatically using v4.4.1 of the
111111-/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
112112-///
113113-pub type GetOccurencesByApplicantRow {
114114- GetOccurencesByApplicantRow(
115115- id: Uuid,
116116- description: Option(String),
117117- category: Option(String),
118118- subcategory: Option(String),
119119- created_at: Option(Timestamp),
120120- resolved_at: Option(Timestamp),
121121- location: List(Float),
122122- reference_point: Option(String),
123123- )
124124-}
125125-126126-/// Retrieves all occurrences associated with a user,
127127-/// including detailed category information and resolution status.
128128-///
129129-/// > 🐿️ This function was generated automatically using v4.4.1 of
130130-/// > the [squirrel package](https://github.com/giacomocavalieri/squirrel).
131131-///
132132-pub fn get_occurences_by_applicant(
133133- db: pog.Connection,
134134- arg_1: Uuid,
135135-) -> Result(pog.Returned(GetOccurencesByApplicantRow), pog.QueryError) {
136136- let decoder = {
137137- use id <- decode.field(0, uuid_decoder())
138138- use description <- decode.field(1, decode.optional(decode.string))
139139- use category <- decode.field(2, decode.optional(decode.string))
140140- use subcategory <- decode.field(3, decode.optional(decode.string))
141141- use created_at <- decode.field(4, decode.optional(pog.timestamp_decoder()))
142142- use resolved_at <- decode.field(5, decode.optional(pog.timestamp_decoder()))
143143- use location <- decode.field(6, decode.list(decode.float))
144144- use reference_point <- decode.field(7, decode.optional(decode.string))
145145- decode.success(GetOccurencesByApplicantRow(
146146- id:,
147147- description:,
148148- category:,
149149- subcategory:,
150150- created_at:,
151151- resolved_at:,
152152- location:,
153153- reference_point:,
154154- ))
155155- }
156156-157157- "-- Retrieves all occurrences associated with a user,
158158--- including detailed category information and resolution status.
159159-SELECT
160160- o.id,
161161- o.description,
162162- oc_cat.category_name AS category,
163163- sub_cat.category_name AS subcategory,
164164- o.created_at,
165165- o.resolved_at,
166166- o.location,
167167- o.reference_point
168168-FROM public.query_all_ocurrences_by_user_id($1) AS oc_list (id)
169169-INNER JOIN public.occurrence AS o
170170- ON oc_list.id = o.id
171171-LEFT JOIN public.occurrence_category AS oc_cat
172172- ON o.category_id = oc_cat.id
173173-LEFT JOIN public.occurrence_category AS sub_cat
174174- ON o.subcategory_id = sub_cat.id;
175175-"
176176- |> pog.query
177177- |> pog.parameter(pog.text(uuid.to_string(arg_1)))
178102 |> pog.returning(decoder)
179103 |> pog.execute(db)
180104}