Drone improvements, reply for Sentry feedback.
This commit is contained in:
parent
9e25205405
commit
1404d09436
|
@ -14,7 +14,9 @@ steps:
|
|||
- apt-get update -y
|
||||
- apt-get install pkg-config libssl-dev ca-certificates python3 python3-pip nodejs -y
|
||||
- pip3 install cfscrape
|
||||
- rustup component add clippy
|
||||
- cargo test
|
||||
- cargo clippy
|
||||
|
||||
- name: sentry-release
|
||||
image: getsentry/sentry-cli
|
||||
|
@ -35,6 +37,8 @@ steps:
|
|||
image: plugins/docker
|
||||
settings:
|
||||
auto_tag: true
|
||||
build_args_from_env:
|
||||
- DRONE_COMMIT_SHA
|
||||
password:
|
||||
from_secret: docker_password
|
||||
registry: registry.huefox.com
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
FROM rustlang/rust:nightly-slim AS builder
|
||||
WORKDIR /src
|
||||
RUN apt-get update -y && apt-get install pkg-config libssl-dev python3 python3-dev -y
|
||||
ARG DRONE_COMMIT_SHA
|
||||
ENV RELEASE $DRONE_COMMIT_SHA
|
||||
COPY . .
|
||||
RUN cargo install --root / --path .
|
||||
|
||||
|
|
|
@ -62,5 +62,6 @@ alternate-distance = · { $link } (distance of { $distance })
|
|||
alternate-multiple-photo = I can only find alternates for a single photo, sorry.
|
||||
|
||||
# Error Messages
|
||||
error-generic = Oh no, something went wrong! Please send a message to my creator { -creatorName } if you continue having issues.
|
||||
error-uuid = Oh no, something went wrong! Please send a message to my creator { -creatorName } with this ID if you continue having issues: { $uuid }
|
||||
error-generic = Oh no, something went wrong! Please send a message to my creator, { -creatorName }, saying what happened.
|
||||
error-uuid = Oh no, something went wrong! Please reply to this message saying what happened. You may also send a message to my creator, { -creatorName }, with this ID if you continue having issues: { $uuid }
|
||||
error-feedback = Thank you for the feedback, hopefully we can get this issue resolved soon.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit dc628de3342203b71cdedd4ff3c8a86eb7acefa4
|
|
@ -1,4 +1,5 @@
|
|||
use super::Status::*;
|
||||
use crate::needs_field;
|
||||
use async_trait::async_trait;
|
||||
use telegram::*;
|
||||
|
||||
|
@ -16,15 +17,13 @@ impl super::Handler for ChosenInlineHandler {
|
|||
update: &Update,
|
||||
_command: Option<&Command>,
|
||||
) -> Result<super::Status, failure::Error> {
|
||||
Ok(if let Some(chosen_result) = &update.chosen_inline_result {
|
||||
let point = influxdb::Query::write_query(influxdb::Timestamp::Now, "chosen")
|
||||
.add_field("user_id", chosen_result.from.id);
|
||||
let chosen_result = needs_field!(update, chosen_inline_result);
|
||||
|
||||
let _ = handler.influx.query(&point).await;
|
||||
let point = influxdb::Query::write_query(influxdb::Timestamp::Now, "chosen")
|
||||
.add_field("user_id", chosen_result.from.id);
|
||||
|
||||
Completed
|
||||
} else {
|
||||
Ignored
|
||||
})
|
||||
let _ = handler.influx.query(&point).await;
|
||||
|
||||
Ok(Completed)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ impl super::Handler for CommandHandler {
|
|||
"/mirror" => self.handle_mirror(&handler, message).await,
|
||||
"/source" => self.handle_source(&handler, message).await,
|
||||
"/alts" => self.handle_alts(&handler, message).await,
|
||||
"/error" => Err(failure::format_err!("a test error message")),
|
||||
_ => {
|
||||
tracing::info!("unknown command: {}", command.name);
|
||||
Ok(())
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
use super::Status::*;
|
||||
use crate::needs_field;
|
||||
use async_trait::async_trait;
|
||||
use telegram::*;
|
||||
|
||||
pub struct ErrorReplyHandler {
|
||||
client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl ErrorReplyHandler {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
client: reqwest::Client::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl super::Handler for ErrorReplyHandler {
|
||||
fn name(&self) -> &'static str {
|
||||
"error_reply"
|
||||
}
|
||||
|
||||
async fn handle(
|
||||
&self,
|
||||
handler: &crate::MessageHandler,
|
||||
update: &Update,
|
||||
_command: Option<&Command>,
|
||||
) -> Result<super::Status, failure::Error> {
|
||||
let message = needs_field!(update, message);
|
||||
let text = needs_field!(message, text);
|
||||
let reply_message = needs_field!(message, reply_to_message);
|
||||
let reply_message_from = needs_field!(reply_message, from);
|
||||
let reply_message_text = needs_field!(reply_message, text);
|
||||
let entities = needs_field!(reply_message, entities);
|
||||
|
||||
// Only want to look at messages that are replies to this bot
|
||||
if reply_message_from.id != handler.bot_user.id {
|
||||
return Ok(Ignored);
|
||||
}
|
||||
|
||||
let code = match get_code_block(&entities, &reply_message_text) {
|
||||
Some(code) => code,
|
||||
_ => return Ok(Ignored),
|
||||
};
|
||||
|
||||
let dsn = match &handler.config.sentry_dsn {
|
||||
Some(dsn) => dsn,
|
||||
_ => return Ok(Completed),
|
||||
};
|
||||
|
||||
let auth = format!("DSN {}", dsn);
|
||||
|
||||
let data = SentryFeedback {
|
||||
comments: text.to_string(),
|
||||
event_id: code,
|
||||
// This field is required, but Telegram doesn't give us emails...
|
||||
email: "telegram-user@example.com".to_string(),
|
||||
name: message
|
||||
.from
|
||||
.as_ref()
|
||||
.map(|from| from.username.clone().unwrap_or_else(|| from.id.to_string())),
|
||||
};
|
||||
|
||||
self.client
|
||||
.post(&format!(
|
||||
"https://sentry.io/api/0/projects/{}/{}/user-feedback/",
|
||||
handler.config.sentry_organization_slug.as_ref().unwrap(),
|
||||
handler.config.sentry_project_slug.as_ref().unwrap()
|
||||
))
|
||||
.json(&data)
|
||||
.header(reqwest::header::AUTHORIZATION, auth)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
handler
|
||||
.send_generic_reply(&message, "error-feedback")
|
||||
.await?;
|
||||
|
||||
Ok(Completed)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct SentryFeedback {
|
||||
comments: String,
|
||||
event_id: String,
|
||||
name: Option<String>,
|
||||
email: String,
|
||||
}
|
||||
|
||||
fn get_code_block(entities: &[MessageEntity], text: &str) -> Option<String> {
|
||||
// Find any code blocks, ignore if there's more than one
|
||||
let code_blocks = entities
|
||||
.iter()
|
||||
.filter(|entity| entity.entity_type == MessageEntityType::Code)
|
||||
.collect::<Vec<_>>();
|
||||
if code_blocks.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Make sure the code block is the correct length
|
||||
let entity = code_blocks[0];
|
||||
if entity.length != 36 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Iterate the text of the message this is replying to in order to
|
||||
// get the event ID
|
||||
let code = text
|
||||
.chars()
|
||||
.skip(entity.offset as usize)
|
||||
.take(entity.length as usize)
|
||||
.filter(|c| *c != '-')
|
||||
.collect();
|
||||
|
||||
Some(code)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_get_code_block() {
|
||||
let entities = vec![telegram::MessageEntity {
|
||||
entity_type: telegram::MessageEntityType::Code,
|
||||
offset: 0,
|
||||
length: 36,
|
||||
url: None,
|
||||
user: None,
|
||||
}];
|
||||
let text = "e52569fa-99a0-44fc-ae9d-2477177b550b";
|
||||
|
||||
assert_eq!(
|
||||
Some("e52569fa99a044fcae9d2477177b550b".to_string()),
|
||||
super::get_code_block(&entities, &text)
|
||||
);
|
||||
|
||||
let entities = vec![];
|
||||
assert_eq!(None, super::get_code_block(&entities, text));
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ use async_trait::async_trait;
|
|||
mod channel_photo;
|
||||
mod chosen_inline_handler;
|
||||
mod commands;
|
||||
mod error_reply;
|
||||
mod group_add;
|
||||
mod inline_handler;
|
||||
mod photo;
|
||||
|
@ -11,6 +12,7 @@ mod text;
|
|||
pub use channel_photo::ChannelPhotoHandler;
|
||||
pub use chosen_inline_handler::ChosenInlineHandler;
|
||||
pub use commands::CommandHandler;
|
||||
pub use error_reply::ErrorReplyHandler;
|
||||
pub use group_add::GroupAddHandler;
|
||||
pub use inline_handler::InlineHandler;
|
||||
pub use photo::PhotoHandler;
|
||||
|
|
25
src/main.rs
25
src/main.rs
|
@ -67,7 +67,9 @@ pub struct Config {
|
|||
|
||||
// Logging
|
||||
jaeger_collector: Option<String>,
|
||||
sentry_dsn: Option<String>,
|
||||
pub sentry_dsn: Option<String>,
|
||||
pub sentry_organization_slug: Option<String>,
|
||||
pub sentry_project_slug: Option<String>,
|
||||
|
||||
// Telegram config
|
||||
telegram_apitoken: String,
|
||||
|
@ -236,6 +238,7 @@ async fn main() {
|
|||
Box::new(handlers::PhotoHandler),
|
||||
Box::new(handlers::CommandHandler),
|
||||
Box::new(handlers::TextHandler),
|
||||
Box::new(handlers::ErrorReplyHandler::new()),
|
||||
];
|
||||
|
||||
let handler = Arc::new(MessageHandler {
|
||||
|
@ -256,7 +259,11 @@ async fn main() {
|
|||
|
||||
let _guard = if let Some(dsn) = config.sentry_dsn {
|
||||
sentry::integrations::panic::register_panic_handler();
|
||||
Some(sentry::init(dsn))
|
||||
Some(sentry::init(sentry::ClientOptions {
|
||||
dsn: Some(dsn.parse().unwrap()),
|
||||
release: option_env!("RELEASE").map(std::borrow::Cow::from),
|
||||
..Default::default()
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -432,7 +439,6 @@ pub struct MessageHandler {
|
|||
}
|
||||
|
||||
impl MessageHandler {
|
||||
#[tracing::instrument(skip(self, callback))]
|
||||
async fn get_fluent_bundle<C, R>(&self, requested: Option<&str>, callback: C) -> R
|
||||
where
|
||||
C: FnOnce(&fluent::FluentBundle<fluent::FluentResource>) -> R,
|
||||
|
@ -643,14 +649,23 @@ impl MessageHandler {
|
|||
Ok(status) if status == handlers::Status::Completed => break,
|
||||
Err(e) => {
|
||||
log::error!("Error handling update: {:#?}", e);
|
||||
|
||||
let mut tags = vec![("handler", handler.name().to_string())];
|
||||
if let Some(user) = user {
|
||||
tags.push(("user_id", user.id.to_string()));
|
||||
}
|
||||
if let Some(command) = command {
|
||||
tags.push(("command", command.name));
|
||||
}
|
||||
|
||||
utils::with_user_scope(user, Some(tags), || {
|
||||
if let Some(msg) = &update.message {
|
||||
self.report_error(&msg, Some(tags), || capture_error(&e))
|
||||
.await;
|
||||
} else {
|
||||
capture_error(&e);
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue