Report errors to server
This commit is contained in:
parent
9d8622f418
commit
1519474f93
@ -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);
|
||||||
|
@ -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(
|
||||||
|
@ -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")]
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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
48
web/src/routes/report.rs
Normal 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!({}))
|
||||||
|
}
|
@ -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
16
web/static/js/reporter.js
Normal 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,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
@ -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">
|
||||||
|
Loading…
Reference in New Issue
Block a user