Skip to content

Commit 22001b6

Browse files
committed
reenable and fix stats rendering
1 parent 1855978 commit 22001b6

File tree

10 files changed

+269
-115
lines changed

10 files changed

+269
-115
lines changed

.sqlx/query-eb5c92f5a47a730bf82d92fc0107913cb37d57d99f0170538f1b1da14665bbb5.json renamed to .sqlx/query-86474d3afa501597c7eeef4136a60d39c8a9cd5c327c4dff3776b4cfc37f1dc5.json

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/src/link_api.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use dioxus::prelude::{ServerFnError, server, server_fn};
1010
use enum_map::EnumMap;
1111
use pslink_shared::{
1212
apirequests::links::{LinkDelta, LinkRequestForm},
13-
datatypes::{FullLink, Item, Link, ListWithOwner},
13+
datatypes::{Clicks, FullLink, Item, Link, ListWithOwner},
1414
};
1515

1616
#[cfg(feature = "server")]
@@ -20,7 +20,7 @@ use pslink_shared::{
2020
links::LinkOverviewColumns,
2121
users::Role,
2222
},
23-
datatypes::{Clicks, Count, Lang, Secret, User},
23+
datatypes::{Count, Lang, Secret, User},
2424
};
2525
/// Returns a List of `FullLink` meaning `Links` enriched by their author and statistics. This returns all links if the user is either Admin or Regular user.
2626
///
@@ -272,3 +272,21 @@ pub async fn delete_link(link_id: i64) -> Result<(), ServerFnError> {
272272

273273
Ok(())
274274
}
275+
276+
#[server(GetLinkStatistics, endpoint = "get_link_statistics")]
277+
pub async fn get_link_statistics(link_id: i64) -> Result<Clicks, ServerFnError> {
278+
let auth = crate::auth::get_session().await?;
279+
if auth.is_anonymous() {
280+
return Err(ServerFnError::new("Not authenticated".to_owned()));
281+
}
282+
let _user = auth
283+
.current_user
284+
.expect("not authenticated")
285+
.get_user()
286+
.expect("User is authenticated");
287+
288+
// Get existing link first
289+
let stats = Link::get_statistics(link_id).await?;
290+
291+
Ok(Clicks::Extended(stats))
292+
}

backend/src/models.rs

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ pub trait LinkDbOperations<T> {
280280
async fn get_link_by_id(id: i64) -> Result<T, ServerFnError>;
281281
async fn delete_link_by_code(code: &str) -> Result<(), ServerFnError>;
282282
async fn update_link(&self) -> Result<(), ServerFnError>;
283-
async fn get_statistics(code: i64) -> Result<Statistics, ServerFnError>;
283+
async fn get_statistics(link_id: i64) -> Result<Statistics, ServerFnError>;
284284
}
285285

286286
impl LinkDbOperations<Self> for Link {
@@ -292,24 +292,37 @@ impl LinkDbOperations<Self> for Link {
292292
async fn get_statistics(link_id: i64) -> Result<Statistics, ServerFnError> {
293293
let db = crate::get_db().await;
294294
// Verify that the code exists to avoid injections in the next query
295-
let code = sqlx::query!("select code from links where id=?", link_id)
295+
let link = sqlx::query!("select id,code from links where id=?", link_id)
296296
.fetch_one(&db)
297-
.await?
298-
.code;
299-
// The query to get the statistics carefully check code before to avoid injections.
300-
let qry = format!(
301-
r#"SELECT created_at AS month,
302-
cast(strftime('%W', created_at) AS String) AS week,
303-
count(*) AS total
304-
FROM clicks
305-
WHERE month > date('now', 'start of month', '-1 year')
306-
AND link = '{}'
307-
GROUP BY week
308-
ORDER BY month"#,
309-
link_id
310-
);
297+
.await?;
298+
// Use proper parameter binding for SQLx static analysis
299+
let qry = "WITH all_weeks AS (
300+
WITH RECURSIVE weeks(date_value) AS (
301+
SELECT datetime('now', 'start of month', '-1 year')
302+
UNION ALL
303+
SELECT datetime(date_value, '+7 days')
304+
FROM weeks
305+
WHERE date_value < date('now')
306+
)
307+
SELECT
308+
date_value AS month,
309+
cast(strftime('%W', date_value) AS String) AS week
310+
FROM weeks
311+
)
312+
SELECT
313+
aw.month,
314+
aw.week,
315+
COALESCE(COUNT(c.id), 0) AS total
316+
FROM all_weeks aw
317+
LEFT JOIN clicks c ON cast(strftime('%W', c.created_at) AS String) = aw.week
318+
AND c.link = ?
319+
AND c.created_at > date('now', 'start of month', '-1 year')
320+
GROUP BY aw.week
321+
ORDER BY aw.month";
322+
let code = link.code;
311323
// Execute and map the query to the desired type
312-
let values: Vec<WeekCount> = sqlx::query(&qry)
324+
let values: Vec<WeekCount> = sqlx::query(qry)
325+
.bind(link.id)
313326
.fetch_all(&db)
314327
.await?
315328
.into_iter()
@@ -326,13 +339,13 @@ ORDER BY month"#,
326339
"select count(*) as number from clicks join links on clicks.link = links.id where links.code = ?",
327340
code
328341
).fetch_one(&db).await?;
329-
info!("Found Statistics: {:?}", &values);
330342
Ok(Statistics {
331343
link_id,
332344
total,
333345
values,
334346
})
335347
}
348+
336349
/// Get a link by its code (the short url code)
337350
///
338351
/// # Errors

shared/src/datatypes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ impl Ord for WeekCount {
111111
}
112112
}
113113

114-
#[derive(Serialize, Deserialize, Debug, Clone)]
114+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
115115
pub struct Statistics {
116116
pub link_id: i64,
117117
pub total: Count,

translations/de-DE.ftl

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# Generated translation template by dioxus-i18n-collect
2-
# Contains 65 translation keys
2+
# Contains 68 translation keys
33

4-
# Source: ./ui/src/login.rs:108
4+
# Source: ./ui/src/navbar.rs:160
5+
demo-warning = Diese Instanz ist nicht für dauerhaftes Speichern konfiguriert... Die eingegebenen Daten werden nur bis zum Neustart gespeichert.
6+
7+
# Source: ./ui/src/login.rs:103
58
# Parameters: $error
69
failed-login = Benutzername oder passwort waren leider falsch, bitte versuche es erneut.
710
@@ -65,131 +68,141 @@ link-edit-placeholder-description = Beschreibung
6568
link-edit-placeholder-target = Ziel der Weiterleitung
6669
6770
# Button text to load more links
68-
# Source: ./ui/src/links/mod.rs:323
71+
# Source: ./ui/src/links/mod.rs:355
6972
links-button-load-more = Mehr Links laden
7073
7174
# Text displayed while loading links data
72-
# Source: ./ui/src/links/mod.rs:329
75+
# Source: ./ui/src/links/mod.rs:361
7376
links-loading = Die Links werden geladen
7477
7578
# Text for login link
76-
# Source: ./ui/src/links/mod.rs:330
79+
# Source: ./ui/src/links/mod.rs:362
7780
links-login = Anmelden
7881
7982
# Placeholder text for filter input field
80-
# Source: ./ui/src/links/mod.rs:242
83+
# Source: ./ui/src/links/mod.rs:261
8184
links-table-filter-placeholder = Filtere die Links nach…
8285
8386
# Column header for link code
84-
# Source: ./ui/src/links/mod.rs:204
87+
# Source: ./ui/src/links/mod.rs:222
8588
links-table-header-code = Code
8689
8790
# Column header for description
88-
# Source: ./ui/src/links/mod.rs:211
91+
# Source: ./ui/src/links/mod.rs:229
8992
links-table-header-description = Beschreibung
9093
9194
# Column header for statistics
92-
# Source: ./ui/src/links/mod.rs:232
95+
# Source: ./ui/src/links/mod.rs:250
9396
links-table-header-statistics = Statistik
9497
9598
# Column header for link target
96-
# Source: ./ui/src/links/mod.rs:218
99+
# Source: ./ui/src/links/mod.rs:236
97100
links-table-header-target = Ziel des Kurzlinks
98101
99102
# Column header for username
100-
# Source: ./ui/src/links/mod.rs:225
103+
# Source: ./ui/src/links/mod.rs:243
101104
links-table-header-username = Author
102105
103106
# The menu entry for login
104-
# Source: ./ui/src/login.rs:146
107+
# Source: ./ui/src/login.rs:141
105108
login = Anmelden
106109
107110
# The menu entry for logout
108111
# Source: ./ui/src/navbar.rs:106
109112
logout = Abmelden
110113
111114
# The title of the page
112-
# Source: ./ui/src/navbar.rs:136
115+
# Source: ./ui/src/navbar.rs:137
113116
page-not-found = 404 – Seite nicht gefunden
114117
115118
# The text of the page
116-
# Source: ./ui/src/navbar.rs:137
119+
# Source: ./ui/src/navbar.rs:138
117120
page-not-found-text = Diese Seite konnte nicht gefunden werden.
118121
119122
# Source: ./ui/src/login.rs:77
120123
password = Passwort
121124
122125
# The requested route on the 404 page
123-
# Source: ./ui/src/navbar.rs:138
126+
# Source: ./ui/src/navbar.rs:139
124127
# Parameters: $route
125128
requested-route = Der Pfad, der gesucht wurde: {$route}
126129
127130
# The menu entry for links
128131
# Source: ./ui/src/navbar.rs:69
129132
short_urls = Kurzlinks
130133
134+
# Displayed as a tooltip when there have been no clicks on this link in the last 12 months.
135+
# Source: ./ui/src/links/stats.rs:23
136+
# Parameters: $count
137+
tooltip_no_clicks = Dieser Link wurde in den letzen 12 Monaten nicht geklickt. Davor wurde er {$count} mal geklickt.
138+
139+
# Text below the click statistic graph
140+
# Source: ./ui/src/links/stats.rs:17
141+
# Parameters: $count
142+
total_clicks = Klicks insgesamt {$count}
143+
131144
# Button text for confirming user deletion
132-
# Source: ./ui/src/users/user_edit.rs:270
145+
# Source: ./ui/src/users/user_edit.rs:278
133146
user-edit-button-confirm-delete = Benutzer wirklich löschen
134147
135148
# Button text for creating a new user
136-
# Source: ./ui/src/users/user_edit.rs:215
149+
# Source: ./ui/src/users/user_edit.rs:221
137150
user-edit-button-create = Benutzer erstellen
138151
139152
# Button text for deleting a user
140-
# Source: ./ui/src/users/user_edit.rs:226
153+
# Source: ./ui/src/users/user_edit.rs:233
141154
user-edit-button-delete = Benutzer löschen
142155
143156
# Button text for updating an existing user
144-
# Source: ./ui/src/users/user_edit.rs:244
157+
# Source: ./ui/src/users/user_edit.rs:252
145158
user-edit-button-update = Benutzer editieren
146159
147160
# Warning message displayed when attempting to delete a user
148-
# Source: ./ui/src/users/user_edit.rs:168
161+
# Source: ./ui/src/users/user_edit.rs:173
149162
user-edit-delete-warning = Einen Nutzer zu löschen ist meist nicht sinnvoll, da die erstellten Links dann Besitzerlos sind. Besser wäre es einfach das Passwort zu ändern.
150163
151164
# Label for email field in edit form
152-
# Source: ./ui/src/users/user_edit.rs:66
165+
# Source: ./ui/src/users/user_edit.rs:70
153166
user-edit-label-email = E-Mail
154167
155168
# Label for password field in edit form
156-
# Source: ./ui/src/users/user_edit.rs:86
169+
# Source: ./ui/src/users/user_edit.rs:90
157170
user-edit-label-password = Passwort
158171
159172
# Label for role selection dropdown in edit form
160-
# Source: ./ui/src/users/user_edit.rs:111
173+
# Source: ./ui/src/users/user_edit.rs:115
161174
user-edit-label-role = Berechtigung
162175
163176
# Label for username field in edit form
164-
# Source: ./ui/src/users/user_edit.rs:42
177+
# Source: ./ui/src/users/user_edit.rs:46
165178
user-edit-label-username = Benutzername
166179
167180
# Placeholder text for email input field
168-
# Source: ./ui/src/users/user_edit.rs:72
181+
# Source: ./ui/src/users/user_edit.rs:76
169182
user-edit-placeholder-email = E-Mail
170183
171184
# Placeholder text for password input field
172-
# Source: ./ui/src/users/user_edit.rs:92
185+
# Source: ./ui/src/users/user_edit.rs:96
173186
user-edit-placeholder-password = Passwort
174187
175188
# Placeholder text for username input field
176-
# Source: ./ui/src/users/user_edit.rs:52
189+
# Source: ./ui/src/users/user_edit.rs:56
177190
user-edit-placeholder-username = Benutzername
178191
179192
# Option for admin role in dropdown
180-
# Source: ./ui/src/users/user_edit.rs:132
193+
# Source: ./ui/src/users/user_edit.rs:137
181194
user-edit-role-admin = Administrator
182195
183196
# Option for disabled role in dropdown
184-
# Source: ./ui/src/users/user_edit.rs:139
197+
# Source: ./ui/src/users/user_edit.rs:144
185198
user-edit-role-disabled = Deaktiviert
186199
187200
# Option for regular user role in dropdown
188-
# Source: ./ui/src/users/user_edit.rs:127
201+
# Source: ./ui/src/users/user_edit.rs:132
189202
user-edit-role-regular = Regulär
190203
191204
# Title of the username in the edit dialog
192-
# Source: ./ui/src/users/user_edit.rs:297
205+
# Source: ./ui/src/users/user_edit.rs:305
193206
# Parameters: $username
194207
user-edit-title = Benutzerdaten
195208
@@ -257,4 +270,3 @@ welcome-stranger = welcome-stranger
257270
# Parameters: $username
258271
welcome-user = Herzlich Wilkommen {$username}
259272
260-
demo-warning = Diese Instanz ist nicht für dauerhaftes Speichern konfiguriert... Die eingegebenen Daten werden nur bis zum Neustart gespeichert.

0 commit comments

Comments
 (0)