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