Report errors to server

This commit is contained in:
jude 2023-06-20 13:13:26 +01:00
parent 9d8622f418
commit 1519474f93
10 changed files with 92 additions and 18 deletions

View File

@ -2,6 +2,7 @@ pub(crate) mod pager;
use std::io::Cursor; use std::io::Cursor;
use base64::{engine::general_purpose, Engine};
use chrono_tz::Tz; use chrono_tz::Tz;
use log::warn; use log::warn;
use poise::{ use poise::{
@ -51,11 +52,12 @@ impl ComponentDataModel {
pub fn to_custom_id(&self) -> String { pub fn to_custom_id(&self) -> String {
let mut buf = Vec::new(); let mut buf = Vec::new();
self.serialize(&mut Serializer::new(&mut buf)).unwrap(); self.serialize(&mut Serializer::new(&mut buf)).unwrap();
base64::encode(buf) general_purpose::STANDARD.encode(buf)
} }
pub fn from_custom_id(data: &String) -> Self { pub fn from_custom_id(data: &String) -> Self {
let buf = base64::decode(data) let buf = general_purpose::STANDARD
.decode(data)
.map_err(|e| format!("Could not decode `custom_id' {}: {:?}", data, e)) .map_err(|e| format!("Could not decode `custom_id' {}: {:?}", data, e))
.unwrap(); .unwrap();
let cur = Cursor::new(buf); let cur = Cursor::new(buf);

View File

@ -116,7 +116,8 @@ pub async fn initialize(
routes::cookies, routes::cookies,
routes::privacy, routes::privacy,
routes::terms, routes::terms,
routes::return_to_same_site routes::return_to_same_site,
routes::report::report_error,
], ],
) )
.mount( .mount(

View File

@ -10,9 +10,12 @@ use serenity::{
}; };
use sqlx::{MySql, Pool}; use sqlx::{MySql, Pool};
use crate::routes::dashboard::{ use crate::routes::{
create_reminder, generate_uid, ImportBody, JsonResult, Reminder, ReminderCsv, dashboard::{
ReminderTemplateCsv, TodoCsv, create_reminder, generate_uid, ImportBody, Reminder, ReminderCsv, ReminderTemplateCsv,
TodoCsv,
},
JsonResult,
}; };
#[get("/api/guild/<id>/export/reminders")] #[get("/api/guild/<id>/export/reminders")]

View File

@ -23,9 +23,12 @@ use crate::{
MAX_EMBED_FOOTER_LENGTH, MAX_EMBED_TITLE_LENGTH, MAX_URL_LENGTH, MAX_USERNAME_LENGTH, MAX_EMBED_FOOTER_LENGTH, MAX_EMBED_TITLE_LENGTH, MAX_URL_LENGTH, MAX_USERNAME_LENGTH,
MIN_INTERVAL, MIN_INTERVAL,
}, },
routes::dashboard::{ routes::{
create_database_channel, create_reminder, template_name_default, DeleteReminder, dashboard::{
DeleteReminderTemplate, JsonResult, PatchReminder, Reminder, ReminderTemplate, create_database_channel, create_reminder, template_name_default, DeleteReminder,
DeleteReminderTemplate, PatchReminder, Reminder, ReminderTemplate,
},
JsonResult,
}, },
}; };

View File

@ -2,11 +2,7 @@ use std::collections::HashMap;
use chrono::{naive::NaiveDateTime, Utc}; use chrono::{naive::NaiveDateTime, Utc};
use rand::{rngs::OsRng, seq::IteratorRandom}; use rand::{rngs::OsRng, seq::IteratorRandom};
use rocket::{ use rocket::{http::CookieJar, response::Redirect, serde::json::json};
http::CookieJar,
response::Redirect,
serde::json::{json, Value as JsonValue},
};
use rocket_dyn_templates::Template; use rocket_dyn_templates::Template;
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
use serenity::{ use serenity::{
@ -24,6 +20,7 @@ use crate::{
MAX_EMBED_FIELD_VALUE_LENGTH, MAX_EMBED_FOOTER_LENGTH, MAX_EMBED_TITLE_LENGTH, MAX_EMBED_FIELD_VALUE_LENGTH, MAX_EMBED_FOOTER_LENGTH, MAX_EMBED_TITLE_LENGTH,
MAX_URL_LENGTH, MAX_USERNAME_LENGTH, MIN_INTERVAL, MAX_URL_LENGTH, MAX_USERNAME_LENGTH, MIN_INTERVAL,
}, },
routes::JsonResult,
Database, Error, Database, Error,
}; };
@ -31,7 +28,6 @@ pub mod export;
pub mod guild; pub mod guild;
pub mod user; pub mod user;
pub type JsonResult = Result<JsonValue, JsonValue>;
type Unset<T> = Option<T>; type Unset<T> = Option<T>;
fn name_default() -> String { fn name_default() -> String {

View File

@ -1,11 +1,14 @@
pub mod dashboard; pub mod dashboard;
pub mod login; pub mod login;
pub mod report;
use std::collections::HashMap; use std::collections::HashMap;
use rocket::request::FlashMessage; use rocket::{request::FlashMessage, serde::json::Value as JsonValue};
use rocket_dyn_templates::Template; use rocket_dyn_templates::Template;
pub type JsonResult = Result<JsonValue, JsonValue>;
#[get("/")] #[get("/")]
pub async fn index(flash: Option<FlashMessage<'_>>) -> Template { pub async fn index(flash: Option<FlashMessage<'_>>) -> Template {
let mut map: HashMap<&str, String> = HashMap::new(); let mut map: HashMap<&str, String> = HashMap::new();

48
web/src/routes/report.rs Normal file
View File

@ -0,0 +1,48 @@
use rocket::{
http::CookieJar,
serde::{
json::{json, Json},
Deserialize,
},
};
use crate::routes::JsonResult;
#[derive(Deserialize)]
pub struct ClientError {
#[serde(rename = "reporterId")]
reporter_id: String,
url: String,
#[serde(rename = "relativeTimestamp")]
relative_timestamp: i64,
#[serde(rename = "errorMessage")]
error_message: String,
#[serde(rename = "errorLine")]
error_line: u64,
#[serde(rename = "errorFile")]
error_file: String,
#[serde(rename = "errorType")]
error_type: String,
}
#[post("/report", data = "<client_error>")]
pub async fn report_error(cookies: &CookieJar<'_>, client_error: Json<ClientError>) -> JsonResult {
if let Some(user_id) = cookies.get_private("userid") {
error!(
"User {} reports a client-side error.
{}, {}:{} at {}ms
{}: {}
Chain: {}",
user_id,
client_error.url,
client_error.error_file,
client_error.error_line,
client_error.relative_timestamp,
client_error.error_type,
client_error.error_message,
client_error.reporter_id
);
}
Ok(json!({}))
}

View File

@ -3,12 +3,12 @@
"short_name": "", "short_name": "",
"icons": [ "icons": [
{ {
"src": "/android-chrome-192x192.png", "src": "/static/favicon/android-chrome-192x192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "/android-chrome-512x512.png", "src": "/static/favicon/android-chrome-512x512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png" "type": "image/png"
} }

16
web/static/js/reporter.js Normal file
View File

@ -0,0 +1,16 @@
const REPORTER_ID = crypto.randomUUID();
window.addEventListener("error", async (ev) => {
await fetch("/report", {
method: "POST",
body: JSON.stringify({
reporterId: REPORTER_ID,
url: window.location.href,
relativeTimestamp: ev.timeStamp,
errorMessage: ev.message,
errorLine: ev.lineno,
errorFile: ev.filename,
errorType: ev.type,
}),
});
});

View File

@ -1,6 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="EN"> <html lang="EN">
<head> <head>
<script src="/static/js/reporter.js" type="application/javascript"></script>
<meta name="description" content="The most powerful Discord Reminders Bot"> <meta name="description" content="The most powerful Discord Reminders Bot">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8"> <meta charset="UTF-8">