use url crate

This commit is contained in:
Greg Shuflin 2025-02-02 02:01:51 -08:00
parent 8f1a741411
commit 47de37d6cb
3 changed files with 26 additions and 13 deletions

1
Cargo.lock generated
View File

@ -3279,6 +3279,7 @@ dependencies = [
"form_urlencoded", "form_urlencoded",
"idna", "idna",
"percent-encoding", "percent-encoding",
"serde",
] ]
[[package]] [[package]]

View File

@ -14,4 +14,4 @@ rss = "2.0.11"
sqlx = { version = "0.7", features = ["runtime-tokio", "sqlite", "chrono", "uuid"] } sqlx = { version = "0.7", features = ["runtime-tokio", "sqlite", "chrono", "uuid"] }
uuid = { version = "1.7.0", features = ["v4", "serde"] } uuid = { version = "1.7.0", features = ["v4", "serde"] }
bcrypt = "0.15" bcrypt = "0.15"
url = "2.5.4" url = { version = "2.5", features = ["serde"] }

View File

@ -3,6 +3,7 @@ use rocket::http::Status;
use rocket::serde::{json::Json, Deserialize, Serialize}; use rocket::serde::{json::Json, Deserialize, Serialize};
use rocket_db_pools::Connection; use rocket_db_pools::Connection;
use uuid::Uuid; use uuid::Uuid;
use url::Url;
use crate::Db; use crate::Db;
use crate::user::AuthenticatedUser; use crate::user::AuthenticatedUser;
@ -12,14 +13,14 @@ use crate::user::AuthenticatedUser;
pub struct Feed { pub struct Feed {
feed_id: Uuid, feed_id: Uuid,
name: String, name: String,
url: String, url: Url,
user_id: Uuid, user_id: Uuid,
added_time: chrono::DateTime<chrono::Utc>, added_time: chrono::DateTime<chrono::Utc>,
last_checked_time: chrono::DateTime<chrono::Utc>, last_checked_time: chrono::DateTime<chrono::Utc>,
} }
impl Feed { impl Feed {
pub fn new(name: String, url: String, user_id: Uuid) -> Self { pub fn new(name: String, url: Url, user_id: Uuid) -> Self {
let now = chrono::Utc::now(); let now = chrono::Utc::now();
Feed { Feed {
feed_id: Uuid::new_v4(), feed_id: Uuid::new_v4(),
@ -36,7 +37,7 @@ impl Feed {
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
pub struct NewFeed { pub struct NewFeed {
pub name: String, pub name: String,
pub url: String, pub url: Url, // Changed from String to Url
} }
#[post("/feeds", data = "<new_feed>")] #[post("/feeds", data = "<new_feed>")]
@ -46,6 +47,12 @@ pub async fn create_feed(
user: AuthenticatedUser, user: AuthenticatedUser,
) -> Result<Json<Feed>, Status> { ) -> Result<Json<Feed>, Status> {
let new_feed = new_feed.into_inner(); let new_feed = new_feed.into_inner();
// URL validation only needs to check scheme now
if !new_feed.url.scheme().eq("http") && !new_feed.url.scheme().eq("https") {
return Err(Status::UnprocessableEntity);
}
let feed = Feed::new(new_feed.name, new_feed.url, user.user_id); let feed = Feed::new(new_feed.name, new_feed.url, user.user_id);
let query = sqlx::query( let query = sqlx::query(
@ -54,7 +61,7 @@ pub async fn create_feed(
) )
.bind(feed.feed_id.to_string()) .bind(feed.feed_id.to_string())
.bind(&feed.name) .bind(&feed.name)
.bind(&feed.url) .bind(feed.url.as_str())
.bind(feed.user_id.to_string()) .bind(feed.user_id.to_string())
.bind(feed.added_time.to_rfc3339()) .bind(feed.added_time.to_rfc3339())
.bind(feed.last_checked_time.to_rfc3339()) .bind(feed.last_checked_time.to_rfc3339())
@ -106,15 +113,20 @@ pub async fn list_feeds(
let feeds = query let feeds = query
.into_iter() .into_iter()
.map(|row| Feed { .map(|row| {
// Parse URL from string
let url = Url::parse(&row.url).map_err(|_| Status::InternalServerError)?;
Ok(Feed {
feed_id: Uuid::parse_str(&row.feed_id).unwrap(), feed_id: Uuid::parse_str(&row.feed_id).unwrap(),
name: row.name, name: row.name,
url: row.url, url,
user_id: Uuid::parse_str(&row.user_id).unwrap(), user_id: Uuid::parse_str(&row.user_id).unwrap(),
added_time: row.added_time, added_time: row.added_time,
last_checked_time: row.last_checked_time, last_checked_time: row.last_checked_time,
}) })
.collect(); })
.collect::<Result<Vec<_>, Status>>()?;
Ok(Json(feeds)) Ok(Json(feeds))
} }