small tweaks
This commit is contained in:
parent
9e6168b5e1
commit
ad4377b52c
@ -130,7 +130,7 @@ pub struct Signin {
|
||||
/// The model for the query parameters of the report request.
|
||||
#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct ReportQuery {
|
||||
pub grade: Option<i32>,
|
||||
pub detailed_event_view: bool,
|
||||
}
|
||||
|
||||
/// The model for the confirm attending request.
|
||||
@ -164,6 +164,20 @@ pub struct LeaderBoardEntry {
|
||||
pub username: String,
|
||||
pub points: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
sqlx::Type, Clone, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct ReportEntry {
|
||||
pub username: String,
|
||||
pub grade: i32,
|
||||
pub points: Option<i64>,
|
||||
pub event_titles: Vec<String>,
|
||||
pub event_points: Vec<i32>,
|
||||
pub event_discriptions: Vec<String>,
|
||||
pub event_types: Vec<String>,
|
||||
}
|
||||
|
||||
/// Module for (de)serializing [OffsetDateTime] to conform with the JWT spec (RFC 7519 section 2, "Numeric Date")
|
||||
mod serde_numeric_date {
|
||||
use serde::{self, Deserialize, Deserializer, Serializer};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
jwt::handle_token,
|
||||
models::{LeaderBoardEntry, ReportQuery, Role},
|
||||
models::{ReportEntry, ReportQuery, Role},
|
||||
AppState,
|
||||
};
|
||||
use axum::{
|
||||
@ -40,24 +40,24 @@ pub async fn get_report(
|
||||
};
|
||||
|
||||
let result = query_as!(
|
||||
LeaderBoardEntry,
|
||||
ReportEntry,
|
||||
r#"
|
||||
SELECT
|
||||
u.username,
|
||||
COALESCE(SUM(e.points), 0) AS points
|
||||
FROM
|
||||
users u
|
||||
u.grade,
|
||||
COALESCE(SUM(e.points), 0) AS points,
|
||||
array_agg(e.title) AS "event_titles!",
|
||||
array_agg(e.description) AS "event_discriptions!",
|
||||
array_agg(e.points) AS "event_points!",
|
||||
array_agg(e.event_type) AS "event_types!: Vec<String>"
|
||||
FROM users u
|
||||
LEFT JOIN event_attendees ea
|
||||
ON u.id = ea.user_id AND ea.confirmed = true
|
||||
LEFT JOIN events e
|
||||
ON ea.event_id = e.id
|
||||
WHERE
|
||||
u.grade = $1 OR $2
|
||||
GROUP BY u.id
|
||||
ORDER BY points
|
||||
ORDER BY u.grade, u.username, points
|
||||
"#,
|
||||
report_query.grade.unwrap_or(0),
|
||||
report_query.grade.is_none(),
|
||||
)
|
||||
.fetch_all(&app_state.db_pool)
|
||||
.await;
|
||||
@ -76,9 +76,10 @@ pub async fn get_report(
|
||||
};
|
||||
|
||||
let mut context = Context::new();
|
||||
context.insert("grade", &report_query.grade);
|
||||
context.insert("date", &Local::now().format("%Y-%m-%d").to_string());
|
||||
context.insert("users", &records);
|
||||
context.insert("detailed_event_view", &report_query.detailed_event_view);
|
||||
|
||||
let report = match TEMPLATES.render("report.html", &context) {
|
||||
Ok(report) => report,
|
||||
Err(err) => {
|
||||
|
||||
@ -199,7 +199,7 @@ pub async fn mark_claimed(
|
||||
|
||||
match result {
|
||||
Ok(record) => {
|
||||
if (record.rows_affected() == 0) {
|
||||
if record.rows_affected() == 0 {
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Json(json!({ "error": format!("winner_id not found") })),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Student Point Report Grade {{ grade }}</title>
|
||||
<title>Student Point Report</title>
|
||||
<style>
|
||||
/* color theme */
|
||||
:root {
|
||||
@ -15,12 +15,19 @@
|
||||
}
|
||||
/* table styling */
|
||||
table {
|
||||
font-family: Arial, sans-serif;
|
||||
color: var(--text-color);
|
||||
width: 100%;
|
||||
}
|
||||
.styled-table{
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
font-family: Arial, sans-serif;
|
||||
color: var(--text-color);
|
||||
}
|
||||
.inner-table{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
th, td {
|
||||
text-align: left;
|
||||
@ -30,7 +37,7 @@
|
||||
th {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
font-weight: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
/* header styling */
|
||||
header {
|
||||
@ -51,21 +58,48 @@
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Student Point Report Grade {{ grade }}</h1>
|
||||
<h1>Student Point Report</h1>
|
||||
<p style="margin: 0;">{{ date }}</p>
|
||||
</header>
|
||||
<table>
|
||||
<table class="styled-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Grade</th>
|
||||
<th>Points</th>
|
||||
{% if detailed_event_view %}
|
||||
<th>Events</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.grade }}</td>
|
||||
<td>{{ user.points }}</td>
|
||||
{% if detailed_event_view %}
|
||||
<td>
|
||||
<table class="inner-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Points</td>
|
||||
<th>Type</td>
|
||||
<th>Title</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for i in range(end=user.event_titles|length) %}
|
||||
<tr>
|
||||
<td>{{user.event_points[i]}}</td>
|
||||
<td>{{user.event_types[i]}}</td>
|
||||
<td>{{user.event_titles[i]}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user