@@ -28,99 +28,86 @@ use actix_web::{
28
28
HttpRequest , HttpResponse , Responder ,
29
29
} ;
30
30
use http:: StatusCode ;
31
- use serde_json:: { Error as SerdeError , Map } ;
31
+ use serde_json:: Error as SerdeError ;
32
32
33
- pub async fn list ( ) -> Result < impl Responder , DashboardError > {
33
+ pub async fn list_dashboards ( ) -> Result < impl Responder , DashboardError > {
34
34
let dashboards = DASHBOARDS . list_dashboards ( ) . await ;
35
- //dashboards list should contain the title, author and modified date
36
- let dashboards: Vec < Map < String , serde_json:: Value > > = dashboards
35
+ let dashboard_summaries = dashboards
37
36
. iter ( )
38
- . map ( |dashboard| {
39
- let mut map = Map :: new ( ) ;
40
- map. insert (
41
- "title" . to_string ( ) ,
42
- serde_json:: Value :: String ( dashboard. title . clone ( ) ) ,
43
- ) ;
44
- if let Some ( author) = & dashboard. author {
45
- map. insert (
46
- "author" . to_string ( ) ,
47
- serde_json:: Value :: String ( author. to_string ( ) ) ,
48
- ) ;
49
- }
50
- if let Some ( modified) = & dashboard. modified {
51
- map. insert (
52
- "modified" . to_string ( ) ,
53
- serde_json:: Value :: String ( modified. to_string ( ) ) ,
54
- ) ;
55
- }
56
- if let Some ( dashboard_id) = & dashboard. dashboard_id {
57
- map. insert (
58
- "dashboard_id" . to_string ( ) ,
59
- serde_json:: Value :: String ( dashboard_id. to_string ( ) ) ,
60
- ) ;
61
- }
62
- map
63
- } )
64
- . collect ( ) ;
65
- Ok ( ( web:: Json ( dashboards) , StatusCode :: OK ) )
37
+ . map ( |dashboard| dashboard. to_summary ( ) )
38
+ . collect :: < Vec < _ > > ( ) ;
39
+
40
+ Ok ( ( web:: Json ( dashboard_summaries) , StatusCode :: OK ) )
66
41
}
67
42
68
- pub async fn get ( dashboard_id : Path < String > ) -> Result < impl Responder , DashboardError > {
43
+ pub async fn get_dashboard ( dashboard_id : Path < String > ) -> Result < impl Responder , DashboardError > {
69
44
let dashboard_id = validate_dashboard_id ( dashboard_id. into_inner ( ) ) ?;
70
45
71
- if let Some ( dashboard) = DASHBOARDS . get_dashboard ( dashboard_id) . await {
72
- return Ok ( ( web:: Json ( dashboard) , StatusCode :: OK ) ) ;
73
- }
46
+ let dashboard = DASHBOARDS
47
+ . get_dashboard ( dashboard_id)
48
+ . await
49
+ . ok_or_else ( || DashboardError :: Metadata ( "Dashboard does not exist" ) ) ?;
74
50
75
- Err ( DashboardError :: Metadata ( "Dashboard does not exist" ) )
51
+ Ok ( ( web :: Json ( dashboard ) , StatusCode :: OK ) )
76
52
}
77
53
78
- pub async fn post (
54
+ pub async fn create_dashboard (
79
55
req : HttpRequest ,
80
56
Json ( mut dashboard) : Json < Dashboard > ,
81
57
) -> Result < impl Responder , DashboardError > {
82
58
if dashboard. title . is_empty ( ) {
83
59
return Err ( DashboardError :: Metadata ( "Title must be provided" ) ) ;
84
60
}
85
- let mut user_id = get_user_from_request ( & req) ?;
86
- user_id = get_hash ( & user_id) ;
87
- dashboard. author = Some ( user_id. clone ( ) ) ;
61
+
62
+ let user_id = get_hash ( & get_user_from_request ( & req) ?) ;
88
63
89
64
DASHBOARDS . create ( & user_id, & mut dashboard) . await ?;
90
65
Ok ( ( web:: Json ( dashboard) , StatusCode :: OK ) )
91
66
}
92
67
93
- pub async fn update (
68
+ pub async fn update_dashboard (
94
69
req : HttpRequest ,
95
70
dashboard_id : Path < String > ,
96
71
Json ( mut dashboard) : Json < Dashboard > ,
97
72
) -> Result < impl Responder , DashboardError > {
98
- let mut user_id = get_user_from_request ( & req) ?;
99
- user_id = get_hash ( & user_id) ;
73
+ let user_id = get_hash ( & get_user_from_request ( & req) ?) ;
100
74
let dashboard_id = validate_dashboard_id ( dashboard_id. into_inner ( ) ) ?;
101
75
102
- for tile in dashboard. tiles . as_ref ( ) . unwrap_or ( & Vec :: new ( ) ) {
103
- if tile. tile_id . is_nil ( ) {
104
- return Err ( DashboardError :: Metadata (
105
- "Tile ID must be provided by the client" ,
106
- ) ) ;
76
+ // Validate all tiles have valid IDs
77
+ if let Some ( tiles) = & dashboard. tiles {
78
+ if tiles. iter ( ) . any ( |tile| tile. tile_id . is_nil ( ) ) {
79
+ return Err ( DashboardError :: Metadata ( "Tile ID must be provided" ) ) ;
80
+ }
81
+ }
82
+
83
+ // Check if tile_id are unique
84
+ if let Some ( tiles) = & dashboard. tiles {
85
+ let unique_tiles: Vec < _ > = tiles
86
+ . iter ( )
87
+ . map ( |tile| tile. tile_id )
88
+ . collect :: < std:: collections:: HashSet < _ > > ( )
89
+ . into_iter ( )
90
+ . collect ( ) ;
91
+
92
+ if unique_tiles. len ( ) != tiles. len ( ) {
93
+ return Err ( DashboardError :: Metadata ( "Tile IDs must be unique" ) ) ;
107
94
}
108
95
}
109
- dashboard. author = Some ( user_id. clone ( ) ) ;
110
96
111
97
DASHBOARDS
112
98
. update ( & user_id, dashboard_id, & mut dashboard)
113
99
. await ?;
100
+
114
101
Ok ( ( web:: Json ( dashboard) , StatusCode :: OK ) )
115
102
}
116
103
117
- pub async fn delete (
104
+ pub async fn delete_dashboard (
118
105
req : HttpRequest ,
119
106
dashboard_id : Path < String > ,
120
107
) -> Result < HttpResponse , DashboardError > {
121
- let mut user_id = get_user_from_request ( & req) ?;
122
- user_id = get_hash ( & user_id) ;
108
+ let user_id = get_hash ( & get_user_from_request ( & req) ?) ;
123
109
let dashboard_id = validate_dashboard_id ( dashboard_id. into_inner ( ) ) ?;
110
+
124
111
DASHBOARDS . delete_dashboard ( & user_id, dashboard_id) . await ?;
125
112
126
113
Ok ( HttpResponse :: Ok ( ) . finish ( ) )
@@ -131,22 +118,26 @@ pub async fn add_tile(
131
118
dashboard_id : Path < String > ,
132
119
Json ( tile) : Json < Tile > ,
133
120
) -> Result < impl Responder , DashboardError > {
134
- let mut user_id = get_user_from_request ( & req) ?;
135
- user_id = get_hash ( & user_id) ;
136
- let dashboard_id = validate_dashboard_id ( dashboard_id. into_inner ( ) ) ?;
137
-
138
121
if tile. tile_id . is_nil ( ) {
139
- return Err ( DashboardError :: Metadata (
140
- "Tile ID must be provided by the client" ,
141
- ) ) ;
122
+ return Err ( DashboardError :: Metadata ( "Tile ID must be provided" ) ) ;
142
123
}
143
124
125
+ let user_id = get_hash ( & get_user_from_request ( & req) ?) ;
126
+ let dashboard_id = validate_dashboard_id ( dashboard_id. into_inner ( ) ) ?;
127
+
144
128
let mut dashboard = DASHBOARDS
145
129
. get_dashboard_by_user ( dashboard_id, & user_id)
146
130
. await
147
131
. ok_or ( DashboardError :: Unauthorized ) ?;
132
+
148
133
let tiles = dashboard. tiles . get_or_insert_with ( Vec :: new) ;
149
- tiles. push ( tile. clone ( ) ) ;
134
+
135
+ // check if the tile already exists
136
+ if tiles. iter ( ) . any ( |t| t. tile_id == tile. tile_id ) {
137
+ return Err ( DashboardError :: Metadata ( "Tile already exists" ) ) ;
138
+ }
139
+ tiles. push ( tile) ;
140
+
150
141
DASHBOARDS
151
142
. update ( & user_id, dashboard_id, & mut dashboard)
152
143
. await ?;
@@ -166,7 +157,7 @@ pub enum DashboardError {
166
157
UserDoesNotExist ( #[ from] RBACError ) ,
167
158
#[ error( "Error: {0}" ) ]
168
159
Custom ( String ) ,
169
- #[ error( "Unauthorized to access resource " ) ]
160
+ #[ error( "Dashboard does not exist or is not accessible " ) ]
170
161
Unauthorized ,
171
162
}
172
163
0 commit comments