@@ -70,6 +70,7 @@ defmodule Canary.Plugs do
70
70
* `:id_field` - Specifies the name of the ID field in the database for searching :id_name value, defaults to "id".
71
71
* `:persisted` - Specifies the resource should always be loaded from the database, defaults to false
72
72
* `:not_found_handler` - Specify a handler function to be called if the resource is not found
73
+ * `:required` - Same as `:persisted` but with not found handler - even for :index, :new or :create action
73
74
74
75
Examples:
75
76
```
@@ -104,10 +105,13 @@ defmodule Canary.Plugs do
104
105
cond do
105
106
is_persisted ->
106
107
fetch_resource ( conn , opts )
108
+
107
109
action == :index ->
108
110
fetch_all ( conn , opts )
111
+
109
112
action in [ :new , :create ] ->
110
113
nil
114
+
111
115
true ->
112
116
fetch_resource ( conn , opts )
113
117
end
@@ -162,9 +166,12 @@ defmodule Canary.Plugs do
162
166
163
167
defp do_authorize_controller ( conn , opts ) do
164
168
controller = conn . assigns [ :canary_controller ] || conn . private [ :phoenix_controller ]
165
- current_user_name = opts [ :current_user ] ||
166
- Application . get_env ( :canary , :current_user , :current_user )
167
- current_user = Map . fetch! conn . assigns , current_user_name
169
+
170
+ current_user_name =
171
+ opts [ :current_user ] ||
172
+ Application . get_env ( :canary , :current_user , :current_user )
173
+
174
+ current_user = Map . fetch! ( conn . assigns , current_user_name )
168
175
action = get_action ( conn )
169
176
170
177
Plug.Conn . assign ( conn , :authorized , can? ( current_user , action , controller ) )
@@ -252,25 +259,31 @@ defmodule Canary.Plugs do
252
259
end
253
260
254
261
defp do_authorize_resource ( conn , opts ) do
255
- current_user_name = opts [ :current_user ] || Application . get_env ( :canary , :current_user , :current_user )
256
- current_user = Map . fetch! conn . assigns , current_user_name
262
+ current_user_name =
263
+ opts [ :current_user ] || Application . get_env ( :canary , :current_user , :current_user )
264
+
265
+ current_user = Map . fetch! ( conn . assigns , current_user_name )
257
266
action = get_action ( conn )
258
267
is_persisted = persisted? ( opts )
268
+
259
269
non_id_actions =
260
270
if opts [ :non_id_actions ] do
261
271
Enum . concat ( [ :index , :new , :create ] , opts [ :non_id_actions ] )
262
272
else
263
273
[ :index , :new , :create ]
264
274
end
265
275
266
- resource = cond do
267
- is_persisted ->
268
- fetch_resource ( conn , opts )
269
- action in non_id_actions ->
270
- opts [ :model ]
271
- true ->
272
- fetch_resource ( conn , opts )
273
- end
276
+ resource =
277
+ cond do
278
+ is_persisted ->
279
+ fetch_resource ( conn , opts )
280
+
281
+ action in non_id_actions ->
282
+ opts [ :model ]
283
+
284
+ true ->
285
+ fetch_resource ( conn , opts )
286
+ end
274
287
275
288
Plug.Conn . assign ( conn , :authorized , can? ( current_user , action , resource ) )
276
289
end
@@ -329,9 +342,11 @@ defmodule Canary.Plugs do
329
342
330
343
defp do_load_and_authorize_resource ( conn , opts ) do
331
344
conn
332
- |> Map . put ( :skip_canary_handler , true ) # skip not_found_handler so auth handler can catch first if needed
345
+ # skip not_found_handler so auth handler can catch first if needed
346
+ |> Map . put ( :skip_canary_handler , true )
333
347
|> load_resource ( opts )
334
- |> Map . delete ( :skip_canary_handler ) # allow auth handling
348
+ # allow auth handling
349
+ |> Map . delete ( :skip_canary_handler )
335
350
|> authorize_resource ( opts )
336
351
|> maybe_handle_not_found ( opts )
337
352
|> purge_resource_if_unauthorized ( opts )
@@ -343,6 +358,7 @@ defmodule Canary.Plugs do
343
358
344
359
defp purge_resource_if_unauthorized ( % { assigns: % { authorized: true } } = conn , _opts ) ,
345
360
do: conn
361
+
346
362
defp purge_resource_if_unauthorized ( % { assigns: % { authorized: false } } = conn , opts ) ,
347
363
do: Plug.Conn . assign ( conn , get_resource_name ( conn , opts ) , nil )
348
364
@@ -357,12 +373,15 @@ defmodule Canary.Plugs do
357
373
:error ->
358
374
repo . get_by ( opts [ :model ] , get_map_args )
359
375
|> preload_if_needed ( repo , opts )
376
+
360
377
{ :ok , nil } ->
361
378
repo . get_by ( opts [ :model ] , get_map_args )
362
379
|> preload_if_needed ( repo , opts )
380
+
363
381
{ :ok , resource } ->
364
382
if resource . __struct__ == opts [ :model ] do
365
- resource # A resource of the type passed as opts[:model] is already loaded; do not clobber it
383
+ # A resource of the type passed as opts[:model] is already loaded; do not clobber it
384
+ resource
366
385
else
367
386
opts [ :model ]
368
387
|> repo . get_by ( get_map_args )
@@ -376,9 +395,11 @@ defmodule Canary.Plugs do
376
395
377
396
resource_name = get_resource_name ( conn , opts )
378
397
379
- case Map . fetch ( conn . assigns , resource_name ) do # check if a resource is already loaded at the key
398
+ # check if a resource is already loaded at the key
399
+ case Map . fetch ( conn . assigns , resource_name ) do
380
400
:error ->
381
401
from ( m in opts [ :model ] ) |> select ( [ m ] , m ) |> repo . all |> preload_if_needed ( repo , opts )
402
+
382
403
{ :ok , resources } ->
383
404
if Enum . at ( resources , 0 ) . __struct__ == opts [ :model ] do
384
405
resources
@@ -392,6 +413,7 @@ defmodule Canary.Plugs do
392
413
case opts [ :id_name ] do
393
414
nil ->
394
415
conn . params [ "id" ]
416
+
395
417
id_name ->
396
418
conn . params [ id_name ]
397
419
end
@@ -400,7 +422,7 @@ defmodule Canary.Plugs do
400
422
defp get_action ( conn ) do
401
423
case Map . fetch ( conn . assigns , :canary_action ) do
402
424
{ :ok , action } -> action
403
- _ -> conn . private . phoenix_action
425
+ _ -> conn . private . phoenix_action
404
426
end
405
427
end
406
428
@@ -428,17 +450,24 @@ defmodule Canary.Plugs do
428
450
cond do
429
451
has_key? ( opts , :except ) && has_key? ( opts , :only ) ->
430
452
false
453
+
431
454
has_key? ( opts , :except ) ->
432
455
! action_exempt? ( conn , opts )
456
+
433
457
has_key? ( opts , :only ) ->
434
458
action_included? ( conn , opts )
459
+
435
460
true ->
436
461
true
437
462
end
438
463
end
439
464
440
465
defp persisted? ( opts ) do
441
- ! ! Keyword . get ( opts , :persisted , false )
466
+ ! ! Keyword . get ( opts , :persisted , false ) || ! ! Keyword . get ( opts , :required , false )
467
+ end
468
+
469
+ defp required? ( opts ) do
470
+ ! ! Keyword . get ( opts , :required , false )
442
471
end
443
472
444
473
defp get_resource_name ( conn , opts ) do
@@ -450,7 +479,9 @@ defmodule Canary.Plugs do
450
479
|> Macro . underscore ( )
451
480
|> pluralize_if_needed ( conn , opts )
452
481
|> String . to_atom ( )
453
- as -> as
482
+
483
+ as ->
484
+ as
454
485
end
455
486
end
456
487
@@ -470,15 +501,15 @@ defmodule Canary.Plugs do
470
501
case opts [ :preload ] do
471
502
nil ->
472
503
records
504
+
473
505
models ->
474
506
repo . preload ( records , models )
475
507
end
476
508
end
477
509
478
- defp handle_unauthorized ( % { skip_canary_handler: true } = conn , _opts ) ,
479
- do: conn
480
510
defp handle_unauthorized ( % { assigns: % { authorized: true } } = conn , _opts ) ,
481
511
do: conn
512
+
482
513
defp handle_unauthorized ( % { assigns: % { authorized: false } } = conn , opts ) ,
483
514
do: apply_error_handler ( conn , :unauthorized_handler , opts )
484
515
@@ -488,28 +519,32 @@ defmodule Canary.Plugs do
488
519
489
520
defp handle_not_found ( conn , opts ) do
490
521
action = get_action ( conn )
522
+
491
523
non_id_actions =
492
524
if opts [ :non_id_actions ] do
493
525
Enum . concat ( [ :index , :new , :create ] , opts [ :non_id_actions ] )
494
526
else
495
527
[ :index , :new , :create ]
496
528
end
529
+
530
+ is_required = required? ( opts )
497
531
resource_name = Map . get ( conn . assigns , get_resource_name ( conn , opts ) )
498
532
499
- if is_nil ( resource_name ) and not action in non_id_actions do
533
+ if is_nil ( resource_name ) and ( is_required or action not in non_id_actions ) do
500
534
apply_error_handler ( conn , :not_found_handler , opts )
501
535
else
502
536
conn
503
537
end
504
538
end
505
539
506
540
defp apply_error_handler ( conn , handler_key , opts ) do
507
- handler = Keyword . get ( opts , handler_key )
508
- || Application . get_env ( :canary , handler_key )
541
+ handler =
542
+ Keyword . get ( opts , handler_key ) ||
543
+ Application . get_env ( :canary , handler_key )
509
544
510
545
case handler do
511
546
{ mod , fun } -> apply ( mod , fun , [ conn ] )
512
- nil -> conn
547
+ nil -> conn
513
548
end
514
549
end
515
550
end
0 commit comments