Adds fetching hits

This commit is contained in:
2025-10-08 18:49:29 +02:00
parent 544fb9bba9
commit caf98654ce
3 changed files with 127 additions and 10 deletions

View File

@@ -1,8 +1,9 @@
use crate::auth::Authenticated; use crate::auth::Authenticated;
use crate::dtos::hit::HitDTO;
use crate::dtos::tracker::{NewTrackerDTO, TrackerDTO}; use crate::dtos::tracker::{NewTrackerDTO, TrackerDTO};
use crate::models::AppState; use crate::models::AppState;
use crate::models::tracker::Tracker; use crate::models::tracker::Tracker;
use crate::schema::hits::dsl as hits; use crate::schema::hits;
use crate::schema::trackers; use crate::schema::trackers;
use crate::schema::trackers::dsl; use crate::schema::trackers::dsl;
use chrono::Utc; use chrono::Utc;
@@ -61,6 +62,30 @@ pub fn get(
} }
} }
#[get("/<id>/hits")]
pub fn get_hits(
id: &str,
_auth: Authenticated,
state: &State<AppState>,
) -> Result<Json<Vec<HitDTO>>, Status> {
let mut db = state.db.lock().unwrap();
let id = match Uuid::parse_str(id).ok() {
Some(id) => id,
None => return Err(Status::BadRequest),
};
let result = hits::dsl::hits
.filter(hits::tracker_id.eq(id))
.load(&mut *db)
.ok();
match result {
Some(results) => Ok(Json(results.iter().map(HitDTO::from).collect())),
None => Err(Status::NotFound),
}
}
#[post("/", format = "json", data = "<data>")] #[post("/", format = "json", data = "<data>")]
pub fn create( pub fn create(
data: Json<NewTrackerDTO>, data: Json<NewTrackerDTO>,
@@ -108,7 +133,7 @@ pub fn delete(
if delete_hits { if delete_hits {
let hit_count = let hit_count =
diesel::delete(hits::hits.filter(hits::tracker_id.eq(id))).execute(&mut *db); diesel::delete(hits::dsl::hits.filter(hits::tracker_id.eq(id))).execute(&mut *db);
if let Err(err) = hit_count { if let Err(err) = hit_count {
error!("Failed to delete associated hits: {}", err) error!("Failed to delete associated hits: {}", err)
} }

View File

@@ -67,6 +67,7 @@ fn rocket() -> _ {
routes![ routes![
tracker::index, tracker::index,
tracker::get, tracker::get,
tracker::get_hits,
tracker::create, tracker::create,
tracker::delete tracker::delete
], ],

View File

@@ -118,11 +118,44 @@
width: 15rem; width: 15rem;
} }
#tracker-table td, #tracker-table th { #tracker-table td:nth-child(4) {
width: 10rem;
}
#tracker-table td, #tracker-table th, #hit-table td, #hit-table th {
margin: 0; margin: 0;
padding: 0; padding: 0.2rem 0;
border-bottom: 1px solid black; border-bottom: 1px solid black;
} }
#hit-title {
font-size: 1.15rem;
width: 100%;
margin-top: 2rem;
margin-bottom: 0;
}
#hit-table {
width: 100%;
overflow: auto;
font-size: 1.10rem;
}
#hit-table th:nth-child(1) {
width: 20rem;
}
#hit-table th:nth-child(2) {
width: 10rem;
}
#hit-table th:nth-child(4) {
width: 8rem;
}
#hit-table th:nth-child(5) {
width: 15rem;
}
</style> </style>
</head> </head>
<body> <body>
@@ -141,7 +174,18 @@
<th>ID</th> <th>ID</th>
<th>Name</th> <th>Name</th>
<th>Created at</th> <th>Created at</th>
<th>Hits</th> <th></th>
</tr>
</table>
<p id="hit-title">No tracker selected</p>
<table id="hit-table">
<tr>
<th>ID</th>
<th>IP</th>
<th>Agent</th>
<th>Language</th>
<th>Created at</th>
</tr> </tr>
</table> </table>
@@ -184,21 +228,68 @@
} }
}).then((res) => { }).then((res) => {
res.json().then((trackers) => { res.json().then((trackers) => {
console.log(trackers);
trackers.forEach((tracker) => { trackers.forEach((tracker) => {
document.getElementById("tracker-table").innerHTML += ` document.getElementById("tracker-table").innerHTML += `
<tr> <tr>
<td>${tracker.id}</td> <td>${tracker.id}</td>
<td>${tracker.name}</td> <td>${tracker.name}</td>
<td>${tracker.created_at}</td> <td>${tracker.created_at}</td>
<td>${tracker.hits}</td> <td>
</tr> <button onclick="loadTrigger('${tracker.id}')">
`; Show more
}) </button>
<button onclick="copyLink('${tracker.id}')">
Copy link
</button>
</td>
</tr>`;
});
}).catch((err) => alert(`Couldn't unwrap json: ${err}`)) }).catch((err) => alert(`Couldn't unwrap json: ${err}`))
}).catch((err) => alert(`Couldn't fetch trackers: ${err}`)); }).catch((err) => alert(`Couldn't fetch trackers: ${err}`));
} }
function loadTrigger(id) {
const apiKey = localStorage.getItem("api-key");
if (!apiKey) {
return;
}
fetch(`http://localhost:8000/tracker/${id}/hits`, {
method: "GET",
headers: {
Authorization: apiKey,
}
}).then((res) => {
res.json().then((hits) => {
document.getElementById("hit-title").innerHTML = `${hits.length} hit(s) for tracker ${id}`;
document.getElementById("hit-table").innerHTML = `
<tr>
<th>ID</th>
<th>IP</th>
<th>Agent</th>
<th>Language</th>
<th>Created at</th>
</tr>`;
hits.forEach((hit) => {
document.getElementById("hit-table").innerHTML += `
<tr>
<td>${hit.id}</td>
<td>${hit.ip}</td>
<td>${hit.agent}</td>
<td>${hit.language}</td>
<td>${hit.created_at}</td>
</tr>`;
});
}).catch((err) => alert(`Couldn't unwrap json: ${err}`));
}).catch((err) => alert(`Couldn't fetch hits: ${err}`));
}
function copyLink(id) {
navigator.clipboard.writeText(`http://localhost:8000/image/${id}`).catch((err) => alert(`Couldn't copy: ${err}`));
}
init(); init();
</script> </script>
</body> </body>