@@ -56,7 +56,7 @@ defmodule Sanbase.Menus do
56
56
query = Menu . by_id ( menu_id , user_id )
57
57
58
58
case Repo . one ( query ) do
59
- nil -> { :error , "Menu with id #{ menu_id } not found" }
59
+ nil -> { :error , "Menu with id #{ menu_id } not found or it is owned by another user " }
60
60
menu -> { :ok , menu }
61
61
end
62
62
end
@@ -65,10 +65,14 @@ defmodule Sanbase.Menus do
65
65
Convert a menu with preloaded menu items to a map in the format. This format
66
66
can directly be returned by the GraphQL API if the return type is `:json`
67
67
68
+ Note: The keys are strings in camelCase, not atoms in snake case. This is because this result
69
+ is directly returned to the API client as a JSON type, which does not go through the
70
+ snake_case => camelCase transformation.
71
+
68
72
%{
69
- entity: :menu, id: 1, name: "N", description: "D", menu_items: [
70
- %{entity_type: :query, id: 2, name: "Q", description: "D", position: 1},
71
- %{entity_type: :dashboard, id: 21, name: "D", description: "D", position: 2}
73
+ "entityType" => :menu, "entityId" 1, " name" => "N", " description" => "D", "menuItems" => [
74
+ %{"entityType" => :query, "entityType" => 2, " name" => "Q", " description" => "D", " position" => 1},
75
+ %{"entityType" => :dashboard, "entityType" => 21, " name" => "D", " description" => "D", " position" => 2}
72
76
]
73
77
}
74
78
"""
@@ -77,12 +81,12 @@ defmodule Sanbase.Menus do
77
81
# If this menu is a sub-menu, then the caller from get_menu_items/1 will
78
82
# additionally set the menu_item_id. If this is the top-level menu, then
79
83
# this is not a sub-menu and it does not have a menu_item_id
80
- menu_item_id: nil ,
81
- type: :menu ,
82
- id: menu . id ,
83
- name: menu . name ,
84
- description: menu . description ,
85
- menu_items: get_menu_items ( menu )
84
+ "menuItemId" => nil ,
85
+ "entityType" => :menu ,
86
+ "entityId" => menu . id ,
87
+ " name" => menu . name ,
88
+ " description" => menu . description ,
89
+ "menuItems" => get_menu_items ( menu )
86
90
}
87
91
|> recursively_order_menu_items ( )
88
92
end
@@ -212,7 +216,7 @@ defmodule Sanbase.Menus do
212
216
case Map . get ( params , :position ) do
213
217
nil ->
214
218
# If `position` is not specified, add it at the end by getting the last position + 1
215
- { :ok , get_next_position ( params . parent_id ) }
219
+ get_next_position ( params . parent_id )
216
220
217
221
position when is_integer ( position ) ->
218
222
# If `position` is specified, bump all the positions bigger than it by 1 in
@@ -256,17 +260,32 @@ defmodule Sanbase.Menus do
256
260
get_menu_item_for_update ( menu_item_id , user_id )
257
261
end )
258
262
|> Ecto.Multi . run (
259
- :maybe_update_items_positions ,
263
+ :get_new_params_after_position_adjustment ,
260
264
fn _repo , % { get_menu_item_for_update: menu_item } ->
261
265
case Map . get ( params , :position ) do
262
266
nil ->
263
- { :ok , nil }
267
+ parent_id = Map . get ( params , :parent_id )
268
+
269
+ # We cannot change the parent_id without also specifying the position
270
+ case is_nil ( parent_id ) or parent_id == menu_item . parent_id do
271
+ true ->
272
+ { :ok , params }
273
+
274
+ false ->
275
+ { :error ,
276
+ "If the parent_id for a menu item is updated, the position in the new menu must also be specified" }
277
+ end
264
278
265
279
position when is_integer ( position ) ->
266
280
# If `position` is specified, bump all the positions bigger than it by 1 in
267
281
# order to avoid having multiple items with the same position.
268
- { :ok , { _ , nil } } = inc_all_positions_after ( menu_item . parent_id , position )
269
- { :ok , position }
282
+ #
283
+ # If the menu gets its parent_id also changed , the bumping
284
+ # must happen in the new parent menu, not in the old one.
285
+ parent_id_after_update = Map . get ( params , :parent_id , menu_item . parent_id )
286
+
287
+ { :ok , { _ , nil } } = inc_all_positions_after ( parent_id_after_update , position )
288
+ { :ok , params }
270
289
end
271
290
end
272
291
)
@@ -307,7 +326,7 @@ defmodule Sanbase.Menus do
307
326
query = Menu . get_for_update ( menu_id , user_id )
308
327
309
328
case Repo . one ( query ) do
310
- nil -> { :error , "Menu item does not exist " }
329
+ nil -> { :error , "Menu with id #{ menu_id } not found or it is owned by another user " }
311
330
menu -> { :ok , menu }
312
331
end
313
332
end
@@ -316,13 +335,18 @@ defmodule Sanbase.Menus do
316
335
query = MenuItem . get_for_update ( menu_item_id , user_id )
317
336
318
337
case Repo . one ( query ) do
319
- nil -> { :error , "Menu item does not exist" }
320
- menu -> { :ok , menu }
338
+ nil ->
339
+ { :error ,
340
+ "Menu item with id #{ menu_item_id } not found or it is part of a menu owned by another user" }
341
+
342
+ menu ->
343
+ { :ok , menu }
321
344
end
322
345
end
323
346
324
347
defp get_next_position ( menu_id ) do
325
348
query = MenuItem . get_next_position ( menu_id )
349
+
326
350
{ :ok , Repo . one ( query ) }
327
351
end
328
352
@@ -341,15 +365,15 @@ defmodule Sanbase.Menus do
341
365
do: { :error , error }
342
366
343
367
# Helpers for transforming a menu struct to a simple map
344
- defp recursively_order_menu_items ( % { menu_items: menu_items } = map ) do
368
+ defp recursively_order_menu_items ( % { "menuItems" => menu_items } = map ) do
345
369
sorted_menu_items =
346
- Enum . sort_by ( menu_items , & & 1 . position , :asc )
370
+ Enum . sort_by ( menu_items , & & 1 [ " position" ] , :asc )
347
371
|> Enum . map ( fn
348
- % { menu_items: [ _ | _ ] } = elem -> recursively_order_menu_items ( elem )
372
+ % { "menuItems" => [ _ | _ ] } = elem -> recursively_order_menu_items ( elem )
349
373
x -> x
350
374
end )
351
375
352
- % { map | menu_items: sorted_menu_items }
376
+ % { map | "menuItems" => sorted_menu_items }
353
377
end
354
378
355
379
defp recursively_order_menu_items ( data ) , do: data
@@ -359,17 +383,38 @@ defmodule Sanbase.Menus do
359
383
defp get_menu_items ( % Menu { menu_items: list } ) when is_list ( list ) do
360
384
list
361
385
|> Enum . map ( fn
362
- % { id: menu_item_id , query: % { id: _ } = map , position: position } ->
363
- Map . take ( map , [ :id , :name , :description ] )
364
- |> Map . merge ( % { type: :query , position: position , menu_item_id: menu_item_id } )
386
+ % { id: menu_item_id , query: % { } = map , position: position } ->
387
+ % {
388
+ "name" => map . name ,
389
+ "description" => map . description ,
390
+ "entityType" => :query ,
391
+ "entityId" => map . id ,
392
+ "position" => position ,
393
+ "menuItemId" => menu_item_id
394
+ }
365
395
366
- % { id: menu_item_id , dashboard: % { id: _ } = map , position: position } ->
367
- Map . take ( map , [ :id , :name , :description ] )
368
- |> Map . merge ( % { type: :dashboard , position: position , menu_item_id: menu_item_id } )
396
+ % { id: menu_item_id , dashboard: % { } = map , position: position } ->
397
+ Map . take ( map , [ :name , :description ] )
398
+
399
+ % {
400
+ "name" => map . name ,
401
+ "description" => map . description ,
402
+ "entityType" => :dashboard ,
403
+ "entityId" => map . id ,
404
+ "position" => position ,
405
+ "menuItemId" => menu_item_id
406
+ }
369
407
370
- % { id: menu_item_id , menu: % { id: _ } = map , position: position } ->
408
+ % { id: menu_item_id , menu: % { } = map , position: position } ->
371
409
menu_to_simple_map ( map )
372
- |> Map . merge ( % { type: :menu , position: position , menu_item_id: menu_item_id } )
410
+ |> Map . merge ( % {
411
+ "name" => map . name ,
412
+ "description" => map . description ,
413
+ "entityType" => :menu ,
414
+ "entityId" => map . id ,
415
+ "position" => position ,
416
+ "menuItemId" => menu_item_id
417
+ } )
373
418
end )
374
419
end
375
420
end
0 commit comments