Skip to content

Instantly share code, notes, and snippets.

@ckruse
Last active August 6, 2023 06:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ckruse/d09910083f06b764eb8203d3bc04af65 to your computer and use it in GitHub Desktop.
Save ckruse/d09910083f06b764eb8203d3bc04af65 to your computer and use it in GitHub Desktop.
pub async fn create_mention(
source_url: String,
target_url: String,
object_type: &str,
id: i32,
author: String,
title: String,
conn: &mut PgConnection,
) -> Result<Mention, sqlx::Error> {
let now = chrono::Utc::now().naive_utc();
let mut data = NewMention {
source_url,
target_url,
author,
title,
mention_type: "TODO:".to_owned(),
inserted_at: Some(now),
updated_at: Some(now),
..Default::default()
};
match object_type {
"note" => {
data.note_id = Some(id);
}
"picture" => {
data.picture_id = Some(id);
}
"article" => {
data.article_id = Some(id);
}
_ => {}
};
query_as!(
Mention,
r#"
INSERT INTO mentions (source_url, target_url, author, title, mention_type, inserted_at, updated_at, note_id, picture_id, article_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING *
"#,
data.source_url,
data.target_url,
data.author,
data.title,
data.mention_type,
data.inserted_at,
data.updated_at,
data.note_id,
data.picture_id,
data.article_id
)
.fetch_one(conn)
.await
}
error[E0277]: the trait bound `fn(axum::extract::State<AppState>, axum::Form<MentionValues>) -> impl Future<Output = Result<impl IntoResponse, AppError>> {receive_webmention}: Handler<_, _, _>` is not satisfied
--> src/webmentions.rs:19:36
|
19 | app.route("/webmentions", post(receive_webmention))
| ---- ^^^^^^^^^^^^^^^^^^ the trait `Handler<_, _, _>` is not implemented for fn item `fn(axum::extract::State<AppState>, axum::Form<MentionValues>) -> impl Future<Output = Result<impl IntoResponse, AppError>> {receive_webmention}`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Handler<T, S, B>`:
<MethodRouter<S, B> as Handler<(), S, B>>
<axum::handler::Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>
<axum_extra::handler::IntoHandler<H, T, S, B> as Handler<T, S, B>>
<axum_extra::handler::or::Or<L, R, Lt, Rt, S, B> as Handler<(M, Lt, Rt), S, B>>
note: required by a bound in `post`
--> /Users/ckruse/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.6.19/src/routing/method_routing.rs:407:1
|
407 | top_level_handler_fn!(post, POST);
| ^^^^^^^^^^^^^^^^^^^^^^----^^^^^^^
| | |
| | required by a bound in this function
| required by this bound in `post`
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
use axum::{
extract::{Form, State},
response::IntoResponse,
routing::post,
};
use serde::{Deserialize, Serialize};
use url::Url;
use visdom::{types::IAttrValue, Vis};
use self::actions::{create_mention, mention_exists, target_exists};
use crate::{errors::AppError, uri_helpers::root_uri, AppRouter, AppState};
pub mod actions;
pub mod send;
mod mail_sender;
pub fn configure(app: AppRouter) -> AppRouter {
app.route("/webmentions", post(receive_webmention))
}
#[derive(Deserialize, Serialize, Debug, Clone, Default)]
pub struct MentionValues {
pub source: String,
pub target: String,
}
pub async fn receive_webmention(
State(state): State<AppState>,
Form(values): Form<MentionValues>,
) -> Result<impl IntoResponse, AppError> {
let mut conn = state.pool.acquire().await?;
let root_url = Url::parse(&root_uri()).unwrap();
let source_url =
Url::parse(&values.source).map_err(|_| AppError::InternalError("source url invalid".to_owned()))?;
let target_url =
Url::parse(&values.target).map_err(|_| AppError::InternalError("target url invalid".to_owned()))?;
if target_url.host_str() != root_url.host_str() {
return Err(AppError::BadRequest("target url invalid".to_owned()));
}
let (object_type, id) = target_exists(&target_url, &mut conn)
.await
.unwrap_or_else(|| ("".to_owned(), 0));
let surl = source_url.to_string();
let body = reqwest::get(surl)
.await
.map_err(|e| AppError::InternalError(format!("request error: {}", e)))?
.text()
.await
.map_err(|e| AppError::InternalError(format!("request error: {}", e)))?;
if !body.contains(&target_url.to_string()) {
return Err(AppError::BadRequest("source url invalid".to_owned()));
}
let mention_exists = mention_exists(source_url.as_ref(), target_url.as_ref(), &mut conn).await;
if mention_exists {
return Ok("OK");
}
let tree = Vis::load(&body).map_err(|_| AppError::BadRequest("could not parse source document".to_owned()))?;
let title = tree.find("title").text();
let author = match tree.find("meta[name=author]").attr("content") {
Some(IAttrValue::Value(author, _)) => author,
_ => "unknown".to_owned(),
};
//
// commenting this out fixes the compile error
//
let mention = create_mention(
source_url.to_string(),
target_url.to_string(),
&object_type,
id,
author,
title,
&mut conn,
)
.await?;
if source_url.host() != root_url.host() {
tokio::task::spawn_blocking(move || mail_sender::send_mail(mention));
}
Ok("OK")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment