Merge branch 'main' into timeline-cli
This commit is contained in:
@@ -10,31 +10,31 @@ bcrypt = "0.12.1"
|
||||
guid-create = "0.2"
|
||||
itertools = "0.10.3"
|
||||
lazy_static = "1.0"
|
||||
ldap3 = "0.10.5"
|
||||
ldap3 = "0.11.1"
|
||||
migrations_internals= "1.4.0"
|
||||
openssl = "0.10.40"
|
||||
rocket = "0.4.11"
|
||||
rocket_i18n = "0.4.1"
|
||||
reqwest = "0.11.11"
|
||||
scheduled-thread-pool = "0.2.6"
|
||||
serde = "1.0"
|
||||
serde = "1.0.137"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0.81"
|
||||
tantivy = "0.13.3"
|
||||
url = "2.1"
|
||||
walkdir = "2.2"
|
||||
webfinger = "0.4.1"
|
||||
whatlang = "0.16.0"
|
||||
whatlang = "0.16.2"
|
||||
shrinkwraprs = "0.3.0"
|
||||
diesel-derive-newtype = "1.0.0"
|
||||
glob = "0.3.0"
|
||||
glob = "0.3.1"
|
||||
lindera-tantivy = { version = "0.7.1", optional = true }
|
||||
tracing = "0.1.35"
|
||||
riker = "0.4.2"
|
||||
once_cell = "1.12.0"
|
||||
lettre = "0.9.6"
|
||||
native-tls = "0.2.10"
|
||||
activitystreams = "0.7.0-alpha.18"
|
||||
activitystreams = "=0.7.0-alpha.20"
|
||||
|
||||
[dependencies.chrono]
|
||||
features = ["serde"]
|
||||
|
||||
@@ -103,7 +103,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for ApiToken {
|
||||
let conn = request
|
||||
.guard::<DbConn>()
|
||||
.map_failure(|_| (Status::InternalServerError, TokenError::DbError))?;
|
||||
if let Ok(token) = ApiToken::find_by_value(&*conn, val) {
|
||||
if let Ok(token) = ApiToken::find_by_value(&conn, val) {
|
||||
return Outcome::Success(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,12 +126,9 @@ pub(crate) mod tests {
|
||||
.id,
|
||||
various[1].id
|
||||
);
|
||||
assert_eq!(
|
||||
BlocklistedEmail::matches_blocklist(&conn, no_match)
|
||||
.unwrap()
|
||||
.is_none(),
|
||||
true
|
||||
);
|
||||
assert!(BlocklistedEmail::matches_blocklist(&conn, no_match)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
+61
-53
@@ -18,10 +18,13 @@ use openssl::{
|
||||
rsa::Rsa,
|
||||
sign::{Signer, Verifier},
|
||||
};
|
||||
use plume_common::activity_pub::{
|
||||
inbox::{AsActor, FromId},
|
||||
sign, ActivityStream, ApSignature, CustomGroup, Id, IntoId, PublicKey, Source, SourceProperty,
|
||||
ToAsString, ToAsUri,
|
||||
use plume_common::{
|
||||
activity_pub::{
|
||||
inbox::{AsActor, FromId},
|
||||
sign, ActivityStream, ApSignature, CustomGroup, Id, IntoId, PublicKey, Source,
|
||||
SourceProperty, ToAsString, ToAsUri,
|
||||
},
|
||||
utils::iri_percent_encode_seg,
|
||||
};
|
||||
use webfinger::*;
|
||||
|
||||
@@ -83,9 +86,13 @@ impl Blog {
|
||||
|
||||
if inserted.fqn.is_empty() {
|
||||
if instance.local {
|
||||
inserted.fqn = inserted.actor_id.clone();
|
||||
inserted.fqn = iri_percent_encode_seg(&inserted.actor_id);
|
||||
} else {
|
||||
inserted.fqn = format!("{}@{}", inserted.actor_id, instance.public_domain);
|
||||
inserted.fqn = format!(
|
||||
"{}@{}",
|
||||
iri_percent_encode_seg(&inserted.actor_id),
|
||||
instance.public_domain
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +173,7 @@ impl Blog {
|
||||
|
||||
pub fn to_activity(&self, conn: &Connection) -> Result<CustomGroup> {
|
||||
let mut blog = ApActor::new(self.inbox_url.parse()?, Group::new());
|
||||
blog.set_preferred_username(self.actor_id.clone());
|
||||
blog.set_preferred_username(iri_percent_encode_seg(&self.actor_id));
|
||||
blog.set_name(self.title.clone());
|
||||
blog.set_outbox(self.outbox_url.parse()?);
|
||||
blog.set_summary(self.summary_html.to_string());
|
||||
@@ -381,6 +388,7 @@ impl FromId<Connection> for Blog {
|
||||
.ok_or(Error::MissingApProperty)?
|
||||
.to_string();
|
||||
if name.contains(&['<', '>', '&', '@', '\'', '"', ' ', '\t'][..]) {
|
||||
tracing::error!("preferredUsername includes invalid character(s): {}", &name);
|
||||
return Err(Error::InvalidValue);
|
||||
}
|
||||
(
|
||||
@@ -660,7 +668,7 @@ pub(crate) mod tests {
|
||||
.unwrap()
|
||||
.id,
|
||||
);
|
||||
let _: Blog = blog1.save_changes(&*conn).unwrap();
|
||||
let _: Blog = blog1.save_changes(conn).unwrap();
|
||||
|
||||
(users, vec![blog1, blog2, blog3])
|
||||
}
|
||||
@@ -669,10 +677,10 @@ pub(crate) mod tests {
|
||||
fn get_instance() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
fill_database(&conn);
|
||||
fill_database(conn);
|
||||
|
||||
let blog = Blog::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlog::new_local(
|
||||
"SomeName".to_owned(),
|
||||
"Some name".to_owned(),
|
||||
@@ -684,7 +692,7 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
blog.get_instance(&conn).unwrap().id,
|
||||
blog.get_instance(conn).unwrap().id,
|
||||
Instance::get_local().unwrap().id
|
||||
);
|
||||
// TODO add tests for remote instance
|
||||
@@ -696,10 +704,10 @@ pub(crate) mod tests {
|
||||
fn authors() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (user, _) = fill_database(&conn);
|
||||
let (user, _) = fill_database(conn);
|
||||
|
||||
let b1 = Blog::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlog::new_local(
|
||||
"SomeName".to_owned(),
|
||||
"Some name".to_owned(),
|
||||
@@ -710,7 +718,7 @@ pub(crate) mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
let b2 = Blog::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlog::new_local(
|
||||
"Blog".to_owned(),
|
||||
"Blog".to_owned(),
|
||||
@@ -723,7 +731,7 @@ pub(crate) mod tests {
|
||||
let blog = vec![b1, b2];
|
||||
|
||||
BlogAuthor::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlogAuthor {
|
||||
blog_id: blog[0].id,
|
||||
author_id: user[0].id,
|
||||
@@ -733,7 +741,7 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
|
||||
BlogAuthor::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlogAuthor {
|
||||
blog_id: blog[0].id,
|
||||
author_id: user[1].id,
|
||||
@@ -743,7 +751,7 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
|
||||
BlogAuthor::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlogAuthor {
|
||||
blog_id: blog[1].id,
|
||||
author_id: user[0].id,
|
||||
@@ -753,39 +761,39 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert!(blog[0]
|
||||
.list_authors(&conn)
|
||||
.list_authors(conn)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|a| a.id == user[0].id));
|
||||
assert!(blog[0]
|
||||
.list_authors(&conn)
|
||||
.list_authors(conn)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|a| a.id == user[1].id));
|
||||
assert!(blog[1]
|
||||
.list_authors(&conn)
|
||||
.list_authors(conn)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|a| a.id == user[0].id));
|
||||
assert!(!blog[1]
|
||||
.list_authors(&conn)
|
||||
.list_authors(conn)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|a| a.id == user[1].id));
|
||||
|
||||
assert!(Blog::find_for_author(&conn, &user[0])
|
||||
assert!(Blog::find_for_author(conn, &user[0])
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|b| b.id == blog[0].id));
|
||||
assert!(Blog::find_for_author(&conn, &user[1])
|
||||
assert!(Blog::find_for_author(conn, &user[1])
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|b| b.id == blog[0].id));
|
||||
assert!(Blog::find_for_author(&conn, &user[0])
|
||||
assert!(Blog::find_for_author(conn, &user[0])
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|b| b.id == blog[1].id));
|
||||
assert!(!Blog::find_for_author(&conn, &user[1])
|
||||
assert!(!Blog::find_for_author(conn, &user[1])
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|b| b.id == blog[1].id));
|
||||
@@ -797,10 +805,10 @@ pub(crate) mod tests {
|
||||
fn find_local() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
fill_database(&conn);
|
||||
fill_database(conn);
|
||||
|
||||
let blog = Blog::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlog::new_local(
|
||||
"SomeName".to_owned(),
|
||||
"Some name".to_owned(),
|
||||
@@ -811,7 +819,7 @@ pub(crate) mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(Blog::find_by_fqn(&conn, "SomeName").unwrap().id, blog.id);
|
||||
assert_eq!(Blog::find_by_fqn(conn, "SomeName").unwrap().id, blog.id);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@@ -820,10 +828,10 @@ pub(crate) mod tests {
|
||||
fn get_fqn() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
fill_database(&conn);
|
||||
fill_database(conn);
|
||||
|
||||
let blog = Blog::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlog::new_local(
|
||||
"SomeName".to_owned(),
|
||||
"Some name".to_owned(),
|
||||
@@ -843,10 +851,10 @@ pub(crate) mod tests {
|
||||
fn delete() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (_, blogs) = fill_database(&conn);
|
||||
let (_, blogs) = fill_database(conn);
|
||||
|
||||
blogs[0].delete(&conn).unwrap();
|
||||
assert!(Blog::get(&conn, blogs[0].id).is_err());
|
||||
blogs[0].delete(conn).unwrap();
|
||||
assert!(Blog::get(conn, blogs[0].id).is_err());
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@@ -855,10 +863,10 @@ pub(crate) mod tests {
|
||||
fn delete_via_user() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (user, _) = fill_database(&conn);
|
||||
let (user, _) = fill_database(conn);
|
||||
|
||||
let b1 = Blog::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlog::new_local(
|
||||
"SomeName".to_owned(),
|
||||
"Some name".to_owned(),
|
||||
@@ -869,7 +877,7 @@ pub(crate) mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
let b2 = Blog::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlog::new_local(
|
||||
"Blog".to_owned(),
|
||||
"Blog".to_owned(),
|
||||
@@ -882,7 +890,7 @@ pub(crate) mod tests {
|
||||
let blog = vec![b1, b2];
|
||||
|
||||
BlogAuthor::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlogAuthor {
|
||||
blog_id: blog[0].id,
|
||||
author_id: user[0].id,
|
||||
@@ -892,7 +900,7 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
|
||||
BlogAuthor::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlogAuthor {
|
||||
blog_id: blog[0].id,
|
||||
author_id: user[1].id,
|
||||
@@ -902,7 +910,7 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
|
||||
BlogAuthor::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewBlogAuthor {
|
||||
blog_id: blog[1].id,
|
||||
author_id: user[0].id,
|
||||
@@ -911,11 +919,11 @@ pub(crate) mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
user[0].delete(&conn).unwrap();
|
||||
assert!(Blog::get(&conn, blog[0].id).is_ok());
|
||||
assert!(Blog::get(&conn, blog[1].id).is_err());
|
||||
user[1].delete(&conn).unwrap();
|
||||
assert!(Blog::get(&conn, blog[0].id).is_err());
|
||||
user[0].delete(conn).unwrap();
|
||||
assert!(Blog::get(conn, blog[0].id).is_ok());
|
||||
assert!(Blog::get(conn, blog[1].id).is_err());
|
||||
user[1].delete(conn).unwrap();
|
||||
assert!(Blog::get(conn, blog[0].id).is_err());
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@@ -924,10 +932,10 @@ pub(crate) mod tests {
|
||||
fn self_federation() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (users, mut blogs) = fill_database(&conn);
|
||||
let (users, mut blogs) = fill_database(conn);
|
||||
blogs[0].icon_id = Some(
|
||||
Media::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewMedia {
|
||||
file_path: "aaa.png".into(),
|
||||
alt_text: String::new(),
|
||||
@@ -943,7 +951,7 @@ pub(crate) mod tests {
|
||||
);
|
||||
blogs[0].banner_id = Some(
|
||||
Media::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewMedia {
|
||||
file_path: "bbb.png".into(),
|
||||
alt_text: String::new(),
|
||||
@@ -958,9 +966,9 @@ pub(crate) mod tests {
|
||||
.id,
|
||||
);
|
||||
let _: Blog = blogs[0].save_changes(&**conn).unwrap();
|
||||
let ap_repr = blogs[0].to_activity(&conn).unwrap();
|
||||
blogs[0].delete(&conn).unwrap();
|
||||
let blog = Blog::from_activity(&conn, ap_repr).unwrap();
|
||||
let ap_repr = blogs[0].to_activity(conn).unwrap();
|
||||
blogs[0].delete(conn).unwrap();
|
||||
let blog = Blog::from_activity(conn, ap_repr).unwrap();
|
||||
|
||||
assert_eq!(blog.actor_id, blogs[0].actor_id);
|
||||
assert_eq!(blog.title, blogs[0].title);
|
||||
@@ -972,8 +980,8 @@ pub(crate) mod tests {
|
||||
assert_eq!(blog.public_key, blogs[0].public_key);
|
||||
assert_eq!(blog.fqn, blogs[0].fqn);
|
||||
assert_eq!(blog.summary_html, blogs[0].summary_html);
|
||||
assert_eq!(blog.icon_url(&conn), blogs[0].icon_url(&conn));
|
||||
assert_eq!(blog.banner_url(&conn), blogs[0].banner_url(&conn));
|
||||
assert_eq!(blog.icon_url(conn), blogs[0].icon_url(conn));
|
||||
assert_eq!(blog.banner_url(conn), blogs[0].banner_url(conn));
|
||||
|
||||
Ok(())
|
||||
})
|
||||
@@ -983,7 +991,7 @@ pub(crate) mod tests {
|
||||
fn to_activity() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, Error, _>(|| {
|
||||
let (_users, blogs) = fill_database(&conn);
|
||||
let (_users, blogs) = fill_database(conn);
|
||||
let blog = &blogs[0];
|
||||
let act = blog.to_activity(conn)?;
|
||||
|
||||
|
||||
@@ -430,7 +430,7 @@ mod tests {
|
||||
use serde_json::{json, to_value};
|
||||
|
||||
fn prepare_activity(conn: &DbConn) -> (Comment, Vec<Post>, Vec<User>, Vec<Blog>) {
|
||||
let (posts, users, blogs) = fill_database(&conn);
|
||||
let (posts, users, blogs) = fill_database(conn);
|
||||
|
||||
let comment = Comment::insert(
|
||||
conn,
|
||||
@@ -456,8 +456,8 @@ mod tests {
|
||||
fn self_federation() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (original_comm, posts, users, _blogs) = prepare_activity(&conn);
|
||||
let act = original_comm.create_activity(&conn).unwrap();
|
||||
let (original_comm, posts, users, _blogs) = prepare_activity(conn);
|
||||
let act = original_comm.create_activity(conn).unwrap();
|
||||
|
||||
assert_json_eq!(to_value(&act).unwrap(), json!({
|
||||
"actor": "https://plu.me/@/admin/",
|
||||
@@ -499,7 +499,7 @@ mod tests {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let reply_act = reply.create_activity(&conn).unwrap();
|
||||
let reply_act = reply.create_activity(conn).unwrap();
|
||||
|
||||
assert_json_eq!(to_value(&reply_act).unwrap(), json!({
|
||||
"actor": "https://plu.me/@/user/",
|
||||
@@ -521,12 +521,12 @@ mod tests {
|
||||
}));
|
||||
|
||||
inbox(
|
||||
&conn,
|
||||
serde_json::to_value(original_comm.build_delete(&conn).unwrap()).unwrap(),
|
||||
conn,
|
||||
serde_json::to_value(original_comm.build_delete(conn).unwrap()).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
match inbox(&conn, to_value(act).unwrap()).unwrap() {
|
||||
match inbox(conn, to_value(act).unwrap()).unwrap() {
|
||||
InboxResult::Commented(c) => {
|
||||
// TODO: one is HTML, the other markdown: assert_eq!(c.content, original_comm.content);
|
||||
assert_eq!(c.in_response_to_id, original_comm.in_response_to_id);
|
||||
|
||||
@@ -69,7 +69,8 @@ pub(crate) mod tests {
|
||||
impl CustomizeConnection<Connection, ConnError> for TestConnectionCustomizer {
|
||||
fn on_acquire(&self, conn: &mut Connection) -> Result<(), ConnError> {
|
||||
PragmaForeignKey.on_acquire(conn)?;
|
||||
Ok(conn.begin_test_transaction().unwrap())
|
||||
conn.begin_test_transaction().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
blocklisted_emails::BlocklistedEmail,
|
||||
db_conn::DbConn,
|
||||
schema::email_signups,
|
||||
users::{NewUser, Role, User},
|
||||
@@ -60,6 +61,8 @@ pub struct NewEmailSignup<'a> {
|
||||
|
||||
impl EmailSignup {
|
||||
pub fn start(conn: &DbConn, email: &str) -> Result<Token> {
|
||||
Self::ensure_email_not_blocked(conn, email)?;
|
||||
|
||||
conn.transaction(|| {
|
||||
Self::ensure_user_not_exist_by_email(conn, email)?;
|
||||
let _rows = Self::delete_existings_by_email(conn, email)?;
|
||||
@@ -90,6 +93,8 @@ impl EmailSignup {
|
||||
}
|
||||
|
||||
pub fn confirm(&self, conn: &DbConn) -> Result<()> {
|
||||
Self::ensure_email_not_blocked(conn, &self.email)?;
|
||||
|
||||
conn.transaction(|| {
|
||||
Self::ensure_user_not_exist_by_email(conn, &self.email)?;
|
||||
if self.expired() {
|
||||
@@ -101,6 +106,8 @@ impl EmailSignup {
|
||||
}
|
||||
|
||||
pub fn complete(&self, conn: &DbConn, username: String, password: String) -> Result<User> {
|
||||
Self::ensure_email_not_blocked(conn, &self.email)?;
|
||||
|
||||
conn.transaction(|| {
|
||||
Self::ensure_user_not_exist_by_email(conn, &self.email)?;
|
||||
let user = NewUser::new_local(
|
||||
@@ -122,6 +129,14 @@ impl EmailSignup {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_email_not_blocked(conn: &DbConn, email: &str) -> Result<()> {
|
||||
if let Some(x) = BlocklistedEmail::matches_blocklist(conn, email)? {
|
||||
Err(Error::Blocklisted(x.notify_user, x.notification_text))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_user_not_exist_by_email(conn: &DbConn, email: &str) -> Result<()> {
|
||||
if User::email_used(conn, email)? {
|
||||
let _rows = Self::delete_existings_by_email(conn, email)?;
|
||||
|
||||
@@ -107,12 +107,7 @@ impl Follow {
|
||||
res.notify(conn)?;
|
||||
|
||||
let accept = res.build_accept(from, target, follow)?;
|
||||
broadcast(
|
||||
&*target,
|
||||
accept,
|
||||
vec![from.clone()],
|
||||
CONFIG.proxy().cloned(),
|
||||
);
|
||||
broadcast(target, accept, vec![from.clone()], CONFIG.proxy().cloned());
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
||||
@@ -82,9 +82,9 @@ pub(crate) mod tests {
|
||||
use crate::post_authors::*;
|
||||
use crate::posts::*;
|
||||
|
||||
let (users, blogs) = blog_fill_db(&conn);
|
||||
let (users, blogs) = blog_fill_db(conn);
|
||||
let post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[0].id,
|
||||
slug: "testing".to_owned(),
|
||||
@@ -102,7 +102,7 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
|
||||
PostAuthor::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPostAuthor {
|
||||
post_id: post.id,
|
||||
author_id: users[0].id,
|
||||
@@ -190,7 +190,7 @@ pub(crate) mod tests {
|
||||
});
|
||||
|
||||
assert!(matches!(
|
||||
super::inbox(&conn, act.clone()),
|
||||
super::inbox(&conn, act),
|
||||
Err(super::Error::Inbox(
|
||||
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||
))
|
||||
@@ -221,7 +221,7 @@ pub(crate) mod tests {
|
||||
});
|
||||
|
||||
assert!(matches!(
|
||||
super::inbox(&conn, act.clone()),
|
||||
super::inbox(&conn, act),
|
||||
Err(super::Error::Inbox(
|
||||
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||
))
|
||||
@@ -249,7 +249,7 @@ pub(crate) mod tests {
|
||||
});
|
||||
|
||||
assert!(matches!(
|
||||
super::inbox(&conn, act.clone()),
|
||||
super::inbox(&conn, act),
|
||||
Err(super::Error::Inbox(
|
||||
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||
))
|
||||
@@ -324,7 +324,7 @@ pub(crate) mod tests {
|
||||
});
|
||||
|
||||
assert!(matches!(
|
||||
super::inbox(&conn, act.clone()),
|
||||
super::inbox(&conn, act),
|
||||
Err(super::Error::Inbox(
|
||||
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||
))
|
||||
@@ -362,7 +362,7 @@ pub(crate) mod tests {
|
||||
});
|
||||
|
||||
assert!(matches!(
|
||||
super::inbox(&conn, act.clone()),
|
||||
super::inbox(&conn, act),
|
||||
Err(super::Error::Inbox(
|
||||
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||
))
|
||||
@@ -397,7 +397,7 @@ pub(crate) mod tests {
|
||||
});
|
||||
|
||||
assert!(matches!(
|
||||
super::inbox(&conn, act.clone()),
|
||||
super::inbox(&conn, act),
|
||||
Err(super::Error::Inbox(
|
||||
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||
))
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::{self, result::Error::NotFound, ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||
use once_cell::sync::OnceCell;
|
||||
use plume_common::utils::md_to_html;
|
||||
use plume_common::utils::{iri_percent_encode_seg, md_to_html};
|
||||
use std::sync::RwLock;
|
||||
|
||||
#[derive(Clone, Identifiable, Queryable)]
|
||||
@@ -173,8 +173,8 @@ impl Instance {
|
||||
"{instance}/{prefix}/{name}/{box_name}",
|
||||
instance = self.public_domain,
|
||||
prefix = prefix,
|
||||
name = name,
|
||||
box_name = box_name
|
||||
name = iri_percent_encode_seg(name),
|
||||
box_name = iri_percent_encode_seg(box_name)
|
||||
))
|
||||
}
|
||||
|
||||
@@ -523,7 +523,7 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
let inst = Instance::get(conn, inst.id).unwrap();
|
||||
assert_eq!(inst.name, "NewName".to_owned());
|
||||
assert_eq!(inst.open_registrations, false);
|
||||
assert!(!inst.open_registrations);
|
||||
assert_eq!(
|
||||
inst.long_description.get(),
|
||||
"[long_description](/with_link)"
|
||||
|
||||
@@ -177,7 +177,7 @@ pub type Result<T> = std::result::Result<T, Error>;
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```ignore
|
||||
/// impl Model {
|
||||
/// find_by!(model_table, name_of_the_function, field1 as String, field2 as i32);
|
||||
/// }
|
||||
@@ -201,7 +201,7 @@ macro_rules! find_by {
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```ignore
|
||||
/// impl Model {
|
||||
/// list_by!(model_table, name_of_the_function, field1 as String);
|
||||
/// }
|
||||
@@ -225,7 +225,7 @@ macro_rules! list_by {
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```rust
|
||||
/// ```ignore
|
||||
/// impl Model {
|
||||
/// get!(model_table);
|
||||
/// }
|
||||
@@ -248,7 +248,7 @@ macro_rules! get {
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```rust
|
||||
/// ```ignore
|
||||
/// impl Model {
|
||||
/// insert!(model_table, NewModelType);
|
||||
/// }
|
||||
@@ -280,7 +280,7 @@ macro_rules! insert {
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```rust
|
||||
/// ```ignore
|
||||
/// impl Model {
|
||||
/// last!(model_table);
|
||||
/// }
|
||||
@@ -354,7 +354,7 @@ mod tests {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn db<'a>() -> db_conn::DbConn {
|
||||
pub fn db() -> db_conn::DbConn {
|
||||
db_conn::DbConn((*DB_POOL).get().unwrap())
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ mod tests {
|
||||
let (posts, _users, _blogs) = fill_database(&conn);
|
||||
let post = &posts[0];
|
||||
let user = &post.get_authors(&conn)?[0];
|
||||
let like = Like::insert(&*conn, NewLike::new(post, user))?;
|
||||
let like = Like::insert(&conn, NewLike::new(post, user))?;
|
||||
let act = like.to_activity(&conn).unwrap();
|
||||
|
||||
let expected = json!({
|
||||
@@ -223,8 +223,8 @@ mod tests {
|
||||
let (posts, _users, _blogs) = fill_database(&conn);
|
||||
let post = &posts[0];
|
||||
let user = &post.get_authors(&conn)?[0];
|
||||
let like = Like::insert(&*conn, NewLike::new(post, user))?;
|
||||
let act = like.build_undo(&*conn)?;
|
||||
let like = Like::insert(&conn, NewLike::new(post, user))?;
|
||||
let act = like.build_undo(&conn)?;
|
||||
|
||||
let expected = json!({
|
||||
"actor": "https://plu.me/@/admin/",
|
||||
|
||||
@@ -435,7 +435,7 @@ mod tests {
|
||||
&List::find_for_user_by_name(conn, l1.user_id, &l1.name).unwrap(),
|
||||
);
|
||||
l_eq(
|
||||
&&l1u,
|
||||
&l1u,
|
||||
&List::find_for_user_by_name(conn, l1u.user_id, &l1u.name).unwrap(),
|
||||
);
|
||||
Ok(())
|
||||
|
||||
@@ -42,7 +42,7 @@ pub struct NewMedia {
|
||||
pub owner_id: i32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum MediaCategory {
|
||||
Image,
|
||||
Audio,
|
||||
@@ -343,7 +343,7 @@ pub(crate) mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
pub(crate) fn fill_database(conn: &Conn) -> (Vec<User>, Vec<Media>) {
|
||||
let mut wd = current_dir().unwrap().to_path_buf();
|
||||
let mut wd = current_dir().unwrap();
|
||||
while wd.pop() {
|
||||
if wd.join(".git").exists() {
|
||||
set_current_dir(wd).unwrap();
|
||||
@@ -456,7 +456,7 @@ pub(crate) mod tests {
|
||||
let media = Media::insert(
|
||||
conn,
|
||||
NewMedia {
|
||||
file_path: path.clone(),
|
||||
file_path: path,
|
||||
alt_text: "alt message".to_owned(),
|
||||
is_remote: false,
|
||||
remote_url: None,
|
||||
|
||||
@@ -89,7 +89,7 @@ mod tests {
|
||||
let request = PasswordResetRequest::find_by_token(&conn, &token)
|
||||
.expect("couldn't retrieve request");
|
||||
|
||||
assert!(&token.len() > &32);
|
||||
assert!(token.len() > 32);
|
||||
assert_eq!(&request.email, &admin_email);
|
||||
|
||||
Ok(())
|
||||
@@ -103,8 +103,8 @@ mod tests {
|
||||
user_tests::fill_database(&conn);
|
||||
let admin_email = "admin@example.com";
|
||||
|
||||
PasswordResetRequest::insert(&conn, &admin_email).expect("couldn't insert new request");
|
||||
PasswordResetRequest::insert(&conn, &admin_email)
|
||||
PasswordResetRequest::insert(&conn, admin_email).expect("couldn't insert new request");
|
||||
PasswordResetRequest::insert(&conn, admin_email)
|
||||
.expect("couldn't insert second request");
|
||||
|
||||
let count = password_reset_requests::table.count().get_result(&*conn);
|
||||
@@ -132,7 +132,7 @@ mod tests {
|
||||
.execute(&*conn)
|
||||
.expect("could not insert request");
|
||||
|
||||
match PasswordResetRequest::find_by_token(&conn, &token) {
|
||||
match PasswordResetRequest::find_by_token(&conn, token) {
|
||||
Err(Error::Expired) => (),
|
||||
_ => panic!("Received unexpected result finding expired token"),
|
||||
}
|
||||
@@ -148,7 +148,7 @@ mod tests {
|
||||
user_tests::fill_database(&conn);
|
||||
let admin_email = "admin@example.com";
|
||||
|
||||
let token = PasswordResetRequest::insert(&conn, &admin_email)
|
||||
let token = PasswordResetRequest::insert(&conn, admin_email)
|
||||
.expect("couldn't insert new request");
|
||||
PasswordResetRequest::find_and_delete_by_token(&conn, &token)
|
||||
.expect("couldn't find and delete request");
|
||||
|
||||
+20
-16
@@ -134,7 +134,7 @@ impl Post {
|
||||
.filter(posts::published.eq(true))
|
||||
.count()
|
||||
.load(conn)?
|
||||
.get(0)
|
||||
.first()
|
||||
.cloned()
|
||||
.ok_or(Error::NotFound)
|
||||
}
|
||||
@@ -255,7 +255,7 @@ impl Post {
|
||||
ap_url(&format!(
|
||||
"{}/~/{}/{}/",
|
||||
CONFIG.base_url,
|
||||
blog.fqn,
|
||||
iri_percent_encode_seg(&blog.fqn),
|
||||
iri_percent_encode_seg(slug)
|
||||
))
|
||||
}
|
||||
@@ -465,7 +465,7 @@ impl Post {
|
||||
.collect::<HashSet<_>>();
|
||||
for (m, id) in &mentions {
|
||||
if !old_user_mentioned.contains(id) {
|
||||
Mention::from_activity(&*conn, m, self.id, true, true)?;
|
||||
Mention::from_activity(conn, m, self.id, true, true)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,7 +488,7 @@ impl Post {
|
||||
.filter_map(|t| t.name.as_ref().map(|name| name.as_str().to_string()))
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let old_tags = Tag::for_post(&*conn, self.id)?;
|
||||
let old_tags = Tag::for_post(conn, self.id)?;
|
||||
let old_tags_name = old_tags
|
||||
.iter()
|
||||
.filter_map(|tag| {
|
||||
@@ -525,7 +525,7 @@ impl Post {
|
||||
.filter_map(|t| t.name.as_ref().map(|name| name.as_str().to_string()))
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let old_tags = Tag::for_post(&*conn, self.id)?;
|
||||
let old_tags = Tag::for_post(conn, self.id)?;
|
||||
let old_tags_name = old_tags
|
||||
.iter()
|
||||
.filter_map(|tag| {
|
||||
@@ -756,7 +756,11 @@ impl FromId<Connection> for Post {
|
||||
let timestamp_secs = published.unix_timestamp();
|
||||
let timestamp_nanos = published.unix_timestamp_nanos()
|
||||
- (timestamp_secs as i128) * 1000i128 * 1000i128 * 1000i128;
|
||||
NaiveDateTime::from_timestamp(timestamp_secs, timestamp_nanos as u32)
|
||||
NaiveDateTime::from_timestamp_opt(
|
||||
timestamp_secs,
|
||||
timestamp_nanos as u32,
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
subtitle: article
|
||||
.summary()
|
||||
@@ -1036,7 +1040,7 @@ mod tests {
|
||||
let post = &posts[0];
|
||||
let mentioned = &users[1];
|
||||
let mention = Mention::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewMention {
|
||||
mentioned_id: mentioned.id,
|
||||
post_id: Some(post.id),
|
||||
@@ -1044,7 +1048,7 @@ mod tests {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
(post.to_owned(), mention.to_owned(), posts, users, blogs)
|
||||
(post.to_owned(), mention, posts, users, blogs)
|
||||
}
|
||||
|
||||
// creates a post, get it's Create activity, delete the post,
|
||||
@@ -1053,9 +1057,9 @@ mod tests {
|
||||
fn self_federation() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (_, users, blogs) = fill_database(&conn);
|
||||
let (_, users, blogs) = fill_database(conn);
|
||||
let post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[0].id,
|
||||
slug: "yo".into(),
|
||||
@@ -1072,19 +1076,19 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
PostAuthor::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPostAuthor {
|
||||
post_id: post.id,
|
||||
author_id: users[0].id,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let create = post.create_activity(&conn).unwrap();
|
||||
post.delete(&conn).unwrap();
|
||||
let create = post.create_activity(conn).unwrap();
|
||||
post.delete(conn).unwrap();
|
||||
|
||||
match inbox(&conn, serde_json::to_value(create).unwrap()).unwrap() {
|
||||
match inbox(conn, serde_json::to_value(create).unwrap()).unwrap() {
|
||||
InboxResult::Post(p) => {
|
||||
assert!(p.is_author(&conn, users[0].id).unwrap());
|
||||
assert!(p.is_author(conn, users[0].id).unwrap());
|
||||
assert_eq!(p.source, "Hello".to_owned());
|
||||
assert_eq!(p.blog_id, blogs[0].id);
|
||||
assert_eq!(p.content, SafeString::new("Hello"));
|
||||
@@ -1221,7 +1225,7 @@ mod tests {
|
||||
let actual = to_value(act)?;
|
||||
|
||||
let id = actual["id"].to_string();
|
||||
let (id_pre, id_post) = id.rsplit_once("-").unwrap();
|
||||
let (id_pre, id_post) = id.rsplit_once('-').unwrap();
|
||||
assert_eq!(post.ap_url, "https://plu.me/~/BlogName/testing");
|
||||
assert_eq!(
|
||||
id_pre,
|
||||
|
||||
@@ -45,6 +45,12 @@ impl Actor for RemoteFetchActor {
|
||||
RemoteUserFound(user) => match self.conn.get() {
|
||||
Ok(conn) => {
|
||||
let conn = DbConn(conn);
|
||||
if user
|
||||
.get_instance(&conn)
|
||||
.map_or(false, |instance| instance.blocked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Don't call these functions in parallel
|
||||
// for the case database connections limit is too small
|
||||
fetch_and_cache_articles(&user, &conn);
|
||||
|
||||
@@ -229,7 +229,7 @@ mod test {
|
||||
let (posts, _users, _blogs) = fill_database(&conn);
|
||||
let post = &posts[0];
|
||||
let user = &post.get_authors(&conn)?[0];
|
||||
let reshare = Reshare::insert(&*conn, NewReshare::new(post, user))?;
|
||||
let reshare = Reshare::insert(&conn, NewReshare::new(post, user))?;
|
||||
let act = reshare.to_activity(&conn).unwrap();
|
||||
|
||||
let expected = json!({
|
||||
@@ -253,8 +253,8 @@ mod test {
|
||||
let (posts, _users, _blogs) = fill_database(&conn);
|
||||
let post = &posts[0];
|
||||
let user = &post.get_authors(&conn)?[0];
|
||||
let reshare = Reshare::insert(&*conn, NewReshare::new(post, user))?;
|
||||
let act = reshare.build_undo(&*conn)?;
|
||||
let reshare = Reshare::insert(&conn, NewReshare::new(post, user))?;
|
||||
let act = reshare.build_undo(&conn)?;
|
||||
|
||||
let expected = json!({
|
||||
"actor": "https://plu.me/@/admin/",
|
||||
|
||||
@@ -93,7 +93,7 @@ fn url_add_prefix(url: &str) -> Option<Cow<'_, str>> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, AsExpression, FromSqlRow, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, AsExpression, FromSqlRow, Default)]
|
||||
#[sql_type = "Text"]
|
||||
pub struct SafeString {
|
||||
value: String,
|
||||
|
||||
@@ -108,7 +108,7 @@ mod tests {
|
||||
|
||||
let searcher = Arc::new(get_searcher(&CONFIG.search_tokenizers));
|
||||
SearchActor::init(searcher.clone(), db_pool.clone());
|
||||
let conn = db_pool.clone().get().unwrap();
|
||||
let conn = db_pool.get().unwrap();
|
||||
|
||||
let title = random_hex()[..8].to_owned();
|
||||
let (_instance, _user, blog) = fill_database(&conn);
|
||||
@@ -161,41 +161,43 @@ mod tests {
|
||||
long_description_html: "<p>Good morning</p>".to_string(),
|
||||
short_description: SafeString::new("Hello"),
|
||||
short_description_html: "<p>Hello</p>".to_string(),
|
||||
name: random_hex().to_string(),
|
||||
name: random_hex(),
|
||||
open_registrations: true,
|
||||
public_domain: random_hex().to_string(),
|
||||
public_domain: random_hex(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let user = User::insert(
|
||||
conn,
|
||||
NewUser {
|
||||
username: random_hex().to_string(),
|
||||
display_name: random_hex().to_string(),
|
||||
outbox_url: random_hex().to_string(),
|
||||
inbox_url: random_hex().to_string(),
|
||||
username: random_hex(),
|
||||
display_name: random_hex(),
|
||||
outbox_url: random_hex(),
|
||||
inbox_url: random_hex(),
|
||||
summary: "".to_string(),
|
||||
email: None,
|
||||
hashed_password: None,
|
||||
instance_id: instance.id,
|
||||
ap_url: random_hex().to_string(),
|
||||
ap_url: random_hex(),
|
||||
private_key: None,
|
||||
public_key: "".to_string(),
|
||||
shared_inbox_url: None,
|
||||
followers_endpoint: random_hex().to_string(),
|
||||
followers_endpoint: random_hex(),
|
||||
avatar_id: None,
|
||||
summary_html: SafeString::new(""),
|
||||
role: 0,
|
||||
fqn: random_hex().to_string(),
|
||||
fqn: random_hex(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let mut blog = NewBlog::default();
|
||||
blog.instance_id = instance.id;
|
||||
blog.actor_id = random_hex().to_string();
|
||||
blog.ap_url = random_hex().to_string();
|
||||
blog.inbox_url = random_hex().to_string();
|
||||
blog.outbox_url = random_hex().to_string();
|
||||
let blog = NewBlog {
|
||||
instance_id: instance.id,
|
||||
actor_id: random_hex(),
|
||||
ap_url: random_hex(),
|
||||
inbox_url: random_hex(),
|
||||
outbox_url: random_hex(),
|
||||
..Default::default()
|
||||
};
|
||||
let blog = Blog::insert(conn, blog).unwrap();
|
||||
BlogAuthor::insert(
|
||||
conn,
|
||||
|
||||
@@ -154,7 +154,7 @@ pub(crate) mod tests {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
searcher.add_document(&conn, &post).unwrap();
|
||||
searcher.add_document(conn, &post).unwrap();
|
||||
searcher.commit();
|
||||
assert_eq!(
|
||||
searcher.search_document(conn, Query::from_str(&title).unwrap(), (0, 1))[0].id,
|
||||
|
||||
@@ -94,7 +94,7 @@ macro_rules! gen_to_string {
|
||||
)*
|
||||
$(
|
||||
for val in &$self.$date {
|
||||
$result.push_str(&format!("{}:{} ", stringify!($date), NaiveDate::from_num_days_from_ce(*val as i32).format("%Y-%m-%d")));
|
||||
$result.push_str(&format!("{}:{} ", stringify!($date), NaiveDate::from_num_days_from_ce_opt(*val as i32).unwrap().format("%Y-%m-%d")));
|
||||
}
|
||||
)*
|
||||
}
|
||||
@@ -180,12 +180,16 @@ impl PlumeQuery {
|
||||
|
||||
if self.before.is_some() || self.after.is_some() {
|
||||
// if at least one range bound is provided
|
||||
let after = self
|
||||
.after
|
||||
.unwrap_or_else(|| i64::from(NaiveDate::from_ymd(2000, 1, 1).num_days_from_ce()));
|
||||
let after = self.after.unwrap_or_else(|| {
|
||||
i64::from(
|
||||
NaiveDate::from_ymd_opt(2000, 1, 1)
|
||||
.unwrap()
|
||||
.num_days_from_ce(),
|
||||
)
|
||||
});
|
||||
let before = self
|
||||
.before
|
||||
.unwrap_or_else(|| i64::from(Utc::today().num_days_from_ce()));
|
||||
.unwrap_or_else(|| i64::from(Utc::now().date_naive().num_days_from_ce()));
|
||||
let field = Searcher::schema().get_field("creation_date").unwrap();
|
||||
let range =
|
||||
RangeQuery::new_i64_bounds(field, Bound::Included(after), Bound::Included(before));
|
||||
@@ -202,16 +206,20 @@ impl PlumeQuery {
|
||||
pub fn before<D: Datelike>(&mut self, date: &D) -> &mut Self {
|
||||
let before = self
|
||||
.before
|
||||
.unwrap_or_else(|| i64::from(Utc::today().num_days_from_ce()));
|
||||
.unwrap_or_else(|| i64::from(Utc::now().date_naive().num_days_from_ce()));
|
||||
self.before = Some(cmp::min(before, i64::from(date.num_days_from_ce())));
|
||||
self
|
||||
}
|
||||
|
||||
// documents older than the provided date will be ignored
|
||||
pub fn after<D: Datelike>(&mut self, date: &D) -> &mut Self {
|
||||
let after = self
|
||||
.after
|
||||
.unwrap_or_else(|| i64::from(NaiveDate::from_ymd(2000, 1, 1).num_days_from_ce()));
|
||||
let after = self.after.unwrap_or_else(|| {
|
||||
i64::from(
|
||||
NaiveDate::from_ymd_opt(2000, 1, 1)
|
||||
.unwrap()
|
||||
.num_days_from_ce(),
|
||||
)
|
||||
});
|
||||
self.after = Some(cmp::max(after, i64::from(date.num_days_from_ce())));
|
||||
self
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ mod tests {
|
||||
let (posts, _users, _blogs) = fill_database(conn);
|
||||
let post_id = posts[0].id;
|
||||
let mut ht = Hashtag::new();
|
||||
ht.set_href(ap_url(&format!("https://plu.me/tag/a_tag")).parse::<IriString>()?);
|
||||
ht.set_href(ap_url("https://plu.me/tag/a_tag").parse::<IriString>()?);
|
||||
ht.set_name("a_tag".to_string());
|
||||
let tag = Tag::from_activity(conn, &ht, post_id, true)?;
|
||||
|
||||
|
||||
+108
-118
@@ -13,7 +13,7 @@ pub(crate) mod query;
|
||||
pub use self::query::Kind;
|
||||
pub use self::query::{QueryError, TimelineQuery};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Queryable, Identifiable, AsChangeset)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Queryable, Identifiable, AsChangeset)]
|
||||
#[table_name = "timeline_definition"]
|
||||
pub struct Timeline {
|
||||
pub id: i32,
|
||||
@@ -300,73 +300,63 @@ mod tests {
|
||||
fn test_timeline() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let users = userTests::fill_database(&conn);
|
||||
let users = userTests::fill_database(conn);
|
||||
|
||||
let mut tl1_u1 = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"my timeline".to_owned(),
|
||||
"all".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
List::new(
|
||||
&conn,
|
||||
"languages I speak",
|
||||
Some(&users[1]),
|
||||
ListType::Prefix,
|
||||
)
|
||||
.unwrap();
|
||||
List::new(conn, "languages I speak", Some(&users[1]), ListType::Prefix).unwrap();
|
||||
let tl2_u1 = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"another timeline".to_owned(),
|
||||
"followed".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
let tl1_u2 = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[1].id,
|
||||
"english posts".to_owned(),
|
||||
"lang in \"languages I speak\"".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
let tl1_instance = Timeline::new_for_instance(
|
||||
&conn,
|
||||
conn,
|
||||
"english posts".to_owned(),
|
||||
"license in [cc]".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(tl1_u1, Timeline::get(&conn, tl1_u1.id).unwrap());
|
||||
assert_eq!(tl1_u1, Timeline::get(conn, tl1_u1.id).unwrap());
|
||||
assert_eq!(
|
||||
tl2_u1,
|
||||
Timeline::find_for_user_by_name(&conn, Some(users[0].id), "another timeline")
|
||||
Timeline::find_for_user_by_name(conn, Some(users[0].id), "another timeline")
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
tl1_instance,
|
||||
Timeline::find_for_user_by_name(&conn, None, "english posts").unwrap()
|
||||
Timeline::find_for_user_by_name(conn, None, "english posts").unwrap()
|
||||
);
|
||||
|
||||
let tl_u1 = Timeline::list_for_user(&conn, Some(users[0].id)).unwrap();
|
||||
let tl_u1 = Timeline::list_for_user(conn, Some(users[0].id)).unwrap();
|
||||
assert_eq!(3, tl_u1.len()); // it is not 2 because there is a "Your feed" tl created for each user automatically
|
||||
assert!(tl_u1.iter().fold(false, |res, tl| { res || *tl == tl1_u1 }));
|
||||
assert!(tl_u1.iter().fold(false, |res, tl| { res || *tl == tl2_u1 }));
|
||||
assert!(tl_u1.iter().any(|tl| *tl == tl1_u1));
|
||||
assert!(tl_u1.iter().any(|tl| *tl == tl2_u1));
|
||||
|
||||
let tl_instance = Timeline::list_for_user(&conn, None).unwrap();
|
||||
let tl_instance = Timeline::list_for_user(conn, None).unwrap();
|
||||
assert_eq!(3, tl_instance.len()); // there are also the local and federated feed by default
|
||||
assert!(tl_instance
|
||||
.iter()
|
||||
.fold(false, |res, tl| { res || *tl == tl1_instance }));
|
||||
assert!(tl_instance.iter().any(|tl| *tl == tl1_instance));
|
||||
|
||||
tl1_u1.name = "My Super TL".to_owned();
|
||||
let new_tl1_u2 = tl1_u2.update(&conn).unwrap();
|
||||
let new_tl1_u2 = tl1_u2.update(conn).unwrap();
|
||||
|
||||
let tl_u2 = Timeline::list_for_user(&conn, Some(users[1].id)).unwrap();
|
||||
let tl_u2 = Timeline::list_for_user(conn, Some(users[1].id)).unwrap();
|
||||
assert_eq!(2, tl_u2.len()); // same here
|
||||
assert!(tl_u2
|
||||
.iter()
|
||||
.fold(false, |res, tl| { res || *tl == new_tl1_u2 }));
|
||||
assert!(tl_u2.iter().any(|tl| *tl == new_tl1_u2));
|
||||
|
||||
Ok(())
|
||||
});
|
||||
@@ -376,48 +366,48 @@ mod tests {
|
||||
fn test_timeline_creation_error() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let users = userTests::fill_database(&conn);
|
||||
let users = userTests::fill_database(conn);
|
||||
|
||||
assert!(Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"my timeline".to_owned(),
|
||||
"invalid keyword".to_owned(),
|
||||
)
|
||||
.is_err());
|
||||
assert!(Timeline::new_for_instance(
|
||||
&conn,
|
||||
conn,
|
||||
"my timeline".to_owned(),
|
||||
"invalid keyword".to_owned(),
|
||||
)
|
||||
.is_err());
|
||||
|
||||
assert!(Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"my timeline".to_owned(),
|
||||
"author in non_existant_list".to_owned(),
|
||||
)
|
||||
.is_err());
|
||||
assert!(Timeline::new_for_instance(
|
||||
&conn,
|
||||
conn,
|
||||
"my timeline".to_owned(),
|
||||
"lang in dont-exist".to_owned(),
|
||||
)
|
||||
.is_err());
|
||||
|
||||
List::new(&conn, "friends", Some(&users[0]), ListType::User).unwrap();
|
||||
List::new(&conn, "idk", None, ListType::Blog).unwrap();
|
||||
List::new(conn, "friends", Some(&users[0]), ListType::User).unwrap();
|
||||
List::new(conn, "idk", None, ListType::Blog).unwrap();
|
||||
|
||||
assert!(Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"my timeline".to_owned(),
|
||||
"blog in friends".to_owned(),
|
||||
)
|
||||
.is_err());
|
||||
assert!(Timeline::new_for_instance(
|
||||
&conn,
|
||||
conn,
|
||||
"my timeline".to_owned(),
|
||||
"not author in idk".to_owned(),
|
||||
)
|
||||
@@ -431,10 +421,10 @@ mod tests {
|
||||
fn test_simple_match() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (users, blogs) = blogTests::fill_database(&conn);
|
||||
let (users, blogs) = blogTests::fill_database(conn);
|
||||
|
||||
let gnu_tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"GNU timeline".to_owned(),
|
||||
"license in [AGPL, LGPL, GPL]".to_owned(),
|
||||
@@ -442,7 +432,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let gnu_post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[0].id,
|
||||
slug: "slug".to_string(),
|
||||
@@ -458,10 +448,10 @@ mod tests {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert!(gnu_tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
assert!(gnu_tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
|
||||
let non_free_post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[0].id,
|
||||
slug: "slug2".to_string(),
|
||||
@@ -478,7 +468,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!gnu_tl
|
||||
.matches(&conn, &non_free_post, Kind::Original)
|
||||
.matches(conn, &non_free_post, Kind::Original)
|
||||
.unwrap());
|
||||
|
||||
Ok(())
|
||||
@@ -489,9 +479,9 @@ mod tests {
|
||||
fn test_complex_match() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (users, blogs) = blogTests::fill_database(&conn);
|
||||
let (users, blogs) = blogTests::fill_database(conn);
|
||||
Follow::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewFollow {
|
||||
follower_id: users[0].id,
|
||||
following_id: users[1].id,
|
||||
@@ -501,11 +491,11 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let fav_blogs_list =
|
||||
List::new(&conn, "fav_blogs", Some(&users[0]), ListType::Blog).unwrap();
|
||||
fav_blogs_list.add_blogs(&conn, &[blogs[0].id]).unwrap();
|
||||
List::new(conn, "fav_blogs", Some(&users[0]), ListType::Blog).unwrap();
|
||||
fav_blogs_list.add_blogs(conn, &[blogs[0].id]).unwrap();
|
||||
|
||||
let my_tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"My timeline".to_owned(),
|
||||
"blog in fav_blogs and not has_cover or local and followed exclude likes"
|
||||
@@ -514,7 +504,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[0].id,
|
||||
slug: "about-linux".to_string(),
|
||||
@@ -530,10 +520,10 @@ mod tests {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert!(my_tl.matches(&conn, &post, Kind::Original).unwrap()); // matches because of "blog in fav_blogs" (and there is no cover)
|
||||
assert!(my_tl.matches(conn, &post, Kind::Original).unwrap()); // matches because of "blog in fav_blogs" (and there is no cover)
|
||||
|
||||
let post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[1].id,
|
||||
slug: "about-linux-2".to_string(),
|
||||
@@ -551,7 +541,7 @@ mod tests {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!my_tl.matches(&conn, &post, Kind::Like(&users[1])).unwrap());
|
||||
assert!(!my_tl.matches(conn, &post, Kind::Like(&users[1])).unwrap());
|
||||
|
||||
Ok(())
|
||||
});
|
||||
@@ -561,17 +551,17 @@ mod tests {
|
||||
fn test_add_to_all_timelines() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (users, blogs) = blogTests::fill_database(&conn);
|
||||
let (users, blogs) = blogTests::fill_database(conn);
|
||||
|
||||
let gnu_tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"GNU timeline".to_owned(),
|
||||
"license in [AGPL, LGPL, GPL]".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
let non_gnu_tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"Stallman disapproved timeline".to_owned(),
|
||||
"not license in [AGPL, LGPL, GPL]".to_owned(),
|
||||
@@ -579,7 +569,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let gnu_post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[0].id,
|
||||
slug: "slug".to_string(),
|
||||
@@ -597,7 +587,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let non_free_post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[0].id,
|
||||
slug: "slug2".to_string(),
|
||||
@@ -614,13 +604,13 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Timeline::add_to_all_timelines(&conn, &gnu_post, Kind::Original).unwrap();
|
||||
Timeline::add_to_all_timelines(&conn, &non_free_post, Kind::Original).unwrap();
|
||||
Timeline::add_to_all_timelines(conn, &gnu_post, Kind::Original).unwrap();
|
||||
Timeline::add_to_all_timelines(conn, &non_free_post, Kind::Original).unwrap();
|
||||
|
||||
let res = gnu_tl.get_latest(&conn, 2).unwrap();
|
||||
let res = gnu_tl.get_latest(conn, 2).unwrap();
|
||||
assert_eq!(res.len(), 1);
|
||||
assert_eq!(res[0].id, gnu_post.id);
|
||||
let res = non_gnu_tl.get_latest(&conn, 2).unwrap();
|
||||
let res = non_gnu_tl.get_latest(conn, 2).unwrap();
|
||||
assert_eq!(res.len(), 1);
|
||||
assert_eq!(res[0].id, non_free_post.id);
|
||||
|
||||
@@ -632,10 +622,10 @@ mod tests {
|
||||
fn test_matches_lists_direct() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (users, blogs) = blogTests::fill_database(&conn);
|
||||
let (users, blogs) = blogTests::fill_database(conn);
|
||||
|
||||
let gnu_post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[0].id,
|
||||
slug: "slug".to_string(),
|
||||
@@ -652,63 +642,63 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
gnu_post
|
||||
.update_tags(&conn, vec![Tag::build_activity("free".to_owned()).unwrap()])
|
||||
.update_tags(conn, vec![Tag::build_activity("free".to_owned()).unwrap()])
|
||||
.unwrap();
|
||||
PostAuthor::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPostAuthor {
|
||||
post_id: gnu_post.id,
|
||||
author_id: blogs[0].list_authors(&conn).unwrap()[0].id,
|
||||
author_id: blogs[0].list_authors(conn).unwrap()[0].id,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"blog timeline".to_owned(),
|
||||
format!("blog in [{}]", blogs[0].fqn),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"blog timeline".to_owned(),
|
||||
"blog in [no_one@nowhere]".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(!tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"author timeline".to_owned(),
|
||||
format!(
|
||||
"author in [{}]",
|
||||
blogs[0].list_authors(&conn).unwrap()[0].fqn
|
||||
blogs[0].list_authors(conn).unwrap()[0].fqn
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"author timeline".to_owned(),
|
||||
format!("author in [{}]", users[2].fqn),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
assert!(!tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
assert!(tl
|
||||
.matches(&conn, &gnu_post, Kind::Reshare(&users[2]))
|
||||
.matches(conn, &gnu_post, Kind::Reshare(&users[2]))
|
||||
.unwrap());
|
||||
assert!(!tl.matches(&conn, &gnu_post, Kind::Like(&users[2])).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(!tl.matches(conn, &gnu_post, Kind::Like(&users[2])).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"author timeline".to_owned(),
|
||||
format!(
|
||||
@@ -717,50 +707,50 @@ mod tests {
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
assert!(!tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
assert!(!tl
|
||||
.matches(&conn, &gnu_post, Kind::Reshare(&users[2]))
|
||||
.matches(conn, &gnu_post, Kind::Reshare(&users[2]))
|
||||
.unwrap());
|
||||
assert!(tl.matches(&conn, &gnu_post, Kind::Like(&users[2])).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(tl.matches(conn, &gnu_post, Kind::Like(&users[2])).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"tag timeline".to_owned(),
|
||||
"tags in [free]".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"tag timeline".to_owned(),
|
||||
"tags in [private]".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(!tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"english timeline".to_owned(),
|
||||
"lang in [en]".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"franco-italian timeline".to_owned(),
|
||||
"lang in [fr, it]".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(!tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
|
||||
Ok(())
|
||||
});
|
||||
@@ -804,10 +794,10 @@ mod tests {
|
||||
fn test_matches_keyword() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let (users, blogs) = blogTests::fill_database(&conn);
|
||||
let (users, blogs) = blogTests::fill_database(conn);
|
||||
|
||||
let gnu_post = Post::insert(
|
||||
&conn,
|
||||
conn,
|
||||
NewPost {
|
||||
blog_id: blogs[0].id,
|
||||
slug: "slug".to_string(),
|
||||
@@ -825,61 +815,61 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"Linux title".to_owned(),
|
||||
"title contains Linux".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"Microsoft title".to_owned(),
|
||||
"title contains Microsoft".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(!tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"Linux subtitle".to_owned(),
|
||||
"subtitle contains Stallman".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"Microsoft subtitle".to_owned(),
|
||||
"subtitle contains Nadella".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(!tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"Linux content".to_owned(),
|
||||
"content contains Linux".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
let tl = Timeline::new_for_user(
|
||||
&conn,
|
||||
conn,
|
||||
users[0].id,
|
||||
"Microsoft content".to_owned(),
|
||||
"subtitle contains Windows".to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!tl.matches(&conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(&conn).unwrap();
|
||||
assert!(!tl.matches(conn, &gnu_post, Kind::Original).unwrap());
|
||||
tl.delete(conn).unwrap();
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
use plume_common::activity_pub::inbox::AsActor;
|
||||
use whatlang::{self, Lang};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum QueryError {
|
||||
SyntaxError(usize, usize, String),
|
||||
UnexpectedEndOfQuery,
|
||||
@@ -19,7 +19,7 @@ pub enum QueryError {
|
||||
|
||||
pub type QueryResult<T> = std::result::Result<T, QueryError>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Kind<'a> {
|
||||
Original,
|
||||
Reshare(&'a User),
|
||||
|
||||
+37
-56
@@ -187,7 +187,7 @@ impl User {
|
||||
users::table
|
||||
.filter(users::instance_id.eq(Instance::get_local()?.id))
|
||||
.count()
|
||||
.get_result(&*conn)
|
||||
.get_result(conn)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
@@ -246,20 +246,7 @@ impl User {
|
||||
fn fetch(url: &str) -> Result<CustomPerson> {
|
||||
let res = get(url, Self::get_sender(), CONFIG.proxy().cloned())?;
|
||||
let text = &res.text()?;
|
||||
// without this workaround, publicKey is not correctly deserialized
|
||||
let ap_sign = serde_json::from_str::<ApSignature>(text)?;
|
||||
let person = serde_json::from_str::<Person>(text)?;
|
||||
let json = CustomPerson::new(
|
||||
ApActor::new(
|
||||
person
|
||||
.clone()
|
||||
.id_unchecked()
|
||||
.ok_or(Error::MissingApProperty)?
|
||||
.to_owned(),
|
||||
person,
|
||||
),
|
||||
ap_sign,
|
||||
); // FIXME: Don't clone()
|
||||
let json = serde_json::from_str::<CustomPerson>(text)?;
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
@@ -269,23 +256,13 @@ impl User {
|
||||
|
||||
pub fn refetch(&self, conn: &Connection) -> Result<()> {
|
||||
User::fetch(&self.ap_url.clone()).and_then(|json| {
|
||||
let avatar = Media::save_remote(
|
||||
conn,
|
||||
json.ap_actor_ref()
|
||||
.icon()
|
||||
.ok_or(Error::MissingApProperty)? // FIXME: Fails when icon is not set
|
||||
.iter()
|
||||
.next()
|
||||
.and_then(|i| {
|
||||
i.clone()
|
||||
.extend::<Image, ImageType>() // FIXME: Don't clone()
|
||||
.ok()?
|
||||
.and_then(|url| Some(url.id_unchecked()?.to_string()))
|
||||
})
|
||||
.ok_or(Error::MissingApProperty)?,
|
||||
self,
|
||||
)
|
||||
.ok();
|
||||
let avatar = json
|
||||
.icon()
|
||||
.and_then(|icon| icon.iter().next())
|
||||
.and_then(|i| i.clone().extend::<Image, ImageType>().ok())
|
||||
.and_then(|image| image)
|
||||
.and_then(|image| image.id_unchecked().map(|url| url.to_string()))
|
||||
.and_then(|url| Media::save_remote(conn, url, self).ok());
|
||||
|
||||
let pub_key = &json.ext_one.public_key.public_key_pem;
|
||||
diesel::update(self)
|
||||
@@ -435,7 +412,7 @@ impl User {
|
||||
}
|
||||
// if no user was found, and we were unable to auto-register from ldap
|
||||
// fake-verify a password, and return an error.
|
||||
let other = User::get(&*conn, 1)
|
||||
let other = User::get(conn, 1)
|
||||
.expect("No user is registered")
|
||||
.hashed_password;
|
||||
other.map(|pass| bcrypt::verify(password, &pass));
|
||||
@@ -931,7 +908,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for User {
|
||||
.cookies()
|
||||
.get_private(AUTH_COOKIE)
|
||||
.and_then(|cookie| cookie.value().parse().ok())
|
||||
.and_then(|id| User::get(&*conn, id).ok())
|
||||
.and_then(|id| User::get(&conn, id).ok())
|
||||
.or_forward(())
|
||||
}
|
||||
}
|
||||
@@ -960,6 +937,10 @@ impl FromId<Connection> for User {
|
||||
.to_string();
|
||||
|
||||
if username.contains(&['<', '>', '&', '@', '\'', '"', ' ', '\t'][..]) {
|
||||
tracing::error!(
|
||||
"preferredUsername includes invalid character(s): {}",
|
||||
&username
|
||||
);
|
||||
return Err(Error::InvalidValue);
|
||||
}
|
||||
|
||||
@@ -1232,7 +1213,7 @@ pub(crate) mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
other.avatar_id = Some(avatar.id);
|
||||
let other = other.save_changes::<User>(&*conn).unwrap();
|
||||
let other = other.save_changes::<User>(conn).unwrap();
|
||||
|
||||
vec![admin, user, other]
|
||||
}
|
||||
@@ -1335,11 +1316,11 @@ pub(crate) mod tests {
|
||||
fn delete() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let inserted = fill_database(&conn);
|
||||
let inserted = fill_database(conn);
|
||||
|
||||
assert!(User::get(&conn, inserted[0].id).is_ok());
|
||||
inserted[0].delete(&conn).unwrap();
|
||||
assert!(User::get(&conn, inserted[0].id).is_err());
|
||||
assert!(User::get(conn, inserted[0].id).is_ok());
|
||||
inserted[0].delete(conn).unwrap();
|
||||
assert!(User::get(conn, inserted[0].id).is_err());
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
@@ -1348,20 +1329,20 @@ pub(crate) mod tests {
|
||||
fn admin() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
let inserted = fill_database(&conn);
|
||||
let inserted = fill_database(conn);
|
||||
let local_inst = Instance::get_local().unwrap();
|
||||
let mut i = 0;
|
||||
while local_inst.has_admin(&conn).unwrap() {
|
||||
while local_inst.has_admin(conn).unwrap() {
|
||||
assert!(i < 100); //prevent from looping indefinitelly
|
||||
local_inst
|
||||
.main_admin(&conn)
|
||||
.main_admin(conn)
|
||||
.unwrap()
|
||||
.set_role(&conn, Role::Normal)
|
||||
.set_role(conn, Role::Normal)
|
||||
.unwrap();
|
||||
i += 1;
|
||||
}
|
||||
inserted[0].set_role(&conn, Role::Admin).unwrap();
|
||||
assert_eq!(inserted[0].id, local_inst.main_admin(&conn).unwrap().id);
|
||||
inserted[0].set_role(conn, Role::Admin).unwrap();
|
||||
assert_eq!(inserted[0].id, local_inst.main_admin(conn).unwrap().id);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
@@ -1370,9 +1351,9 @@ pub(crate) mod tests {
|
||||
fn auth() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
fill_database(&conn);
|
||||
fill_database(conn);
|
||||
let test_user = NewUser::new_local(
|
||||
&conn,
|
||||
conn,
|
||||
"test".to_owned(),
|
||||
"test user".to_owned(),
|
||||
Role::Normal,
|
||||
@@ -1383,10 +1364,10 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
User::login(&conn, "test", "test_password").unwrap().id,
|
||||
User::login(conn, "test", "test_password").unwrap().id,
|
||||
test_user.id
|
||||
);
|
||||
assert!(User::login(&conn, "test", "other_password").is_err());
|
||||
assert!(User::login(conn, "test", "other_password").is_err());
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
@@ -1395,26 +1376,26 @@ pub(crate) mod tests {
|
||||
fn get_local_page() {
|
||||
let conn = &db();
|
||||
conn.test_transaction::<_, (), _>(|| {
|
||||
fill_database(&conn);
|
||||
fill_database(conn);
|
||||
|
||||
let page = User::get_local_page(&conn, (0, 2)).unwrap();
|
||||
let page = User::get_local_page(conn, (0, 2)).unwrap();
|
||||
assert_eq!(page.len(), 2);
|
||||
assert!(page[0].username <= page[1].username);
|
||||
|
||||
let mut last_username = User::get_local_page(&conn, (0, 1)).unwrap()[0]
|
||||
let mut last_username = User::get_local_page(conn, (0, 1)).unwrap()[0]
|
||||
.username
|
||||
.clone();
|
||||
for i in 1..User::count_local(&conn).unwrap() as i32 {
|
||||
let page = User::get_local_page(&conn, (i, i + 1)).unwrap();
|
||||
for i in 1..User::count_local(conn).unwrap() as i32 {
|
||||
let page = User::get_local_page(conn, (i, i + 1)).unwrap();
|
||||
assert_eq!(page.len(), 1);
|
||||
assert!(last_username <= page[0].username);
|
||||
last_username = page[0].username.clone();
|
||||
}
|
||||
assert_eq!(
|
||||
User::get_local_page(&conn, (0, User::count_local(&conn).unwrap() as i32 + 10))
|
||||
User::get_local_page(conn, (0, User::count_local(conn).unwrap() as i32 + 10))
|
||||
.unwrap()
|
||||
.len() as i64,
|
||||
User::count_local(&conn).unwrap()
|
||||
User::count_local(conn).unwrap()
|
||||
);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user