+1
-1
dev/dummy.gleam
+1
-1
dev/dummy.gleam
+2
-2
src/app/domain/brigade/get_brigade_members.gleam
+2
-2
src/app/domain/brigade/get_brigade_members.gleam
···
38
38
/// }
39
39
/// ]
40
40
pub fn handle_request(
41
-
request request: wisp.Request,
41
+
request req: wisp.Request,
42
42
ctx ctx: Context,
43
43
id brigade_id: String,
44
44
) -> wisp.Response {
45
-
use <- wisp.require_method(request, http.Get)
45
+
use <- wisp.require_method(req, http.Get)
46
46
47
47
case query_brigade_members(ctx, brigade_id) {
48
48
Ok(body) -> wisp.json_response(body, 200)
+6
-8
src/app/domain/brigade/sql.gleam
+6
-8
src/app/domain/brigade/sql.gleam
···
41
41
"
42
42
|> pog.query
43
43
|> pog.parameter(pog.text(uuid.to_string(arg_1)))
44
-
|> pog.parameter(pog.array(
45
-
fn(value) { pog.text(uuid.to_string(value)) },
46
-
arg_2,
47
-
))
44
+
|> pog.parameter(
45
+
pog.array(fn(value) { pog.text(uuid.to_string(value)) }, arg_2),
46
+
)
48
47
|> pog.returning(decoder)
49
48
|> pog.execute(db)
50
49
}
···
354
353
"
355
354
|> pog.query
356
355
|> pog.parameter(pog.text(uuid.to_string(arg_1)))
357
-
|> pog.parameter(pog.array(
358
-
fn(value) { pog.text(uuid.to_string(value)) },
359
-
arg_2,
360
-
))
356
+
|> pog.parameter(
357
+
pog.array(fn(value) { pog.text(uuid.to_string(value)) }, arg_2),
358
+
)
361
359
|> pog.returning(decoder)
362
360
|> pog.execute(db)
363
361
}
+2
-2
src/app/domain/dashboard.gleam
+2
-2
src/app/domain/dashboard.gleam
···
29
29
/// }
30
30
/// ```
31
31
pub fn handle_request(
32
-
request request: wisp.Request,
32
+
request req: wisp.Request,
33
33
ctx ctx: Context,
34
34
) -> wisp.Response {
35
-
use <- wisp.require_method(request, http.Get)
35
+
use <- wisp.require_method(req, http.Get)
36
36
37
37
case query_dashboard_stats(ctx) {
38
38
Ok(body) -> wisp.json_response(body, 200)
+4
-12
src/app/domain/data_analysis/sql.gleam
+4
-12
src/app/domain/data_analysis/sql.gleam
···
131
131
"medic_emergency" -> decode.success(MedicEmergency)
132
132
_ -> decode.failure(Other, "OccurrenceCategoryEnum")
133
133
}
134
-
}
135
-
136
-
/// Corresponds to the Postgres `occurrence_priority_enum` enum.
134
+
}/// Corresponds to the Postgres `occurrence_priority_enum` enum.
137
135
///
138
136
/// > ๐ฟ๏ธ This type definition was generated automatically using v4.6.0 of the
139
137
/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
···
152
150
"low" -> decode.success(Low)
153
151
_ -> decode.failure(High, "OccurrencePriorityEnum")
154
152
}
155
-
}
156
-
157
-
/// Corresponds to the Postgres `occurrence_subcategory_enum` enum.
153
+
}/// Corresponds to the Postgres `occurrence_subcategory_enum` enum.
158
154
///
159
155
/// > ๐ฟ๏ธ This type definition was generated automatically using v4.6.0 of the
160
156
/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
···
178
174
HeartStop
179
175
}
180
176
181
-
fn occurrence_subcategory_enum_decoder() -> decode.Decoder(
182
-
OccurrenceSubcategoryEnum,
183
-
) {
177
+
fn occurrence_subcategory_enum_decoder() -> decode.Decoder(OccurrenceSubcategoryEnum) {
184
178
use occurrence_subcategory_enum <- decode.then(decode.string)
185
179
case occurrence_subcategory_enum {
186
180
"injured_animal" -> decode.success(InjuredAnimal)
···
201
195
"heart_stop" -> decode.success(HeartStop)
202
196
_ -> decode.failure(InjuredAnimal, "OccurrenceSubcategoryEnum")
203
197
}
204
-
}
205
-
206
-
/// Corresponds to the Postgres `user_role_enum` enum.
198
+
}/// Corresponds to the Postgres `user_role_enum` enum.
207
199
///
208
200
/// > ๐ฟ๏ธ This type definition was generated automatically using v4.6.0 of the
209
201
/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
+113
src/app/domain/occurrence/close_occurrence.gleam
+113
src/app/domain/occurrence/close_occurrence.gleam
···
1
+
import app/domain/occurrence
2
+
import app/domain/occurrence/sql
3
+
import app/domain/user
4
+
import app/web
5
+
import app/web/context.{type Context}
6
+
import app/web/socket/message as msg
7
+
import gleam/http
8
+
import gleam/json
9
+
import gleam/list
10
+
import gleam/result
11
+
import gleam/time/timestamp
12
+
import group_registry
13
+
import pog
14
+
import wisp
15
+
import youid/uuid
16
+
17
+
/// Resolving a occurence can fail
18
+
type ResolveOccurrenceError {
19
+
/// Occurrence has invalid Uuid format
20
+
InvalidUuid(String)
21
+
/// Occurrence was not found in the DataBase
22
+
OccurrenceNotFound(uuid.Uuid)
23
+
/// An error occurred whe naccessing the DataBase
24
+
DataBase(pog.QueryError)
25
+
/// Errors related to authentication / authorization
26
+
AccessControl(user.AuthenticationError)
27
+
}
28
+
29
+
/// ๓ฐฐ Updates the `resolved_at` field of a occurrence
30
+
///
31
+
/// ```jsonc
32
+
/// {
33
+
/// "id": "a32fb57f-b547-434d-a5d6-2a2c96cddb20",
34
+
/// "resolved_at": 1762889998.0, // or null
35
+
/// "updated_at": 1762889998.0
36
+
/// }
37
+
/// ````
38
+
pub fn handle_request(
39
+
request req: wisp.Request,
40
+
ctx ctx: Context,
41
+
id occurrence_id: String,
42
+
) -> wisp.Response {
43
+
use <- wisp.require_method(req, http.Post)
44
+
45
+
case close_occurrence(req, ctx, occurrence_id) {
46
+
Error(err) -> handle_error(err)
47
+
Ok(body) -> wisp.json_response(body, 200)
48
+
}
49
+
}
50
+
51
+
fn close_occurrence(
52
+
req: wisp.Request,
53
+
ctx: Context,
54
+
occ_id: String,
55
+
) -> Result(String, ResolveOccurrenceError) {
56
+
use _ <- result.try(
57
+
user.extract_uuid(request: req, cookie_name: user.uuid_cookie_name)
58
+
|> result.map_error(AccessControl),
59
+
)
60
+
61
+
use target <- result.try(
62
+
uuid.from_string(occ_id)
63
+
|> result.replace_error(InvalidUuid(occ_id)),
64
+
)
65
+
66
+
use returned <- result.try(
67
+
sql.close_occurrence(ctx.db, target)
68
+
|> result.map_error(DataBase),
69
+
)
70
+
71
+
use row <- result.map(
72
+
list.first(returned.rows)
73
+
|> result.replace_error(OccurrenceNotFound(target)),
74
+
)
75
+
76
+
// ๏ผ Broadcast to all assigned users ----------------------------------------
77
+
let _ =
78
+
occurrence.broadcast(
79
+
ctx:,
80
+
registry: group_registry.get_registry(ctx.registry_name),
81
+
occurrence: row.id,
82
+
message: msg.Domain(msg.OccurrenceResolved(
83
+
id: row.id,
84
+
when: row.resolved_at,
85
+
)),
86
+
)
87
+
88
+
// RESPONSE
89
+
let timestamp_json =
90
+
json.nullable(row.resolved_at, fn(time) {
91
+
timestamp.to_unix_seconds(time) |> json.float
92
+
})
93
+
94
+
json.to_string(
95
+
json.object([
96
+
#("id", json.string(uuid.to_string(row.id))),
97
+
#("resolved_at", timestamp_json),
98
+
#("updated_at", json.float(timestamp.to_unix_seconds(row.updated_at))),
99
+
]),
100
+
)
101
+
}
102
+
103
+
fn handle_error(err: ResolveOccurrenceError) -> wisp.Response {
104
+
case err {
105
+
AccessControl(err) -> user.handle_authentication_error(err)
106
+
DataBase(err) -> web.handle_database_error(err)
107
+
InvalidUuid(id) ->
108
+
wisp.bad_request("Ocorrรชncia possui Uuid invรกlido: " <> id)
109
+
OccurrenceNotFound(occ_id) ->
110
+
wisp.Text("Ocorrรชncia nรฃo encontrada: " <> uuid.to_string(occ_id))
111
+
|> wisp.set_body(wisp.not_found(), _)
112
+
}
113
+
}
+2
-2
src/app/domain/occurrence/get_ocurrences_by_applicant.gleam
+2
-2
src/app/domain/occurrence/get_ocurrences_by_applicant.gleam
···
22
22
/// ๓ฐกฆ Find all occurrences/applications associated with a specific user
23
23
/// returns them as formatted JSON data
24
24
pub fn handle_request(
25
-
request request: wisp.Request,
25
+
request req: wisp.Request,
26
26
ctx ctx: Context,
27
27
id user_id: String,
28
28
) -> wisp.Response {
29
-
use <- wisp.require_method(request, http.Get)
29
+
use <- wisp.require_method(req, http.Get)
30
30
31
31
case query_occurrences(ctx, user_id) {
32
32
Ok(resp) -> wisp.json_response(resp, 200)
+4
-4
src/app/domain/occurrence/register_new_occurrence.gleam
+4
-4
src/app/domain/occurrence/register_new_occurrence.gleam
···
41
41
/// }
42
42
/// ```
43
43
pub fn handle_request(
44
-
request request: wisp.Request,
44
+
request req: wisp.Request,
45
45
ctx ctx: Context,
46
46
) -> wisp.Response {
47
-
use <- wisp.require_method(request, http.Post)
48
-
use body <- wisp.require_json(request)
47
+
use <- wisp.require_method(req, http.Post)
48
+
use body <- wisp.require_json(req)
49
49
50
50
case decode.run(body, body_decoder()) {
51
51
Error(err) -> web.handle_decode_error(err)
52
-
Ok(body) -> handle_body(request:, ctx:, body:)
52
+
Ok(body) -> handle_body(request: req, ctx:, body:)
53
53
}
54
54
}
55
55
+58
-64
src/app/domain/occurrence/sql.gleam
+58
-64
src/app/domain/occurrence/sql.gleam
···
41
41
"
42
42
|> pog.query
43
43
|> pog.parameter(pog.text(uuid.to_string(arg_1)))
44
-
|> pog.parameter(pog.array(
45
-
fn(value) { pog.text(uuid.to_string(value)) },
46
-
arg_2,
47
-
))
44
+
|> pog.parameter(
45
+
pog.array(fn(value) { pog.text(uuid.to_string(value)) }, arg_2),
46
+
)
47
+
|> pog.returning(decoder)
48
+
|> pog.execute(db)
49
+
}
50
+
51
+
/// A row you get from running the `close_occurrence` query
52
+
/// defined in `./src/app/domain/occurrence/sql/close_occurrence.sql`.
53
+
///
54
+
/// > ๐ฟ๏ธ This type definition was generated automatically using v4.6.0 of the
55
+
/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
56
+
///
57
+
pub type CloseOccurrenceRow {
58
+
CloseOccurrenceRow(
59
+
id: Uuid,
60
+
resolved_at: Option(Timestamp),
61
+
updated_at: Timestamp,
62
+
)
63
+
}
64
+
65
+
/// ๓ฐฐ Mark a occurrence as resolved
66
+
///
67
+
/// > ๐ฟ๏ธ This function was generated automatically using v4.6.0 of
68
+
/// > the [squirrel package](https://github.com/giacomocavalieri/squirrel).
69
+
///
70
+
pub fn close_occurrence(
71
+
db: pog.Connection,
72
+
arg_1: Uuid,
73
+
) -> Result(pog.Returned(CloseOccurrenceRow), pog.QueryError) {
74
+
let decoder = {
75
+
use id <- decode.field(0, uuid_decoder())
76
+
use resolved_at <- decode.field(1, decode.optional(pog.timestamp_decoder()))
77
+
use updated_at <- decode.field(2, pog.timestamp_decoder())
78
+
decode.success(CloseOccurrenceRow(id:, resolved_at:, updated_at:))
79
+
}
80
+
81
+
"-- ๓ฐฐ Mark a occurrence as resolved
82
+
update public.occurrence
83
+
set
84
+
resolved_at = current_timestamp,
85
+
updated_at = current_timestamp
86
+
where id = $1
87
+
returning
88
+
id,
89
+
resolved_at,
90
+
updated_at;
91
+
"
92
+
|> pog.query
93
+
|> pog.parameter(pog.text(uuid.to_string(arg_1)))
48
94
|> pog.returning(decoder)
49
95
|> pog.execute(db)
50
96
}
···
465
511
"
466
512
|> pog.query
467
513
|> pog.parameter(pog.text(uuid.to_string(arg_1)))
468
-
|> pog.parameter(pog.array(
469
-
fn(value) { pog.text(uuid.to_string(value)) },
470
-
arg_2,
471
-
))
472
-
|> pog.returning(decoder)
473
-
|> pog.execute(db)
474
-
}
475
-
476
-
/// A row you get from running the `resolve_occurrence` query
477
-
/// defined in `./src/app/domain/occurrence/sql/resolve_occurrence.sql`.
478
-
///
479
-
/// > ๐ฟ๏ธ This type definition was generated automatically using v4.6.0 of the
480
-
/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
481
-
///
482
-
pub type ResolveOccurrenceRow {
483
-
ResolveOccurrenceRow(
484
-
id: Uuid,
485
-
resolved_at: Option(Timestamp),
486
-
updated_at: Timestamp,
514
+
|> pog.parameter(
515
+
pog.array(fn(value) { pog.text(uuid.to_string(value)) }, arg_2),
487
516
)
488
-
}
489
-
490
-
/// ๓ฐฐ Mark a occurrence as resolved
491
-
///
492
-
/// > ๐ฟ๏ธ This function was generated automatically using v4.6.0 of
493
-
/// > the [squirrel package](https://github.com/giacomocavalieri/squirrel).
494
-
///
495
-
pub fn resolve_occurrence(
496
-
db: pog.Connection,
497
-
arg_1: Uuid,
498
-
) -> Result(pog.Returned(ResolveOccurrenceRow), pog.QueryError) {
499
-
let decoder = {
500
-
use id <- decode.field(0, uuid_decoder())
501
-
use resolved_at <- decode.field(1, decode.optional(pog.timestamp_decoder()))
502
-
use updated_at <- decode.field(2, pog.timestamp_decoder())
503
-
decode.success(ResolveOccurrenceRow(id:, resolved_at:, updated_at:))
504
-
}
505
-
506
-
"-- ๓ฐฐ Mark a occurrence as resolved
507
-
update public.occurrence
508
-
set
509
-
resolved_at = current_timestamp,
510
-
updated_at = current_timestamp
511
-
where id = $1
512
-
returning
513
-
id,
514
-
resolved_at,
515
-
updated_at;
516
-
"
517
-
|> pog.query
518
-
|> pog.parameter(pog.text(uuid.to_string(arg_1)))
519
517
|> pog.returning(decoder)
520
518
|> pog.execute(db)
521
519
}
···
553
551
MedicEmergency -> "medic_emergency"
554
552
}
555
553
|> pog.text
556
-
}
557
-
558
-
/// Corresponds to the Postgres `occurrence_priority_enum` enum.
554
+
}/// Corresponds to the Postgres `occurrence_priority_enum` enum.
559
555
///
560
556
/// > ๐ฟ๏ธ This type definition was generated automatically using v4.6.0 of the
561
557
/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
···
583
579
Low -> "low"
584
580
}
585
581
|> pog.text
586
-
}
587
-
588
-
/// Corresponds to the Postgres `occurrence_subcategory_enum` enum.
582
+
}/// Corresponds to the Postgres `occurrence_subcategory_enum` enum.
589
583
///
590
584
/// > ๐ฟ๏ธ This type definition was generated automatically using v4.6.0 of the
591
585
/// > [squirrel package](https://github.com/giacomocavalieri/squirrel).
···
609
603
HeartStop
610
604
}
611
605
612
-
fn occurrence_subcategory_enum_decoder() -> decode.Decoder(
613
-
OccurrenceSubcategoryEnum,
614
-
) {
606
+
fn occurrence_subcategory_enum_decoder() -> decode.Decoder(OccurrenceSubcategoryEnum) {
615
607
use occurrence_subcategory_enum <- decode.then(decode.string)
616
608
case occurrence_subcategory_enum {
617
609
"injured_animal" -> decode.success(InjuredAnimal)
···
634
626
}
635
627
}
636
628
637
-
fn occurrence_subcategory_enum_encoder(occurrence_subcategory_enum) -> pog.Value {
629
+
fn occurrence_subcategory_enum_encoder(
630
+
occurrence_subcategory_enum,
631
+
) -> pog.Value {
638
632
case occurrence_subcategory_enum {
639
633
InjuredAnimal -> "injured_animal"
640
634
Flood -> "flood"
src/app/domain/occurrence/sql/resolve_occurrence.sql
src/app/domain/occurrence/sql/close_occurrence.sql
src/app/domain/occurrence/sql/resolve_occurrence.sql
src/app/domain/occurrence/sql/close_occurrence.sql
+4
-67
src/app/domain/occurrence/update_occurrence_status.gleam
src/app/domain/occurrence/reopen_occurrence.gleam
+4
-67
src/app/domain/occurrence/update_occurrence_status.gleam
src/app/domain/occurrence/reopen_occurrence.gleam
···
40
40
ctx ctx: Context,
41
41
id occurrence_id: String,
42
42
) -> wisp.Response {
43
-
case req.method {
44
-
// Mark an occurrence as resolved
45
-
http.Post ->
46
-
case resolve_occurrence(req, ctx, occurrence_id) {
47
-
Error(err) -> handle_error(err)
48
-
Ok(body) -> wisp.json_response(body, 200)
49
-
}
50
-
51
-
// Reopen a resolved occurrence
52
-
http.Delete ->
53
-
case reopen_occurrence(req, ctx, occurrence_id) {
54
-
Error(err) -> handle_error(err)
55
-
Ok(body) -> wisp.json_response(body, 200)
56
-
}
43
+
use <- wisp.require_method(req, http.Post)
57
44
58
-
_ -> wisp.method_not_allowed([http.Post, http.Delete])
45
+
case reopen_occurrence(req, ctx, occurrence_id) {
46
+
Error(err) -> handle_error(err)
47
+
Ok(body) -> wisp.json_response(body, 200)
59
48
}
60
-
}
61
-
62
-
fn resolve_occurrence(
63
-
req: wisp.Request,
64
-
ctx: Context,
65
-
occ_id: String,
66
-
) -> Result(String, ResolveOccurrenceError) {
67
-
use _ <- result.try(
68
-
user.extract_uuid(request: req, cookie_name: user.uuid_cookie_name)
69
-
|> result.map_error(AccessControl),
70
-
)
71
-
72
-
use target <- result.try(
73
-
uuid.from_string(occ_id)
74
-
|> result.replace_error(InvalidUuid(occ_id)),
75
-
)
76
-
77
-
use returned <- result.try(
78
-
sql.resolve_occurrence(ctx.db, target)
79
-
|> result.map_error(DataBase),
80
-
)
81
-
82
-
use row <- result.map(
83
-
list.first(returned.rows)
84
-
|> result.replace_error(OccurrenceNotFound(target)),
85
-
)
86
-
87
-
// ๏ผ Broadcast to all assigned users ----------------------------------------
88
-
let _ =
89
-
occurrence.broadcast(
90
-
ctx:,
91
-
registry: group_registry.get_registry(ctx.registry_name),
92
-
occurrence: row.id,
93
-
message: msg.Domain(msg.OccurrenceResolved(
94
-
id: row.id,
95
-
when: row.resolved_at,
96
-
)),
97
-
)
98
-
99
-
// RESPONSE
100
-
let timestamp_json =
101
-
json.nullable(row.resolved_at, fn(time) {
102
-
timestamp.to_unix_seconds(time) |> json.float
103
-
})
104
-
105
-
json.to_string(
106
-
json.object([
107
-
#("id", json.string(uuid.to_string(row.id))),
108
-
#("resolved_at", timestamp_json),
109
-
#("updated_at", json.float(timestamp.to_unix_seconds(row.updated_at))),
110
-
]),
111
-
)
112
49
}
113
50
114
51
fn reopen_occurrence(
+2
-2
src/app/domain/role/get_role_list.gleam
+2
-2
src/app/domain/role/get_role_list.gleam
···
17
17
/// ```
18
18
///
19
19
pub fn handle_request(
20
-
request request: wisp.Request,
20
+
request req: wisp.Request,
21
21
ctx ctx: Context,
22
22
) -> wisp.Response {
23
-
use <- wisp.require_method(request, http.Get)
23
+
use <- wisp.require_method(req, http.Get)
24
24
25
25
case query_user_roles(ctx) {
26
26
Ok(body) -> wisp.json_response(body, 200)
+3
-3
src/app/domain/user/get_user_profile.gleam
+3
-3
src/app/domain/user/get_user_profile.gleam
···
27
27
/// }
28
28
/// ```
29
29
pub fn handle_request(
30
-
request request: wisp.Request,
30
+
request req: wisp.Request,
31
31
ctx ctx: Context,
32
32
) -> wisp.Response {
33
-
use <- wisp.require_method(request, http.Get)
33
+
use <- wisp.require_method(req, http.Get)
34
34
35
35
// ๓ฐกฆ Query the database
36
-
case query_user_data(ctx, request) {
36
+
case query_user_data(ctx, req) {
37
37
// ๏ Handle possible errors
38
38
Error(err) -> handle_error(err)
39
39
// ๓ฑ Send the response to the client
+10
-11
src/app/domain/user/login.gleam
+10
-11
src/app/domain/user/login.gleam
···
10
10
import argus
11
11
import formal/form
12
12
import gleam/float
13
+
import gleam/http
13
14
import gleam/http/response
14
15
import gleam/json
15
16
import gleam/list
···
50
51
/// ```sh
51
52
/// set-cookie: USER_ID=0199b58a-acb0-70a8-9de7-0b65a03b8743
52
53
/// ```
53
-
pub fn handle_request(request request: wisp.Request, ctx ctx: Context) {
54
-
use form_data <- wisp.require_form(request)
54
+
pub fn handle_request(request req: wisp.Request, ctx ctx: Context) {
55
+
use <- wisp.require_method(req, http.Post)
56
+
57
+
use form_data <- wisp.require_form(req)
55
58
let form_result =
56
59
login_form()
57
60
|> form.add_values(form_data.values)
···
61
64
Error(_) -> wisp.unprocessable_content()
62
65
Ok(data) -> {
63
66
let cookie = user.uuid_cookie_name
64
-
handle_login(request, ctx, data, cookie)
67
+
handle_login(req, ctx, data, cookie)
65
68
}
66
69
}
67
70
}
68
71
69
72
fn handle_login(
70
-
request: wisp.Request,
73
+
req: wisp.Request,
71
74
ctx: Context,
72
75
data: RequestBody,
73
76
name: String,
74
77
) -> response.Response(wisp.Body) {
75
78
case query_database(data, ctx) {
76
79
Error(err) -> handle_error(err)
77
-
Ok(resp) -> set_token(resp, request, name)
80
+
Ok(resp) -> set_token(resp, req, name)
78
81
}
79
82
}
80
83
81
-
fn set_token(
82
-
resp: LoginToken,
83
-
request: wisp.Request,
84
-
name: String,
85
-
) -> wisp.Response {
84
+
fn set_token(resp: LoginToken, req: wisp.Request, name: String) -> wisp.Response {
86
85
let response = wisp.json_response(resp.body, 200)
87
86
let value = uuid.to_string(resp.user_id)
88
87
let security = wisp.Signed
···
92
91
|> duration.to_seconds
93
92
|> float.round
94
93
95
-
wisp.set_cookie(response:, request:, name:, value:, security:, max_age:)
94
+
wisp.set_cookie(response:, request: req, name:, value:, security:, max_age:)
96
95
}
97
96
98
97
/// ๓ฑ A form that decodes the `LogIn` value.
+2
src/app/domain/user/signup.gleam
+2
src/app/domain/user/signup.gleam
···
13
13
import app/web/context.{type Context}
14
14
import argus
15
15
import formal/form
16
+
import gleam/http
16
17
import gleam/json
17
18
import gleam/list
18
19
import gleam/result
···
31
32
request req: wisp.Request,
32
33
ctx ctx: Context,
33
34
) -> wisp.Response {
35
+
use <- wisp.require_method(req, http.Post)
34
36
use form_data <- wisp.require_form(req)
35
37
let form_result =
36
38
signup_form()
+4
-4
src/app/domain/user/update_user_password.gleam
+4
-4
src/app/domain/user/update_user_password.gleam
···
20
20
///
21
21
/// ๎ธฌ Extracts the user UUID form the request's Cookies
22
22
pub fn handle_request(
23
-
request request: wisp.Request,
23
+
request req: wisp.Request,
24
24
ctx ctx: Context,
25
25
) -> wisp.Response {
26
-
use <- wisp.require_method(request, http.Put)
27
-
use form_data <- wisp.require_form(request)
26
+
use <- wisp.require_method(req, http.Put)
27
+
use form_data <- wisp.require_form(req)
28
28
let form_result =
29
29
update_password_form()
30
30
|> form.add_values(form_data.values)
31
31
|> form.run()
32
32
33
33
case form_result {
34
-
Ok(form_data) -> handle_form_data(request:, ctx:, form_data:)
34
+
Ok(form_data) -> handle_form_data(request: req, ctx:, form_data:)
35
35
Error(_) -> {
36
36
let resp = wisp.unprocessable_content()
37
37
+34
-38
src/app/http_router.gleam
+34
-38
src/app/http_router.gleam
···
18
18
import app/domain/data_analysis/analysis_occurrence_volume
19
19
import app/domain/notification/get_notification_preferences
20
20
import app/domain/notification/update_notification_preferences
21
+
import app/domain/occurrence/close_occurrence
21
22
import app/domain/occurrence/delete_occurrence
22
23
import app/domain/occurrence/get_ocurrences_by_applicant
23
24
import app/domain/occurrence/register_new_occurrence
24
-
import app/domain/occurrence/update_occurrence_status
25
+
import app/domain/occurrence/reopen_occurrence
25
26
import app/domain/role/get_role_list
26
27
import app/domain/user/delete_user
27
28
import app/domain/user/get_all_user_profiles
···
34
35
import app/domain/user/update_user_status
35
36
import app/web
36
37
import app/web/context.{type Context}
37
-
import gleam/http
38
38
import wisp
39
39
40
40
/// ๓ฑ Main request router - matches HTTP methods and paths to appropriate handlers
···
44
44
ctx ctx: Context,
45
45
) -> wisp.Response {
46
46
use request <- web.middleware(request:, context: ctx)
47
-
case request.method, wisp.path_segments(request) {
47
+
case wisp.path_segments(request) {
48
48
// ๎ฒ Security routes -------------------------------------------------
49
-
http.Post, ["user", "login"] -> login.handle_request(request:, ctx:)
49
+
["user", "login"] -> login.handle_request(request:, ctx:)
50
50
51
-
http.Put, ["user", "password"] ->
52
-
update_user_password.handle_request(request:, ctx:)
51
+
["user", "password"] -> update_user_password.handle_request(request:, ctx:)
53
52
54
53
// ๎ฒ Admin routes ---------------------------------------------------------
55
-
http.Post, ["admin", "setup"] ->
56
-
setup_first_admin.handle_request(request:, ctx:)
54
+
["admin", "setup"] -> setup_first_admin.handle_request(request:, ctx:)
57
55
58
-
http.Post, ["admin", "signup"] -> signup.handle_request(request:, ctx:)
56
+
["admin", "signup"] -> signup.handle_request(request:, ctx:)
59
57
60
-
http.Get, ["admin", "users"] ->
61
-
get_all_user_profiles.handle_request(request:, ctx:)
58
+
["admin", "users"] -> get_all_user_profiles.handle_request(request:, ctx:)
62
59
63
-
http.Put, ["admin", "users", id] ->
60
+
["admin", "users", id, "update"] ->
64
61
admin_update_user.handle_request(request:, ctx:, id:)
65
62
66
-
http.Delete, ["admin", "users", id] ->
63
+
["admin", "users", id, "delete"] ->
67
64
delete_user.handle_request(request:, ctx:, id:)
68
65
69
-
http.Put, ["admin", "users", id, "status"] ->
66
+
["admin", "users", id, "status"] ->
70
67
update_user_status.handle_request(request:, ctx:, id:)
71
68
72
-
http.Get, ["admin", "teams"] ->
73
-
get_all_brigades.handle_request(request:, ctx:)
69
+
["admin", "brigade"] -> get_all_brigades.handle_request(request:, ctx:)
74
70
75
-
http.Post, ["admin", "teams"] ->
71
+
["admin", "brigade", "new"] ->
76
72
register_new_brigade.handle_request(request:, ctx:)
77
73
78
-
http.Put, ["admin", "teams", id, "status"] ->
74
+
["admin", "brigade", id, "status"] ->
79
75
update_brigade_status.handle_request(request:, ctx:, id:)
80
76
81
-
http.Delete, ["admin", "teams", id] ->
77
+
["admin", "brigade", id] ->
82
78
delete_brigade.handle_request(request:, ctx:, id:)
83
79
84
80
// ๓ฐจ Dashboard stats ------------------------------------------------------
85
-
http.Get, ["dashboard", "stats"] -> dashboard.handle_request(request:, ctx:)
81
+
["dashboard", "stats"] -> dashboard.handle_request(request:, ctx:)
86
82
87
83
// ๓ฐฎ Data analysis routes
88
-
http.Get, ["analysis", "occurrence"] ->
84
+
["analysis", "occurrence"] ->
89
85
analysis_occurrence_volume.handle_request(request:, ctx:)
90
86
91
87
// ๏ User data routes -----------------------------------------------------
92
-
http.Get, ["user", id, "occurrences"] ->
88
+
["user", id, "occurrences"] ->
93
89
get_ocurrences_by_applicant.handle_request(request:, ctx:, id:)
94
90
95
-
http.Get, ["user", "profile"] ->
96
-
get_user_profile.handle_request(request:, ctx:)
91
+
["user", "profile"] -> get_user_profile.handle_request(request:, ctx:)
97
92
98
-
http.Put, ["user", "profile"] ->
93
+
["user", "profile", "update"] ->
99
94
update_user_profile.handle_request(request:, ctx:)
100
95
101
-
http.Get, ["user", id, "crew_members"] ->
96
+
["user", id, "crew_members"] ->
102
97
get_crew_members.handle_request(request:, ctx:, id:)
103
98
104
99
// ๏บ Notification routes --------------------------------------------------
105
-
http.Get, ["user", "notification_preferences"] ->
100
+
["user", "notification_preferences"] ->
106
101
get_notification_preferences.handle_request(request:, ctx:)
107
102
108
-
http.Put, ["user", "notification_preferences"] ->
103
+
["user", "notification_preferences", "update"] ->
109
104
update_notification_preferences.handle_request(request:, ctx:)
110
105
111
106
// ๓ฐ Occurrence routes ----------------------------------------------------
112
-
http.Post, ["occurrence", "new"] ->
107
+
["occurrence", "new"] ->
113
108
register_new_occurrence.handle_request(request:, ctx:)
114
109
115
-
http.Delete, ["occurrence", id] ->
116
-
delete_occurrence.handle_request(request:, ctx:, id:)
110
+
["occurrence", id] -> delete_occurrence.handle_request(request:, ctx:, id:)
117
111
118
-
http.Post, ["occurrence", "resolved_at", id]
119
-
| http.Delete, ["occurrence", "resolved_at", id]
120
-
-> update_occurrence_status.handle_request(request:, ctx:, id:)
112
+
["occurrence", "close", id] ->
113
+
close_occurrence.handle_request(request:, ctx:, id:)
114
+
115
+
["occurrence", "reopen", id] ->
116
+
reopen_occurrence.handle_request(request:, ctx:, id:)
121
117
122
118
// ๓ฐขซ Brigade routes -------------------------------------------------------
123
-
http.Get, ["brigade", id, "members"] ->
119
+
["brigade", id, "members"] ->
124
120
get_brigade_members.handle_request(request:, ctx:, id:)
125
121
126
122
// ๎พ Role routes ----------------------------------------------------------
127
-
http.Get, ["user", "roles"] -> get_role_list.handle_request(request:, ctx:)
123
+
["user", "roles"] -> get_role_list.handle_request(request:, ctx:)
128
124
129
125
// Fallback routes ---------------------------------------------------------
130
-
_, [] -> wisp.ok() |> wisp.html_body("<h2>๐ </h2>")
131
-
_, _ -> wisp.not_found()
126
+
[] -> wisp.ok() |> wisp.html_body("<h2>๐ </h2>")
127
+
_ -> wisp.not_found()
132
128
}
133
129
}
+1
-1
test/admin_test.gleam
+1
-1
test/admin_test.gleam
···
18
18
19
19
// DUMMY USER ----------------------------------------------------------------
20
20
let dummy_user_id = dummy.random_user(ctx.db)
21
-
let path = "/admin/users/" <> uuid.to_string(dummy_user_id)
21
+
let path = "/admin/users/" <> uuid.to_string(dummy_user_id) <> "/update"
22
22
23
23
// Data
24
24
let new_full_name = "wibble"
+2
-2
test/brigade_test.gleam
+2
-2
test/brigade_test.gleam
···
13
13
import youid/uuid
14
14
15
15
pub fn register_new_brigade_test() {
16
-
let path = "/admin/teams"
16
+
let path = "/admin/brigade/new"
17
17
let ctx = app_test.global_data()
18
18
use _ <- list.each(list.range(1, app_test.n_tests))
19
19
···
161
161
pub fn get_all_brigades_test() {
162
162
let ctx = app_test.global_data()
163
163
use _ <- list.each(list.range(1, app_test.n_tests))
164
-
let path = "/admin/teams"
164
+
let path = "/admin/brigade"
165
165
166
166
// ๏ DUMMY LEADER -----------------------------------------------------------
167
167
let leader_id = dummy.random_user(ctx.db)
+8
-8
test/occurrence_test.gleam
+8
-8
test/occurrence_test.gleam
···
279
279
let assert Ok(_) = dev_sql.soft_truncate_user_account(ctx.db)
280
280
}
281
281
282
-
pub fn resolve_occurrence_test() {
282
+
pub fn close_occurrence_test() {
283
283
let ctx = app_test.global_data()
284
-
let base_path = "/occurrence/resolved_at/"
284
+
let base_path = "/occurrence/close/"
285
285
use _ <- list.each(list.range(1, app_test.n_tests))
286
286
287
287
// DUMMY ---------------------------------------------------------------------
···
341
341
let assert Ok(_) = dev_sql.soft_truncate_user_account(ctx.db)
342
342
}
343
343
344
-
pub fn resolve_missing_occurrence_test() {
344
+
pub fn close_missing_occurrence_test() {
345
345
let ctx = app_test.global_data()
346
-
let base_path = "/occurrence/resolved_at/"
346
+
let base_path = "/occurrence/close/"
347
347
let path = base_path <> uuid.v7_string()
348
348
349
349
let req =
···
356
356
357
357
pub fn reopen_occurrence_test() {
358
358
let ctx = app_test.global_data()
359
-
let base_path = "/occurrence/resolved_at/"
359
+
let base_path = "/occurrence/reopen/"
360
360
use _ <- list.each(list.range(1, app_test.n_tests))
361
361
362
362
// DUMMY ---------------------------------------------------------------------
···
375
375
)
376
376
377
377
let path = base_path <> uuid.to_string(dummy_occurrence)
378
-
let req = simulate.request(http.Delete, path)
378
+
let req = simulate.request(http.Post, path)
379
379
let resp = http_router.handle_request(req, ctx)
380
380
381
381
assert resp.status == 401 as "Restricted to authenticated Users"
···
414
414
415
415
pub fn reopen_missing_occurrence_test() {
416
416
let ctx = app_test.global_data()
417
-
let base_path = "/occurrence/resolved_at/"
417
+
let base_path = "/occurrence/reopen/"
418
418
let path = base_path <> uuid.v7_string()
419
419
420
420
let req =
421
-
simulate.browser_request(http.Delete, path)
421
+
simulate.browser_request(http.Post, path)
422
422
|> app_test.with_authorization()
423
423
424
424
let resp = http_router.handle_request(req, ctx)