Introduce features to choose between SQlite or Postgres
This commit is contained in:
parent
88456faf84
commit
38d737ed0c
@ -62,5 +62,10 @@ rev = "b326a9893a1849c9abdb39cab9fd7c4a52eb9674"
|
|||||||
git = "https://github.com/BaptisteGelez/rocket_i18n"
|
git = "https://github.com/BaptisteGelez/rocket_i18n"
|
||||||
rev = "75a3bfd7b847324c078a355a7f101f8241a9f59b"
|
rev = "75a3bfd7b847324c078a355a7f101f8241a9f59b"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["postgres"]
|
||||||
|
postgres = ["plume-models/postgres"]
|
||||||
|
sqlite = ["plume-models/sqlite"]
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["plume-api", "plume-models", "plume-common"]
|
members = ["plume-api", "plume-models", "plume-common"]
|
||||||
|
@ -3,6 +3,6 @@ CREATE TABLE likes (
|
|||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE NOT NULL,
|
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE NOT NULL,
|
||||||
post_id INTEGER REFERENCES posts(id) ON DELETE CASCADE NOT NULL,
|
post_id INTEGER REFERENCES posts(id) ON DELETE CASCADE NOT NULL,
|
||||||
ap_url VARCHAR NOT NULL default '',
|
creation_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
creation_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
ap_url VARCHAR NOT NULL default ''
|
||||||
)
|
)
|
||||||
|
@ -23,7 +23,7 @@ features = ["serde"]
|
|||||||
version = "0.4"
|
version = "0.4"
|
||||||
|
|
||||||
[dependencies.diesel]
|
[dependencies.diesel]
|
||||||
features = ["postgres", "sqlite", "r2d2", "chrono"]
|
features = ["r2d2", "chrono"]
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
|
||||||
[dependencies.plume-api]
|
[dependencies.plume-api]
|
||||||
@ -35,3 +35,8 @@ path = "../plume-common"
|
|||||||
[dependencies.rocket]
|
[dependencies.rocket]
|
||||||
git = "https://github.com/SergioBenitez/Rocket"
|
git = "https://github.com/SergioBenitez/Rocket"
|
||||||
rev = "55459db7732b9a240826a5c120c650f87e3372ce"
|
rev = "55459db7732b9a240826a5c120c650f87e3372ce"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["postgres"]
|
||||||
|
postgres = ["diesel/postgres"]
|
||||||
|
sqlite = ["diesel/sqlite"]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods, PgConnection};
|
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods};
|
||||||
|
|
||||||
use schema::blog_authors;
|
use schema::blog_authors;
|
||||||
|
|
||||||
|
@ -6,8 +6,7 @@ use reqwest::{
|
|||||||
};
|
};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use chrono::NaiveDateTime;
|
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods, dsl::any};
|
||||||
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods, PgConnection, dsl::any};
|
|
||||||
use openssl::{
|
use openssl::{
|
||||||
hash::MessageDigest,
|
hash::MessageDigest,
|
||||||
pkey::{PKey, Private},
|
pkey::{PKey, Private},
|
||||||
@ -16,7 +15,7 @@ use openssl::{
|
|||||||
};
|
};
|
||||||
use webfinger::*;
|
use webfinger::*;
|
||||||
|
|
||||||
use {BASE_URL, USE_HTTPS};
|
use {BASE_URL, USE_HTTPS, Connection, SqlDateTime};
|
||||||
use plume_common::activity_pub::{
|
use plume_common::activity_pub::{
|
||||||
ap_accept_header, ApSignature, ActivityStream, Id, IntoId, PublicKey,
|
ap_accept_header, ApSignature, ActivityStream, Id, IntoId, PublicKey,
|
||||||
inbox::WithInbox,
|
inbox::WithInbox,
|
||||||
@ -38,7 +37,7 @@ pub struct Blog {
|
|||||||
pub outbox_url: String,
|
pub outbox_url: String,
|
||||||
pub inbox_url: String,
|
pub inbox_url: String,
|
||||||
pub instance_id: i32,
|
pub instance_id: i32,
|
||||||
pub creation_date: NaiveDateTime,
|
pub creation_date: SqlDateTime,
|
||||||
pub ap_url: String,
|
pub ap_url: String,
|
||||||
pub private_key: Option<String>,
|
pub private_key: Option<String>,
|
||||||
pub public_key: String
|
pub public_key: String
|
||||||
@ -66,11 +65,11 @@ impl Blog {
|
|||||||
find_by!(blogs, find_by_ap_url, ap_url as String);
|
find_by!(blogs, find_by_ap_url, ap_url as String);
|
||||||
find_by!(blogs, find_by_name, actor_id as String, instance_id as i32);
|
find_by!(blogs, find_by_name, actor_id as String, instance_id as i32);
|
||||||
|
|
||||||
pub fn get_instance(&self, conn: &PgConnection) -> Instance {
|
pub fn get_instance(&self, conn: &Connection) -> Instance {
|
||||||
Instance::get(conn, self.instance_id).expect("Couldn't find instance")
|
Instance::get(conn, self.instance_id).expect("Couldn't find instance")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_authors(&self, conn: &PgConnection) -> Vec<User> {
|
pub fn list_authors(&self, conn: &Connection) -> Vec<User> {
|
||||||
use schema::blog_authors;
|
use schema::blog_authors;
|
||||||
use schema::users;
|
use schema::users;
|
||||||
let authors_ids = blog_authors::table.filter(blog_authors::blog_id.eq(self.id)).select(blog_authors::author_id);
|
let authors_ids = blog_authors::table.filter(blog_authors::blog_id.eq(self.id)).select(blog_authors::author_id);
|
||||||
@ -79,7 +78,7 @@ impl Blog {
|
|||||||
.expect("Couldn't load authors of a blog")
|
.expect("Couldn't load authors of a blog")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_for_author(conn: &PgConnection, author_id: i32) -> Vec<Blog> {
|
pub fn find_for_author(conn: &Connection, author_id: i32) -> Vec<Blog> {
|
||||||
use schema::blog_authors;
|
use schema::blog_authors;
|
||||||
let author_ids = blog_authors::table.filter(blog_authors::author_id.eq(author_id)).select(blog_authors::blog_id);
|
let author_ids = blog_authors::table.filter(blog_authors::author_id.eq(author_id)).select(blog_authors::blog_id);
|
||||||
blogs::table.filter(blogs::id.eq(any(author_ids)))
|
blogs::table.filter(blogs::id.eq(any(author_ids)))
|
||||||
@ -87,11 +86,11 @@ impl Blog {
|
|||||||
.expect("Couldn't load blogs ")
|
.expect("Couldn't load blogs ")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_local(conn: &PgConnection, name: String) -> Option<Blog> {
|
pub fn find_local(conn: &Connection, name: String) -> Option<Blog> {
|
||||||
Blog::find_by_name(conn, name, Instance::local_id(conn))
|
Blog::find_by_name(conn, name, Instance::local_id(conn))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_by_fqn(conn: &PgConnection, fqn: String) -> Option<Blog> {
|
pub fn find_by_fqn(conn: &Connection, fqn: String) -> Option<Blog> {
|
||||||
if fqn.contains("@") { // remote blog
|
if fqn.contains("@") { // remote blog
|
||||||
match Instance::find_by_domain(conn, String::from(fqn.split("@").last().unwrap())) {
|
match Instance::find_by_domain(conn, String::from(fqn.split("@").last().unwrap())) {
|
||||||
Some(instance) => {
|
Some(instance) => {
|
||||||
@ -107,7 +106,7 @@ impl Blog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_from_webfinger(conn: &PgConnection, acct: String) -> Option<Blog> {
|
fn fetch_from_webfinger(conn: &Connection, acct: String) -> Option<Blog> {
|
||||||
match resolve(acct.clone(), *USE_HTTPS) {
|
match resolve(acct.clone(), *USE_HTTPS) {
|
||||||
Ok(wf) => wf.links.into_iter().find(|l| l.mime_type == Some(String::from("application/activity+json"))).and_then(|l| Blog::fetch_from_url(conn, l.href.expect("No href for AP WF link"))),
|
Ok(wf) => wf.links.into_iter().find(|l| l.mime_type == Some(String::from("application/activity+json"))).and_then(|l| Blog::fetch_from_url(conn, l.href.expect("No href for AP WF link"))),
|
||||||
Err(details) => {
|
Err(details) => {
|
||||||
@ -117,7 +116,7 @@ impl Blog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_from_url(conn: &PgConnection, url: String) -> Option<Blog> {
|
fn fetch_from_url(conn: &Connection, url: String) -> Option<Blog> {
|
||||||
let req = Client::new()
|
let req = Client::new()
|
||||||
.get(&url[..])
|
.get(&url[..])
|
||||||
.header(Accept(ap_accept_header().into_iter().map(|h| qitem(h.parse::<Mime>().expect("Invalid Content-Type"))).collect()))
|
.header(Accept(ap_accept_header().into_iter().map(|h| qitem(h.parse::<Mime>().expect("Invalid Content-Type"))).collect()))
|
||||||
@ -134,7 +133,7 @@ impl Blog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_activity(conn: &PgConnection, acct: CustomGroup, inst: String) -> Blog {
|
fn from_activity(conn: &Connection, acct: CustomGroup, inst: String) -> Blog {
|
||||||
let instance = match Instance::find_by_domain(conn, inst.clone()) {
|
let instance = match Instance::find_by_domain(conn, inst.clone()) {
|
||||||
Some(instance) => instance,
|
Some(instance) => instance,
|
||||||
None => {
|
None => {
|
||||||
@ -166,7 +165,7 @@ impl Blog {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_activity(&self, _conn: &PgConnection) -> CustomGroup {
|
pub fn into_activity(&self, _conn: &Connection) -> CustomGroup {
|
||||||
let mut blog = Group::default();
|
let mut blog = Group::default();
|
||||||
blog.ap_actor_props.set_preferred_username_string(self.actor_id.clone()).expect("Blog::into_activity: preferredUsername error");
|
blog.ap_actor_props.set_preferred_username_string(self.actor_id.clone()).expect("Blog::into_activity: preferredUsername error");
|
||||||
blog.object_props.set_name_string(self.title.clone()).expect("Blog::into_activity: name error");
|
blog.object_props.set_name_string(self.title.clone()).expect("Blog::into_activity: name error");
|
||||||
@ -185,7 +184,7 @@ impl Blog {
|
|||||||
CustomGroup::new(blog, ap_signature)
|
CustomGroup::new(blog, ap_signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_boxes(&self, conn: &PgConnection) {
|
pub fn update_boxes(&self, conn: &Connection) {
|
||||||
let instance = self.get_instance(conn);
|
let instance = self.get_instance(conn);
|
||||||
if self.outbox_url.len() == 0 {
|
if self.outbox_url.len() == 0 {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
@ -206,14 +205,14 @@ impl Blog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outbox(&self, conn: &PgConnection) -> ActivityStream<OrderedCollection> {
|
pub fn outbox(&self, conn: &Connection) -> ActivityStream<OrderedCollection> {
|
||||||
let mut coll = OrderedCollection::default();
|
let mut coll = OrderedCollection::default();
|
||||||
coll.collection_props.items = serde_json::to_value(self.get_activities(conn)).unwrap();
|
coll.collection_props.items = serde_json::to_value(self.get_activities(conn)).unwrap();
|
||||||
coll.collection_props.set_total_items_u64(self.get_activities(conn).len() as u64).unwrap();
|
coll.collection_props.set_total_items_u64(self.get_activities(conn).len() as u64).unwrap();
|
||||||
ActivityStream::new(coll)
|
ActivityStream::new(coll)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_activities(&self, _conn: &PgConnection) -> Vec<serde_json::Value> {
|
fn get_activities(&self, _conn: &Connection) -> Vec<serde_json::Value> {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +220,7 @@ impl Blog {
|
|||||||
PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.clone().unwrap().as_ref()).unwrap()).unwrap()
|
PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.clone().unwrap().as_ref()).unwrap()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webfinger(&self, conn: &PgConnection) -> Webfinger {
|
pub fn webfinger(&self, conn: &Connection) -> Webfinger {
|
||||||
Webfinger {
|
Webfinger {
|
||||||
subject: format!("acct:{}@{}", self.actor_id, self.get_instance(conn).public_domain),
|
subject: format!("acct:{}@{}", self.actor_id, self.get_instance(conn).public_domain),
|
||||||
aliases: vec![self.ap_url.clone()],
|
aliases: vec![self.ap_url.clone()],
|
||||||
@ -248,7 +247,7 @@ impl Blog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_url(conn: &PgConnection, url: String) -> Option<Blog> {
|
pub fn from_url(conn: &Connection, url: String) -> Option<Blog> {
|
||||||
Blog::find_by_ap_url(conn, url.clone()).or_else(|| {
|
Blog::find_by_ap_url(conn, url.clone()).or_else(|| {
|
||||||
// The requested user was not in the DB
|
// The requested user was not in the DB
|
||||||
// We try to fetch it if it is remote
|
// We try to fetch it if it is remote
|
||||||
@ -260,7 +259,7 @@ impl Blog {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fqn(&self, conn: &PgConnection) -> String {
|
pub fn get_fqn(&self, conn: &Connection) -> String {
|
||||||
if self.instance_id == Instance::local_id(conn) {
|
if self.instance_id == Instance::local_id(conn) {
|
||||||
self.actor_id.clone()
|
self.actor_id.clone()
|
||||||
} else {
|
} else {
|
||||||
@ -268,7 +267,7 @@ impl Blog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_json(&self, conn: &PgConnection) -> serde_json::Value {
|
pub fn to_json(&self, conn: &Connection) -> serde_json::Value {
|
||||||
let mut json = serde_json::to_value(self).unwrap();
|
let mut json = serde_json::to_value(self).unwrap();
|
||||||
json["fqn"] = json!(self.get_fqn(conn));
|
json["fqn"] = json!(self.get_fqn(conn));
|
||||||
json
|
json
|
||||||
|
@ -12,6 +12,7 @@ use plume_common::activity_pub::{
|
|||||||
inbox::{FromActivity, Notify}
|
inbox::{FromActivity, Notify}
|
||||||
};
|
};
|
||||||
use plume_common::utils;
|
use plume_common::utils;
|
||||||
|
use {Connection, SqlDateTime};
|
||||||
use instance::Instance;
|
use instance::Instance;
|
||||||
use mentions::Mention;
|
use mentions::Mention;
|
||||||
use notifications::*;
|
use notifications::*;
|
||||||
@ -27,7 +28,7 @@ pub struct Comment {
|
|||||||
pub in_response_to_id: Option<i32>,
|
pub in_response_to_id: Option<i32>,
|
||||||
pub post_id: i32,
|
pub post_id: i32,
|
||||||
pub author_id: i32,
|
pub author_id: i32,
|
||||||
pub creation_date: chrono::NaiveDateTime,
|
pub creation_date: SqlDateTime,
|
||||||
pub ap_url: Option<String>,
|
pub ap_url: Option<String>,
|
||||||
pub sensitive: bool,
|
pub sensitive: bool,
|
||||||
pub spoiler_text: String
|
pub spoiler_text: String
|
||||||
@ -51,15 +52,15 @@ impl Comment {
|
|||||||
list_by!(comments, list_by_post, post_id as i32);
|
list_by!(comments, list_by_post, post_id as i32);
|
||||||
find_by!(comments, find_by_ap_url, ap_url as String);
|
find_by!(comments, find_by_ap_url, ap_url as String);
|
||||||
|
|
||||||
pub fn get_author(&self, conn: &PgConnection) -> User {
|
pub fn get_author(&self, conn: &Connection) -> User {
|
||||||
User::get(conn, self.author_id).unwrap()
|
User::get(conn, self.author_id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_post(&self, conn: &PgConnection) -> Post {
|
pub fn get_post(&self, conn: &Connection) -> Post {
|
||||||
Post::get(conn, self.post_id).unwrap()
|
Post::get(conn, self.post_id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count_local(conn: &PgConnection) -> usize {
|
pub fn count_local(conn: &Connection) -> usize {
|
||||||
use schema::users;
|
use schema::users;
|
||||||
let local_authors = users::table.filter(users::instance_id.eq(Instance::local_id(conn))).select(users::id);
|
let local_authors = users::table.filter(users::instance_id.eq(Instance::local_id(conn))).select(users::id);
|
||||||
comments::table.filter(comments::author_id.eq(any(local_authors)))
|
comments::table.filter(comments::author_id.eq(any(local_authors)))
|
||||||
@ -68,7 +69,7 @@ impl Comment {
|
|||||||
.len()
|
.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_json(&self, conn: &PgConnection, others: &Vec<Comment>) -> serde_json::Value {
|
pub fn to_json(&self, conn: &Connection, others: &Vec<Comment>) -> serde_json::Value {
|
||||||
let mut json = serde_json::to_value(self).unwrap();
|
let mut json = serde_json::to_value(self).unwrap();
|
||||||
json["author"] = self.get_author(conn).to_json(conn);
|
json["author"] = self.get_author(conn).to_json(conn);
|
||||||
let mentions = Mention::list_for_comment(conn, self.id).into_iter()
|
let mentions = Mention::list_for_comment(conn, self.id).into_iter()
|
||||||
@ -82,7 +83,7 @@ impl Comment {
|
|||||||
json
|
json
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_ap_url(&self, conn: &PgConnection) -> Comment {
|
pub fn update_ap_url(&self, conn: &Connection) -> Comment {
|
||||||
if self.ap_url.is_none() {
|
if self.ap_url.is_none() {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(comments::ap_url.eq(self.compute_id(conn)))
|
.set(comments::ap_url.eq(self.compute_id(conn)))
|
||||||
@ -93,11 +94,11 @@ impl Comment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_id(&self, conn: &PgConnection) -> String {
|
pub fn compute_id(&self, conn: &Connection) -> String {
|
||||||
format!("{}comment/{}", self.get_post(conn).ap_url, self.id)
|
format!("{}comment/{}", self.get_post(conn).ap_url, self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_activity(&self, conn: &PgConnection) -> Note {
|
pub fn into_activity(&self, conn: &Connection) -> Note {
|
||||||
let (html, mentions) = utils::md_to_html(self.content.get().as_ref());
|
let (html, mentions) = utils::md_to_html(self.content.get().as_ref());
|
||||||
|
|
||||||
let author = User::get(conn, self.author_id).unwrap();
|
let author = User::get(conn, self.author_id).unwrap();
|
||||||
@ -119,7 +120,7 @@ impl Comment {
|
|||||||
note
|
note
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_activity(&self, conn: &PgConnection) -> Create {
|
pub fn create_activity(&self, conn: &Connection) -> Create {
|
||||||
let author = User::get(conn, self.author_id).unwrap();
|
let author = User::get(conn, self.author_id).unwrap();
|
||||||
|
|
||||||
let note = self.into_activity(conn);
|
let note = self.into_activity(conn);
|
||||||
@ -134,7 +135,7 @@ impl Comment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromActivity<Note, PgConnection> for Comment {
|
impl FromActivity<Note, PgConnection> for Comment {
|
||||||
fn from_activity(conn: &PgConnection, note: Note, actor: Id) -> Comment {
|
fn from_activity(conn: &Connection, note: Note, actor: Id) -> Comment {
|
||||||
let previous_url = note.object_props.in_reply_to.clone().unwrap().as_str().unwrap().to_string();
|
let previous_url = note.object_props.in_reply_to.clone().unwrap().as_str().unwrap().to_string();
|
||||||
let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone());
|
let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone());
|
||||||
|
|
||||||
@ -168,7 +169,7 @@ impl FromActivity<Note, PgConnection> for Comment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Notify<PgConnection> for Comment {
|
impl Notify<PgConnection> for Comment {
|
||||||
fn notify(&self, conn: &PgConnection) {
|
fn notify(&self, conn: &Connection) {
|
||||||
for author in self.get_post(conn).get_authors(conn) {
|
for author in self.get_post(conn).get_authors(conn) {
|
||||||
Notification::insert(conn, NewNotification {
|
Notification::insert(conn, NewNotification {
|
||||||
kind: notification_kind::COMMENT.to_string(),
|
kind: notification_kind::COMMENT.to_string(),
|
||||||
|
@ -27,7 +27,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for DbConn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the convenience of using an &DbConn as an &PgConnection.
|
// For the convenience of using an &DbConn as an &Connection.
|
||||||
impl Deref for DbConn {
|
impl Deref for DbConn {
|
||||||
type Target = PgConnection;
|
type Target = PgConnection;
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ use activitypub::{Actor, activity::{Accept, Follow as FollowAct, Undo}, actor::P
|
|||||||
use diesel::{self, PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl};
|
use diesel::{self, PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||||
|
|
||||||
use plume_common::activity_pub::{broadcast, Id, IntoId, inbox::{FromActivity, Notify, WithInbox, Deletable}, sign::Signer};
|
use plume_common::activity_pub::{broadcast, Id, IntoId, inbox::{FromActivity, Notify, WithInbox, Deletable}, sign::Signer};
|
||||||
|
use Connection;
|
||||||
use blogs::Blog;
|
use blogs::Blog;
|
||||||
use notifications::*;
|
use notifications::*;
|
||||||
use users::User;
|
use users::User;
|
||||||
@ -29,14 +30,14 @@ impl Follow {
|
|||||||
get!(follows);
|
get!(follows);
|
||||||
find_by!(follows, find_by_ap_url, ap_url as String);
|
find_by!(follows, find_by_ap_url, ap_url as String);
|
||||||
|
|
||||||
pub fn find(conn: &PgConnection, from: i32, to: i32) -> Option<Follow> {
|
pub fn find(conn: &Connection, from: i32, to: i32) -> Option<Follow> {
|
||||||
follows::table.filter(follows::follower_id.eq(from))
|
follows::table.filter(follows::follower_id.eq(from))
|
||||||
.filter(follows::following_id.eq(to))
|
.filter(follows::following_id.eq(to))
|
||||||
.get_result(conn)
|
.get_result(conn)
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_activity(&self, conn: &PgConnection) -> FollowAct {
|
pub fn into_activity(&self, conn: &Connection) -> FollowAct {
|
||||||
let user = User::get(conn, self.follower_id).unwrap();
|
let user = User::get(conn, self.follower_id).unwrap();
|
||||||
let target = User::get(conn, self.following_id).unwrap();
|
let target = User::get(conn, self.following_id).unwrap();
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ impl Follow {
|
|||||||
/// from -> The one sending the follow request
|
/// from -> The one sending the follow request
|
||||||
/// target -> The target of the request, responding with Accept
|
/// target -> The target of the request, responding with Accept
|
||||||
pub fn accept_follow<A: Signer + IntoId + Clone, B: Clone + WithInbox + Actor + IntoId>(
|
pub fn accept_follow<A: Signer + IntoId + Clone, B: Clone + WithInbox + Actor + IntoId>(
|
||||||
conn: &PgConnection,
|
conn: &Connection,
|
||||||
from: &B,
|
from: &B,
|
||||||
target: &A,
|
target: &A,
|
||||||
follow: FollowAct,
|
follow: FollowAct,
|
||||||
@ -80,7 +81,7 @@ impl Follow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromActivity<FollowAct, PgConnection> for Follow {
|
impl FromActivity<FollowAct, PgConnection> for Follow {
|
||||||
fn from_activity(conn: &PgConnection, follow: FollowAct, _actor: Id) -> Follow {
|
fn from_activity(conn: &Connection, follow: FollowAct, _actor: Id) -> Follow {
|
||||||
let from_id = follow.follow_props.actor_link::<Id>().map(|l| l.into())
|
let from_id = follow.follow_props.actor_link::<Id>().map(|l| l.into())
|
||||||
.unwrap_or_else(|_| follow.follow_props.actor_object::<Person>().expect("No actor object (nor ID) on Follow").object_props.id_string().expect("No ID on actor on Follow"));
|
.unwrap_or_else(|_| follow.follow_props.actor_object::<Person>().expect("No actor object (nor ID) on Follow").object_props.id_string().expect("No ID on actor on Follow"));
|
||||||
let from = User::from_url(conn, from_id).unwrap();
|
let from = User::from_url(conn, from_id).unwrap();
|
||||||
@ -95,7 +96,7 @@ impl FromActivity<FollowAct, PgConnection> for Follow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Notify<PgConnection> for Follow {
|
impl Notify<PgConnection> for Follow {
|
||||||
fn notify(&self, conn: &PgConnection) {
|
fn notify(&self, conn: &Connection) {
|
||||||
Notification::insert(conn, NewNotification {
|
Notification::insert(conn, NewNotification {
|
||||||
kind: notification_kind::FOLLOW.to_string(),
|
kind: notification_kind::FOLLOW.to_string(),
|
||||||
object_id: self.id,
|
object_id: self.id,
|
||||||
@ -105,7 +106,7 @@ impl Notify<PgConnection> for Follow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Deletable<PgConnection, Undo> for Follow {
|
impl Deletable<PgConnection, Undo> for Follow {
|
||||||
fn delete(&self, conn: &PgConnection) -> Undo {
|
fn delete(&self, conn: &Connection) -> Undo {
|
||||||
diesel::delete(self).execute(conn).expect("Coudn't delete follow");
|
diesel::delete(self).execute(conn).expect("Coudn't delete follow");
|
||||||
|
|
||||||
// delete associated notification if any
|
// delete associated notification if any
|
||||||
@ -120,7 +121,7 @@ impl Deletable<PgConnection, Undo> for Follow {
|
|||||||
undo
|
undo
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_id(id: String, conn: &PgConnection) {
|
fn delete_id(id: String, conn: &Connection) {
|
||||||
if let Some(follow) = Follow::find_by_ap_url(conn, id) {
|
if let Some(follow) = Follow::find_by_ap_url(conn, id) {
|
||||||
follow.delete(conn);
|
follow.delete(conn);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use chrono::NaiveDateTime;
|
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods};
|
||||||
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods, PgConnection};
|
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
use plume_common::utils::md_to_html;
|
use plume_common::utils::md_to_html;
|
||||||
|
use {Connection, SqlDateTime};
|
||||||
use safe_string::SafeString;
|
use safe_string::SafeString;
|
||||||
use ap_url;
|
use ap_url;
|
||||||
use users::User;
|
use users::User;
|
||||||
@ -15,7 +15,7 @@ pub struct Instance {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub local: bool,
|
pub local: bool,
|
||||||
pub blocked: bool,
|
pub blocked: bool,
|
||||||
pub creation_date: NaiveDateTime,
|
pub creation_date: SqlDateTime,
|
||||||
pub open_registrations: bool,
|
pub open_registrations: bool,
|
||||||
pub short_description: SafeString,
|
pub short_description: SafeString,
|
||||||
pub long_description: SafeString,
|
pub long_description: SafeString,
|
||||||
@ -39,7 +39,7 @@ pub struct NewInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
pub fn get_local(conn: &PgConnection) -> Option<Instance> {
|
pub fn get_local(conn: &Connection) -> Option<Instance> {
|
||||||
instances::table.filter(instances::local.eq(true))
|
instances::table.filter(instances::local.eq(true))
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.load::<Instance>(conn)
|
.load::<Instance>(conn)
|
||||||
@ -47,13 +47,13 @@ impl Instance {
|
|||||||
.into_iter().nth(0)
|
.into_iter().nth(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_remotes(conn: &PgConnection) -> Vec<Instance> {
|
pub fn get_remotes(conn: &Connection) -> Vec<Instance> {
|
||||||
instances::table.filter(instances::local.eq(false))
|
instances::table.filter(instances::local.eq(false))
|
||||||
.load::<Instance>(conn)
|
.load::<Instance>(conn)
|
||||||
.expect("Error loading remote instances infos")
|
.expect("Error loading remote instances infos")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn page(conn: &PgConnection, (min, max): (i32, i32)) -> Vec<Instance> {
|
pub fn page(conn: &Connection, (min, max): (i32, i32)) -> Vec<Instance> {
|
||||||
instances::table.order(instances::public_domain.asc())
|
instances::table.order(instances::public_domain.asc())
|
||||||
.offset(min.into())
|
.offset(min.into())
|
||||||
.limit((max - min).into())
|
.limit((max - min).into())
|
||||||
@ -61,7 +61,7 @@ impl Instance {
|
|||||||
.expect("Error loading a page of instances")
|
.expect("Error loading a page of instances")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_id(conn: &PgConnection) -> i32 {
|
pub fn local_id(conn: &Connection) -> i32 {
|
||||||
Instance::get_local(conn).unwrap().id
|
Instance::get_local(conn).unwrap().id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ impl Instance {
|
|||||||
get!(instances);
|
get!(instances);
|
||||||
find_by!(instances, find_by_domain, public_domain as String);
|
find_by!(instances, find_by_domain, public_domain as String);
|
||||||
|
|
||||||
pub fn toggle_block(&self, conn: &PgConnection) {
|
pub fn toggle_block(&self, conn: &Connection) {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(instances::blocked.eq(!self.blocked))
|
.set(instances::blocked.eq(!self.blocked))
|
||||||
.get_result::<Instance>(conn)
|
.get_result::<Instance>(conn)
|
||||||
@ -77,7 +77,7 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// id: AP object id
|
/// id: AP object id
|
||||||
pub fn is_blocked(conn: &PgConnection, id: String) -> bool {
|
pub fn is_blocked(conn: &Connection, id: String) -> bool {
|
||||||
for block in instances::table.filter(instances::blocked.eq(true))
|
for block in instances::table.filter(instances::blocked.eq(true))
|
||||||
.get_results::<Instance>(conn)
|
.get_results::<Instance>(conn)
|
||||||
.expect("Error listing blocked instances") {
|
.expect("Error listing blocked instances") {
|
||||||
@ -89,7 +89,7 @@ impl Instance {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_admin(&self, conn: &PgConnection) -> bool {
|
pub fn has_admin(&self, conn: &Connection) -> bool {
|
||||||
users::table.filter(users::instance_id.eq(self.id))
|
users::table.filter(users::instance_id.eq(self.id))
|
||||||
.filter(users::is_admin.eq(true))
|
.filter(users::is_admin.eq(true))
|
||||||
.load::<User>(conn)
|
.load::<User>(conn)
|
||||||
@ -97,7 +97,7 @@ impl Instance {
|
|||||||
.len() > 0
|
.len() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main_admin(&self, conn: &PgConnection) -> User {
|
pub fn main_admin(&self, conn: &Connection) -> User {
|
||||||
users::table.filter(users::instance_id.eq(self.id))
|
users::table.filter(users::instance_id.eq(self.id))
|
||||||
.filter(users::is_admin.eq(true))
|
.filter(users::is_admin.eq(true))
|
||||||
.limit(1)
|
.limit(1)
|
||||||
@ -115,7 +115,7 @@ impl Instance {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&self, conn: &PgConnection, name: String, open_registrations: bool, short_description: SafeString, long_description: SafeString) -> Instance {
|
pub fn update(&self, conn: &Connection, name: String, open_registrations: bool, short_description: SafeString, long_description: SafeString) -> Instance {
|
||||||
let (sd, _) = md_to_html(short_description.as_ref());
|
let (sd, _) = md_to_html(short_description.as_ref());
|
||||||
let (ld, _) = md_to_html(long_description.as_ref());
|
let (ld, _) = md_to_html(long_description.as_ref());
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
@ -130,7 +130,7 @@ impl Instance {
|
|||||||
.expect("Couldn't update instance")
|
.expect("Couldn't update instance")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count(conn: &PgConnection) -> i64 {
|
pub fn count(conn: &Connection) -> i64 {
|
||||||
instances::table.count().get_result(conn).expect("Couldn't count instances")
|
instances::table.count().get_result(conn).expect("Couldn't count instances")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![allow(proc_macro_derive_resolution_fallback)] // This can be removed after diesel-1.4
|
#![allow(proc_macro_derive_resolution_fallback)] // This can be removed after diesel-1.4
|
||||||
|
#![feature(crate_in_paths)]
|
||||||
|
|
||||||
extern crate activitypub;
|
extern crate activitypub;
|
||||||
extern crate ammonia;
|
extern crate ammonia;
|
||||||
@ -28,7 +29,7 @@ use std::env;
|
|||||||
macro_rules! find_by {
|
macro_rules! find_by {
|
||||||
($table:ident, $fn:ident, $($col:ident as $type:ident),+) => {
|
($table:ident, $fn:ident, $($col:ident as $type:ident),+) => {
|
||||||
/// Try to find a $table with a given $col
|
/// Try to find a $table with a given $col
|
||||||
pub fn $fn(conn: &PgConnection, $($col: $type),+) -> Option<Self> {
|
pub fn $fn(conn: &crate::Connection, $($col: $type),+) -> Option<Self> {
|
||||||
$table::table
|
$table::table
|
||||||
$(.filter($table::$col.eq($col)))+
|
$(.filter($table::$col.eq($col)))+
|
||||||
.limit(1)
|
.limit(1)
|
||||||
@ -42,7 +43,7 @@ macro_rules! find_by {
|
|||||||
macro_rules! list_by {
|
macro_rules! list_by {
|
||||||
($table:ident, $fn:ident, $($col:ident as $type:ident),+) => {
|
($table:ident, $fn:ident, $($col:ident as $type:ident),+) => {
|
||||||
/// Try to find a $table with a given $col
|
/// Try to find a $table with a given $col
|
||||||
pub fn $fn(conn: &PgConnection, $($col: $type),+) -> Vec<Self> {
|
pub fn $fn(conn: &crate::Connection, $($col: $type),+) -> Vec<Self> {
|
||||||
$table::table
|
$table::table
|
||||||
$(.filter($table::$col.eq($col)))+
|
$(.filter($table::$col.eq($col)))+
|
||||||
.load::<Self>(conn)
|
.load::<Self>(conn)
|
||||||
@ -53,7 +54,7 @@ macro_rules! list_by {
|
|||||||
|
|
||||||
macro_rules! get {
|
macro_rules! get {
|
||||||
($table:ident) => {
|
($table:ident) => {
|
||||||
pub fn get(conn: &PgConnection, id: i32) -> Option<Self> {
|
pub fn get(conn: &crate::Connection, id: i32) -> Option<Self> {
|
||||||
$table::table.filter($table::id.eq(id))
|
$table::table.filter($table::id.eq(id))
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.load::<Self>(conn)
|
.load::<Self>(conn)
|
||||||
@ -65,7 +66,7 @@ macro_rules! get {
|
|||||||
|
|
||||||
macro_rules! insert {
|
macro_rules! insert {
|
||||||
($table:ident, $from:ident) => {
|
($table:ident, $from:ident) => {
|
||||||
pub fn insert(conn: &PgConnection, new: $from) -> Self {
|
pub fn insert(conn: &crate::Connection, new: $from) -> Self {
|
||||||
diesel::insert_into($table::table)
|
diesel::insert_into($table::table)
|
||||||
.values(new)
|
.values(new)
|
||||||
.get_result(conn)
|
.get_result(conn)
|
||||||
@ -76,7 +77,7 @@ macro_rules! insert {
|
|||||||
|
|
||||||
macro_rules! update {
|
macro_rules! update {
|
||||||
($table:ident) => {
|
($table:ident) => {
|
||||||
pub fn update(&self, conn: &PgConnection) -> Self {
|
pub fn update(&self, conn: &crate::Connection) -> Self {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(self)
|
.set(self)
|
||||||
.get_result(conn)
|
.get_result(conn)
|
||||||
@ -104,6 +105,18 @@ pub fn ap_url(url: String) -> String {
|
|||||||
format!("{}://{}", scheme, url)
|
format!("{}://{}", scheme, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "postgres"), feature = "sqlite"))]
|
||||||
|
pub type SqlDateTime = chrono::NaiveDateTime;
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "postgres"), feature = "sqlite"))]
|
||||||
|
pub type Connection = diesel::SqliteConnection;
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
|
||||||
|
pub type SqlDateTime = chrono::NaiveDateTime;
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
|
||||||
|
pub type Connection = diesel::PgConnection;
|
||||||
|
|
||||||
pub mod admin;
|
pub mod admin;
|
||||||
pub mod blog_authors;
|
pub mod blog_authors;
|
||||||
pub mod blogs;
|
pub mod blogs;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use activitypub::activity;
|
use activitypub::activity;
|
||||||
use chrono;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
|
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods};
|
||||||
|
|
||||||
use plume_common::activity_pub::{
|
use plume_common::activity_pub::{
|
||||||
PUBLIC_VISIBILTY,
|
PUBLIC_VISIBILTY,
|
||||||
@ -8,6 +8,7 @@ use plume_common::activity_pub::{
|
|||||||
IntoId,
|
IntoId,
|
||||||
inbox::{FromActivity, Deletable, Notify}
|
inbox::{FromActivity, Deletable, Notify}
|
||||||
};
|
};
|
||||||
|
use Connection;
|
||||||
use notifications::*;
|
use notifications::*;
|
||||||
use posts::Post;
|
use posts::Post;
|
||||||
use users::User;
|
use users::User;
|
||||||
@ -18,7 +19,7 @@ pub struct Like {
|
|||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub user_id: i32,
|
pub user_id: i32,
|
||||||
pub post_id: i32,
|
pub post_id: i32,
|
||||||
pub creation_date: chrono::NaiveDateTime,
|
pub creation_date: NaiveDateTime,
|
||||||
pub ap_url: String
|
pub ap_url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ impl Like {
|
|||||||
find_by!(likes, find_by_ap_url, ap_url as String);
|
find_by!(likes, find_by_ap_url, ap_url as String);
|
||||||
find_by!(likes, find_by_user_on_post, user_id as i32, post_id as i32);
|
find_by!(likes, find_by_user_on_post, user_id as i32, post_id as i32);
|
||||||
|
|
||||||
pub fn update_ap_url(&self, conn: &PgConnection) {
|
pub fn update_ap_url(&self, conn: &Connection) {
|
||||||
if self.ap_url.len() == 0 {
|
if self.ap_url.len() == 0 {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(likes::ap_url.eq(format!(
|
.set(likes::ap_url.eq(format!(
|
||||||
@ -48,7 +49,7 @@ impl Like {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_activity(&self, conn: &PgConnection) -> activity::Like {
|
pub fn into_activity(&self, conn: &Connection) -> activity::Like {
|
||||||
let mut act = activity::Like::default();
|
let mut act = activity::Like::default();
|
||||||
act.like_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).expect("Like::into_activity: actor error");
|
act.like_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).expect("Like::into_activity: actor error");
|
||||||
act.like_props.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).expect("Like::into_activity: object error");
|
act.like_props.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).expect("Like::into_activity: object error");
|
||||||
@ -60,8 +61,8 @@ impl Like {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromActivity<activity::Like, PgConnection> for Like {
|
impl FromActivity<activity::Like, Connection> for Like {
|
||||||
fn from_activity(conn: &PgConnection, like: activity::Like, _actor: Id) -> Like {
|
fn from_activity(conn: &Connection, like: activity::Like, _actor: Id) -> Like {
|
||||||
let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string());
|
let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string());
|
||||||
let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string());
|
let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string());
|
||||||
let res = Like::insert(conn, NewLike {
|
let res = Like::insert(conn, NewLike {
|
||||||
@ -74,8 +75,8 @@ impl FromActivity<activity::Like, PgConnection> for Like {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Notify<PgConnection> for Like {
|
impl Notify<Connection> for Like {
|
||||||
fn notify(&self, conn: &PgConnection) {
|
fn notify(&self, conn: &Connection) {
|
||||||
let post = Post::get(conn, self.post_id).unwrap();
|
let post = Post::get(conn, self.post_id).unwrap();
|
||||||
for author in post.get_authors(conn) {
|
for author in post.get_authors(conn) {
|
||||||
Notification::insert(conn, NewNotification {
|
Notification::insert(conn, NewNotification {
|
||||||
@ -87,8 +88,8 @@ impl Notify<PgConnection> for Like {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deletable<PgConnection, activity::Undo> for Like {
|
impl Deletable<Connection, activity::Undo> for Like {
|
||||||
fn delete(&self, conn: &PgConnection) -> activity::Undo {
|
fn delete(&self, conn: &Connection) -> activity::Undo {
|
||||||
diesel::delete(self).execute(conn).unwrap();
|
diesel::delete(self).execute(conn).unwrap();
|
||||||
|
|
||||||
// delete associated notification if any
|
// delete associated notification if any
|
||||||
@ -106,7 +107,7 @@ impl Deletable<PgConnection, activity::Undo> for Like {
|
|||||||
act
|
act
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_id(id: String, conn: &PgConnection) {
|
fn delete_id(id: String, conn: &Connection) {
|
||||||
if let Some(like) = Like::find_by_ap_url(conn, id.into()) {
|
if let Some(like) = Like::find_by_ap_url(conn, id.into()) {
|
||||||
like.delete(conn);
|
like.delete(conn);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use diesel::{self, PgConnection, QueryDsl, ExpressionMethods, RunQueryDsl};
|
use diesel::{self, QueryDsl, ExpressionMethods, RunQueryDsl};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
use ap_url;
|
use {ap_url, Connection};
|
||||||
use instance::Instance;
|
use instance::Instance;
|
||||||
use schema::medias;
|
use schema::medias;
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ impl Media {
|
|||||||
get!(medias);
|
get!(medias);
|
||||||
list_by!(medias, for_user, owner_id as i32);
|
list_by!(medias, for_user, owner_id as i32);
|
||||||
|
|
||||||
pub fn to_json(&self, conn: &PgConnection) -> serde_json::Value {
|
pub fn to_json(&self, conn: &Connection) -> serde_json::Value {
|
||||||
let mut json = serde_json::to_value(self).unwrap();
|
let mut json = serde_json::to_value(self).unwrap();
|
||||||
let url = self.url(conn);
|
let url = self.url(conn);
|
||||||
let (preview, html, md) = match self.file_path.rsplitn(2, '.').next().unwrap() {
|
let (preview, html, md) = match self.file_path.rsplitn(2, '.').next().unwrap() {
|
||||||
@ -63,7 +63,7 @@ impl Media {
|
|||||||
json
|
json
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url(&self, conn: &PgConnection) -> String {
|
pub fn url(&self, conn: &Connection) -> String {
|
||||||
if self.is_remote {
|
if self.is_remote {
|
||||||
self.remote_url.clone().unwrap_or(String::new())
|
self.remote_url.clone().unwrap_or(String::new())
|
||||||
} else {
|
} else {
|
||||||
@ -71,12 +71,12 @@ impl Media {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(&self, conn: &PgConnection) {
|
pub fn delete(&self, conn: &Connection) {
|
||||||
fs::remove_file(self.file_path.as_str()).expect("Couldn't delete media from disk");
|
fs::remove_file(self.file_path.as_str()).expect("Couldn't delete media from disk");
|
||||||
diesel::delete(self).execute(conn).expect("Couldn't remove media from DB");
|
diesel::delete(self).execute(conn).expect("Couldn't remove media from DB");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_remote(conn: &PgConnection, url: String) -> Media {
|
pub fn save_remote(conn: &Connection, url: String) -> Media {
|
||||||
Media::insert(conn, NewMedia {
|
Media::insert(conn, NewMedia {
|
||||||
file_path: String::new(),
|
file_path: String::new(),
|
||||||
alt_text: String::new(),
|
alt_text: String::new(),
|
||||||
@ -88,7 +88,7 @@ impl Media {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_owner(&self, conn: &PgConnection, id: i32) {
|
pub fn set_owner(&self, conn: &Connection, id: i32) {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(medias::owner_id.eq(id))
|
.set(medias::owner_id.eq(id))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
@ -2,6 +2,7 @@ use activitypub::link;
|
|||||||
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
|
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
|
||||||
|
|
||||||
use plume_common::activity_pub::inbox::Notify;
|
use plume_common::activity_pub::inbox::Notify;
|
||||||
|
use Connection;
|
||||||
use comments::Comment;
|
use comments::Comment;
|
||||||
use notifications::*;
|
use notifications::*;
|
||||||
use posts::Post;
|
use posts::Post;
|
||||||
@ -34,26 +35,26 @@ impl Mention {
|
|||||||
list_by!(mentions, list_for_post, post_id as i32);
|
list_by!(mentions, list_for_post, post_id as i32);
|
||||||
list_by!(mentions, list_for_comment, comment_id as i32);
|
list_by!(mentions, list_for_comment, comment_id as i32);
|
||||||
|
|
||||||
pub fn get_mentioned(&self, conn: &PgConnection) -> Option<User> {
|
pub fn get_mentioned(&self, conn: &Connection) -> Option<User> {
|
||||||
User::get(conn, self.mentioned_id)
|
User::get(conn, self.mentioned_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_post(&self, conn: &PgConnection) -> Option<Post> {
|
pub fn get_post(&self, conn: &Connection) -> Option<Post> {
|
||||||
self.post_id.and_then(|id| Post::get(conn, id))
|
self.post_id.and_then(|id| Post::get(conn, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_comment(&self, conn: &PgConnection) -> Option<Comment> {
|
pub fn get_comment(&self, conn: &Connection) -> Option<Comment> {
|
||||||
self.comment_id.and_then(|id| Comment::get(conn, id))
|
self.comment_id.and_then(|id| Comment::get(conn, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_user(&self, conn: &PgConnection) -> Option<User> {
|
pub fn get_user(&self, conn: &Connection) -> Option<User> {
|
||||||
match self.get_post(conn) {
|
match self.get_post(conn) {
|
||||||
Some(p) => p.get_authors(conn).into_iter().next(),
|
Some(p) => p.get_authors(conn).into_iter().next(),
|
||||||
None => self.get_comment(conn).map(|c| c.get_author(conn))
|
None => self.get_comment(conn).map(|c| c.get_author(conn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_activity(conn: &PgConnection, ment: String) -> link::Mention {
|
pub fn build_activity(conn: &Connection, ment: String) -> link::Mention {
|
||||||
let user = User::find_by_fqn(conn, ment.clone());
|
let user = User::find_by_fqn(conn, ment.clone());
|
||||||
let mut mention = link::Mention::default();
|
let mut mention = link::Mention::default();
|
||||||
mention.link_props.set_href_string(user.clone().map(|u| u.ap_url).unwrap_or(String::new())).expect("Error setting mention's href");
|
mention.link_props.set_href_string(user.clone().map(|u| u.ap_url).unwrap_or(String::new())).expect("Error setting mention's href");
|
||||||
@ -61,7 +62,7 @@ impl Mention {
|
|||||||
mention
|
mention
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_activity(&self, conn: &PgConnection) -> link::Mention {
|
pub fn to_activity(&self, conn: &Connection) -> link::Mention {
|
||||||
let user = self.get_mentioned(conn);
|
let user = self.get_mentioned(conn);
|
||||||
let mut mention = link::Mention::default();
|
let mut mention = link::Mention::default();
|
||||||
mention.link_props.set_href_string(user.clone().map(|u| u.ap_url).unwrap_or(String::new())).expect("Error setting mention's href");
|
mention.link_props.set_href_string(user.clone().map(|u| u.ap_url).unwrap_or(String::new())).expect("Error setting mention's href");
|
||||||
@ -69,7 +70,7 @@ impl Mention {
|
|||||||
mention
|
mention
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_activity(conn: &PgConnection, ment: link::Mention, inside: i32, in_post: bool, notify: bool) -> Option<Self> {
|
pub fn from_activity(conn: &Connection, ment: link::Mention, inside: i32, in_post: bool, notify: bool) -> Option<Self> {
|
||||||
let ap_url = ment.link_props.href_string().ok()?;
|
let ap_url = ment.link_props.href_string().ok()?;
|
||||||
let mentioned = User::find_by_ap_url(conn, ap_url)?;
|
let mentioned = User::find_by_ap_url(conn, ap_url)?;
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ impl Mention {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Notify<PgConnection> for Mention {
|
impl Notify<PgConnection> for Mention {
|
||||||
fn notify(&self, conn: &PgConnection) {
|
fn notify(&self, conn: &Connection) {
|
||||||
self.get_mentioned(conn).map(|m| {
|
self.get_mentioned(conn).map(|m| {
|
||||||
Notification::insert(conn, NewNotification {
|
Notification::insert(conn, NewNotification {
|
||||||
kind: notification_kind::MENTION.to_string(),
|
kind: notification_kind::MENTION.to_string(),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use chrono::NaiveDateTime;
|
use diesel::{self, RunQueryDsl, QueryDsl, ExpressionMethods};
|
||||||
use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods};
|
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
|
use {Connection, SqlDateTime};
|
||||||
use comments::Comment;
|
use comments::Comment;
|
||||||
use follows::Follow;
|
use follows::Follow;
|
||||||
use likes::Like;
|
use likes::Like;
|
||||||
@ -23,7 +23,7 @@ pub mod notification_kind {
|
|||||||
pub struct Notification {
|
pub struct Notification {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub user_id: i32,
|
pub user_id: i32,
|
||||||
pub creation_date: NaiveDateTime,
|
pub creation_date: SqlDateTime,
|
||||||
pub kind: String,
|
pub kind: String,
|
||||||
pub object_id: i32
|
pub object_id: i32
|
||||||
}
|
}
|
||||||
@ -40,14 +40,14 @@ impl Notification {
|
|||||||
insert!(notifications, NewNotification);
|
insert!(notifications, NewNotification);
|
||||||
get!(notifications);
|
get!(notifications);
|
||||||
|
|
||||||
pub fn find_for_user(conn: &PgConnection, user: &User) -> Vec<Notification> {
|
pub fn find_for_user(conn: &Connection, user: &User) -> Vec<Notification> {
|
||||||
notifications::table.filter(notifications::user_id.eq(user.id))
|
notifications::table.filter(notifications::user_id.eq(user.id))
|
||||||
.order_by(notifications::creation_date.desc())
|
.order_by(notifications::creation_date.desc())
|
||||||
.load::<Notification>(conn)
|
.load::<Notification>(conn)
|
||||||
.expect("Couldn't load user notifications")
|
.expect("Couldn't load user notifications")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn page_for_user(conn: &PgConnection, user: &User, (min, max): (i32, i32)) -> Vec<Notification> {
|
pub fn page_for_user(conn: &Connection, user: &User, (min, max): (i32, i32)) -> Vec<Notification> {
|
||||||
notifications::table.filter(notifications::user_id.eq(user.id))
|
notifications::table.filter(notifications::user_id.eq(user.id))
|
||||||
.order_by(notifications::creation_date.desc())
|
.order_by(notifications::creation_date.desc())
|
||||||
.offset(min.into())
|
.offset(min.into())
|
||||||
@ -56,14 +56,14 @@ impl Notification {
|
|||||||
.expect("Couldn't load user notifications page")
|
.expect("Couldn't load user notifications page")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find<S: Into<String>>(conn: &PgConnection, kind: S, obj: i32) -> Option<Notification> {
|
pub fn find<S: Into<String>>(conn: &Connection, kind: S, obj: i32) -> Option<Notification> {
|
||||||
notifications::table.filter(notifications::kind.eq(kind.into()))
|
notifications::table.filter(notifications::kind.eq(kind.into()))
|
||||||
.filter(notifications::object_id.eq(obj))
|
.filter(notifications::object_id.eq(obj))
|
||||||
.get_result::<Notification>(conn)
|
.get_result::<Notification>(conn)
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_json(&self, conn: &PgConnection) -> serde_json::Value {
|
pub fn to_json(&self, conn: &Connection) -> serde_json::Value {
|
||||||
let mut json = json!(self);
|
let mut json = json!(self);
|
||||||
json["object"] = json!(match self.kind.as_ref() {
|
json["object"] = json!(match self.kind.as_ref() {
|
||||||
notification_kind::COMMENT => Comment::get(conn, self.object_id).map(|comment|
|
notification_kind::COMMENT => Comment::get(conn, self.object_id).map(|comment|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
|
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods};
|
||||||
|
|
||||||
use posts::Post;
|
use posts::Post;
|
||||||
use users::User;
|
use users::User;
|
||||||
|
@ -5,7 +5,7 @@ use activitypub::{
|
|||||||
};
|
};
|
||||||
use canapi::{Error, Provider};
|
use canapi::{Error, Provider};
|
||||||
use chrono::{NaiveDateTime, TimeZone, Utc};
|
use chrono::{NaiveDateTime, TimeZone, Utc};
|
||||||
use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, BelongingToDsl, dsl::any};
|
use diesel::{self, RunQueryDsl, QueryDsl, ExpressionMethods, BelongingToDsl, dsl::any};
|
||||||
use heck::KebabCase;
|
use heck::KebabCase;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ use plume_common::activity_pub::{
|
|||||||
PUBLIC_VISIBILTY, Id, IntoId,
|
PUBLIC_VISIBILTY, Id, IntoId,
|
||||||
inbox::{Deletable, FromActivity}
|
inbox::{Deletable, FromActivity}
|
||||||
};
|
};
|
||||||
use {BASE_URL, ap_url};
|
use {BASE_URL, ap_url, Connection, SqlDateTime};
|
||||||
use blogs::Blog;
|
use blogs::Blog;
|
||||||
use instance::Instance;
|
use instance::Instance;
|
||||||
use likes::Like;
|
use likes::Like;
|
||||||
@ -36,7 +36,7 @@ pub struct Post {
|
|||||||
pub content: SafeString,
|
pub content: SafeString,
|
||||||
pub published: bool,
|
pub published: bool,
|
||||||
pub license: String,
|
pub license: String,
|
||||||
pub creation_date: NaiveDateTime,
|
pub creation_date: SqlDateTime,
|
||||||
pub ap_url: String,
|
pub ap_url: String,
|
||||||
pub subtitle: String,
|
pub subtitle: String,
|
||||||
pub source: String,
|
pub source: String,
|
||||||
@ -112,7 +112,7 @@ impl Post {
|
|||||||
find_by!(posts, find_by_slug, slug as String, blog_id as i32);
|
find_by!(posts, find_by_slug, slug as String, blog_id as i32);
|
||||||
find_by!(posts, find_by_ap_url, ap_url as String);
|
find_by!(posts, find_by_ap_url, ap_url as String);
|
||||||
|
|
||||||
pub fn list_by_tag(conn: &PgConnection, tag: String, (min, max): (i32, i32)) -> Vec<Post> {
|
pub fn list_by_tag(conn: &Connection, tag: String, (min, max): (i32, i32)) -> Vec<Post> {
|
||||||
use schema::tags;
|
use schema::tags;
|
||||||
|
|
||||||
let ids = tags::table.filter(tags::tag.eq(tag)).select(tags::post_id);
|
let ids = tags::table.filter(tags::tag.eq(tag)).select(tags::post_id);
|
||||||
@ -125,7 +125,7 @@ impl Post {
|
|||||||
.expect("Error loading posts by tag")
|
.expect("Error loading posts by tag")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count_for_tag(conn: &PgConnection, tag: String) -> i64 {
|
pub fn count_for_tag(conn: &Connection, tag: String) -> i64 {
|
||||||
use schema::tags;
|
use schema::tags;
|
||||||
let ids = tags::table.filter(tags::tag.eq(tag)).select(tags::post_id);
|
let ids = tags::table.filter(tags::tag.eq(tag)).select(tags::post_id);
|
||||||
posts::table.filter(posts::id.eq(any(ids)))
|
posts::table.filter(posts::id.eq(any(ids)))
|
||||||
@ -135,7 +135,7 @@ impl Post {
|
|||||||
.expect("Error counting posts by tag")
|
.expect("Error counting posts by tag")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count_local(conn: &PgConnection) -> usize {
|
pub fn count_local(conn: &Connection) -> usize {
|
||||||
use schema::post_authors;
|
use schema::post_authors;
|
||||||
use schema::users;
|
use schema::users;
|
||||||
let local_authors = users::table.filter(users::instance_id.eq(Instance::local_id(conn))).select(users::id);
|
let local_authors = users::table.filter(users::instance_id.eq(Instance::local_id(conn))).select(users::id);
|
||||||
@ -147,11 +147,11 @@ impl Post {
|
|||||||
.len()
|
.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count(conn: &PgConnection) -> i64 {
|
pub fn count(conn: &Connection) -> i64 {
|
||||||
posts::table.filter(posts::published.eq(true)).count().get_result(conn).expect("Couldn't count posts")
|
posts::table.filter(posts::published.eq(true)).count().get_result(conn).expect("Couldn't count posts")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_recents(conn: &PgConnection, limit: i64) -> Vec<Post> {
|
pub fn get_recents(conn: &Connection, limit: i64) -> Vec<Post> {
|
||||||
posts::table.order(posts::creation_date.desc())
|
posts::table.order(posts::creation_date.desc())
|
||||||
.filter(posts::published.eq(true))
|
.filter(posts::published.eq(true))
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
@ -159,7 +159,7 @@ impl Post {
|
|||||||
.expect("Error loading recent posts")
|
.expect("Error loading recent posts")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_recents_for_author(conn: &PgConnection, author: &User, limit: i64) -> Vec<Post> {
|
pub fn get_recents_for_author(conn: &Connection, author: &User, limit: i64) -> Vec<Post> {
|
||||||
use schema::post_authors;
|
use schema::post_authors;
|
||||||
|
|
||||||
let posts = PostAuthor::belonging_to(author).select(post_authors::post_id);
|
let posts = PostAuthor::belonging_to(author).select(post_authors::post_id);
|
||||||
@ -171,7 +171,7 @@ impl Post {
|
|||||||
.expect("Error loading recent posts for author")
|
.expect("Error loading recent posts for author")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_recents_for_blog(conn: &PgConnection, blog: &Blog, limit: i64) -> Vec<Post> {
|
pub fn get_recents_for_blog(conn: &Connection, blog: &Blog, limit: i64) -> Vec<Post> {
|
||||||
posts::table.filter(posts::blog_id.eq(blog.id))
|
posts::table.filter(posts::blog_id.eq(blog.id))
|
||||||
.filter(posts::published.eq(true))
|
.filter(posts::published.eq(true))
|
||||||
.order(posts::creation_date.desc())
|
.order(posts::creation_date.desc())
|
||||||
@ -180,14 +180,14 @@ impl Post {
|
|||||||
.expect("Error loading recent posts for blog")
|
.expect("Error loading recent posts for blog")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_for_blog(conn: &PgConnection, blog:&Blog) -> Vec<Post> {
|
pub fn get_for_blog(conn: &Connection, blog:&Blog) -> Vec<Post> {
|
||||||
posts::table.filter(posts::blog_id.eq(blog.id))
|
posts::table.filter(posts::blog_id.eq(blog.id))
|
||||||
.filter(posts::published.eq(true))
|
.filter(posts::published.eq(true))
|
||||||
.load::<Post>(conn)
|
.load::<Post>(conn)
|
||||||
.expect("Error loading posts for blog")
|
.expect("Error loading posts for blog")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blog_page(conn: &PgConnection, blog: &Blog, (min, max): (i32, i32)) -> Vec<Post> {
|
pub fn blog_page(conn: &Connection, blog: &Blog, (min, max): (i32, i32)) -> Vec<Post> {
|
||||||
posts::table.filter(posts::blog_id.eq(blog.id))
|
posts::table.filter(posts::blog_id.eq(blog.id))
|
||||||
.filter(posts::published.eq(true))
|
.filter(posts::published.eq(true))
|
||||||
.order(posts::creation_date.desc())
|
.order(posts::creation_date.desc())
|
||||||
@ -198,7 +198,7 @@ impl Post {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Give a page of all the recent posts known to this instance (= federated timeline)
|
/// Give a page of all the recent posts known to this instance (= federated timeline)
|
||||||
pub fn get_recents_page(conn: &PgConnection, (min, max): (i32, i32)) -> Vec<Post> {
|
pub fn get_recents_page(conn: &Connection, (min, max): (i32, i32)) -> Vec<Post> {
|
||||||
posts::table.order(posts::creation_date.desc())
|
posts::table.order(posts::creation_date.desc())
|
||||||
.filter(posts::published.eq(true))
|
.filter(posts::published.eq(true))
|
||||||
.offset(min.into())
|
.offset(min.into())
|
||||||
@ -208,7 +208,7 @@ impl Post {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Give a page of posts from a specific instance
|
/// Give a page of posts from a specific instance
|
||||||
pub fn get_instance_page(conn: &PgConnection, instance_id: i32, (min, max): (i32, i32)) -> Vec<Post> {
|
pub fn get_instance_page(conn: &Connection, instance_id: i32, (min, max): (i32, i32)) -> Vec<Post> {
|
||||||
use schema::blogs;
|
use schema::blogs;
|
||||||
|
|
||||||
let blog_ids = blogs::table.filter(blogs::instance_id.eq(instance_id)).select(blogs::id);
|
let blog_ids = blogs::table.filter(blogs::instance_id.eq(instance_id)).select(blogs::id);
|
||||||
@ -223,7 +223,7 @@ impl Post {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Give a page of customized user feed, based on a list of followed users
|
/// Give a page of customized user feed, based on a list of followed users
|
||||||
pub fn user_feed_page(conn: &PgConnection, followed: Vec<i32>, (min, max): (i32, i32)) -> Vec<Post> {
|
pub fn user_feed_page(conn: &Connection, followed: Vec<i32>, (min, max): (i32, i32)) -> Vec<Post> {
|
||||||
use schema::post_authors;
|
use schema::post_authors;
|
||||||
let post_ids = post_authors::table.filter(post_authors::author_id.eq(any(followed)))
|
let post_ids = post_authors::table.filter(post_authors::author_id.eq(any(followed)))
|
||||||
.select(post_authors::post_id);
|
.select(post_authors::post_id);
|
||||||
@ -237,7 +237,7 @@ impl Post {
|
|||||||
.expect("Error loading user feed page")
|
.expect("Error loading user feed page")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drafts_by_author(conn: &PgConnection, author: &User) -> Vec<Post> {
|
pub fn drafts_by_author(conn: &Connection, author: &User) -> Vec<Post> {
|
||||||
use schema::post_authors;
|
use schema::post_authors;
|
||||||
|
|
||||||
let posts = PostAuthor::belonging_to(author).select(post_authors::post_id);
|
let posts = PostAuthor::belonging_to(author).select(post_authors::post_id);
|
||||||
@ -248,14 +248,14 @@ impl Post {
|
|||||||
.expect("Error listing drafts")
|
.expect("Error listing drafts")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_authors(&self, conn: &PgConnection) -> Vec<User> {
|
pub fn get_authors(&self, conn: &Connection) -> Vec<User> {
|
||||||
use schema::users;
|
use schema::users;
|
||||||
use schema::post_authors;
|
use schema::post_authors;
|
||||||
let author_list = PostAuthor::belonging_to(self).select(post_authors::author_id);
|
let author_list = PostAuthor::belonging_to(self).select(post_authors::author_id);
|
||||||
users::table.filter(users::id.eq(any(author_list))).load::<User>(conn).unwrap()
|
users::table.filter(users::id.eq(any(author_list))).load::<User>(conn).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_blog(&self, conn: &PgConnection) -> Blog {
|
pub fn get_blog(&self, conn: &Connection) -> Blog {
|
||||||
use schema::blogs;
|
use schema::blogs;
|
||||||
blogs::table.filter(blogs::id.eq(self.blog_id))
|
blogs::table.filter(blogs::id.eq(self.blog_id))
|
||||||
.limit(1)
|
.limit(1)
|
||||||
@ -264,21 +264,21 @@ impl Post {
|
|||||||
.into_iter().nth(0).unwrap()
|
.into_iter().nth(0).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_likes(&self, conn: &PgConnection) -> Vec<Like> {
|
pub fn get_likes(&self, conn: &Connection) -> Vec<Like> {
|
||||||
use schema::likes;
|
use schema::likes;
|
||||||
likes::table.filter(likes::post_id.eq(self.id))
|
likes::table.filter(likes::post_id.eq(self.id))
|
||||||
.load::<Like>(conn)
|
.load::<Like>(conn)
|
||||||
.expect("Couldn't load likes associted to post")
|
.expect("Couldn't load likes associted to post")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_reshares(&self, conn: &PgConnection) -> Vec<Reshare> {
|
pub fn get_reshares(&self, conn: &Connection) -> Vec<Reshare> {
|
||||||
use schema::reshares;
|
use schema::reshares;
|
||||||
reshares::table.filter(reshares::post_id.eq(self.id))
|
reshares::table.filter(reshares::post_id.eq(self.id))
|
||||||
.load::<Reshare>(conn)
|
.load::<Reshare>(conn)
|
||||||
.expect("Couldn't load reshares associted to post")
|
.expect("Couldn't load reshares associted to post")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_ap_url(&self, conn: &PgConnection) -> Post {
|
pub fn update_ap_url(&self, conn: &Connection) -> Post {
|
||||||
if self.ap_url.len() == 0 {
|
if self.ap_url.len() == 0 {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(posts::ap_url.eq(self.compute_id(conn)))
|
.set(posts::ap_url.eq(self.compute_id(conn)))
|
||||||
@ -288,7 +288,7 @@ impl Post {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_receivers_urls(&self, conn: &PgConnection) -> Vec<String> {
|
pub fn get_receivers_urls(&self, conn: &Connection) -> Vec<String> {
|
||||||
let followers = self.get_authors(conn).into_iter().map(|a| a.get_followers(conn)).collect::<Vec<Vec<User>>>();
|
let followers = self.get_authors(conn).into_iter().map(|a| a.get_followers(conn)).collect::<Vec<Vec<User>>>();
|
||||||
let to = followers.into_iter().fold(vec![], |mut acc, f| {
|
let to = followers.into_iter().fold(vec![], |mut acc, f| {
|
||||||
for x in f {
|
for x in f {
|
||||||
@ -299,7 +299,7 @@ impl Post {
|
|||||||
to
|
to
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_activity(&self, conn: &PgConnection) -> Article {
|
pub fn into_activity(&self, conn: &Connection) -> Article {
|
||||||
let mut to = self.get_receivers_urls(conn);
|
let mut to = self.get_receivers_urls(conn);
|
||||||
to.push(PUBLIC_VISIBILTY.to_string());
|
to.push(PUBLIC_VISIBILTY.to_string());
|
||||||
|
|
||||||
@ -328,7 +328,7 @@ impl Post {
|
|||||||
article
|
article
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_activity(&self, conn: &PgConnection) -> Create {
|
pub fn create_activity(&self, conn: &Connection) -> Create {
|
||||||
let article = self.into_activity(conn);
|
let article = self.into_activity(conn);
|
||||||
let mut act = Create::default();
|
let mut act = Create::default();
|
||||||
act.object_props.set_id_string(format!("{}activity", self.ap_url)).expect("Post::create_activity: id error");
|
act.object_props.set_id_string(format!("{}activity", self.ap_url)).expect("Post::create_activity: id error");
|
||||||
@ -341,7 +341,7 @@ impl Post {
|
|||||||
act
|
act
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_activity(&self, conn: &PgConnection) -> Update {
|
pub fn update_activity(&self, conn: &Connection) -> Update {
|
||||||
let article = self.into_activity(conn);
|
let article = self.into_activity(conn);
|
||||||
let mut act = Update::default();
|
let mut act = Update::default();
|
||||||
act.object_props.set_id_string(format!("{}/update-{}", self.ap_url, Utc::now().timestamp())).expect("Post::update_activity: id error");
|
act.object_props.set_id_string(format!("{}/update-{}", self.ap_url, Utc::now().timestamp())).expect("Post::update_activity: id error");
|
||||||
@ -354,7 +354,7 @@ impl Post {
|
|||||||
act
|
act
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_update(conn: &PgConnection, updated: Article) {
|
pub fn handle_update(conn: &Connection, updated: Article) {
|
||||||
let id = updated.object_props.id_string().expect("Post::handle_update: id error");
|
let id = updated.object_props.id_string().expect("Post::handle_update: id error");
|
||||||
let mut post = Post::find_by_ap_url(conn, id).unwrap();
|
let mut post = Post::find_by_ap_url(conn, id).unwrap();
|
||||||
|
|
||||||
@ -382,7 +382,7 @@ impl Post {
|
|||||||
post.update(conn);
|
post.update(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_json(&self, conn: &PgConnection) -> serde_json::Value {
|
pub fn to_json(&self, conn: &Connection) -> serde_json::Value {
|
||||||
let blog = self.get_blog(conn);
|
let blog = self.get_blog(conn);
|
||||||
json!({
|
json!({
|
||||||
"post": self,
|
"post": self,
|
||||||
@ -394,13 +394,13 @@ impl Post {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_id(&self, conn: &PgConnection) -> String {
|
pub fn compute_id(&self, conn: &Connection) -> String {
|
||||||
ap_url(format!("{}/~/{}/{}/", BASE_URL.as_str(), self.get_blog(conn).get_fqn(conn), self.slug))
|
ap_url(format!("{}/~/{}/{}/", BASE_URL.as_str(), self.get_blog(conn).get_fqn(conn), self.slug))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromActivity<Article, PgConnection> for Post {
|
impl FromActivity<Article, Connection> for Post {
|
||||||
fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post {
|
fn from_activity(conn: &Connection, article: Article, _actor: Id) -> Post {
|
||||||
if let Some(post) = Post::find_by_ap_url(conn, article.object_props.id_string().unwrap_or(String::new())) {
|
if let Some(post) = Post::find_by_ap_url(conn, article.object_props.id_string().unwrap_or(String::new())) {
|
||||||
post
|
post
|
||||||
} else {
|
} else {
|
||||||
@ -457,8 +457,8 @@ impl FromActivity<Article, PgConnection> for Post {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deletable<PgConnection, Delete> for Post {
|
impl Deletable<Connection, Delete> for Post {
|
||||||
fn delete(&self, conn: &PgConnection) -> Delete {
|
fn delete(&self, conn: &Connection) -> Delete {
|
||||||
let mut act = Delete::default();
|
let mut act = Delete::default();
|
||||||
act.delete_props.set_actor_link(self.get_authors(conn)[0].clone().into_id()).expect("Post::delete: actor error");
|
act.delete_props.set_actor_link(self.get_authors(conn)[0].clone().into_id()).expect("Post::delete: actor error");
|
||||||
|
|
||||||
@ -473,7 +473,7 @@ impl Deletable<PgConnection, Delete> for Post {
|
|||||||
act
|
act
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_id(id: String, conn: &PgConnection) {
|
fn delete_id(id: String, conn: &Connection) {
|
||||||
Post::find_by_ap_url(conn, id).map(|p| p.delete(conn));
|
Post::find_by_ap_url(conn, id).map(|p| p.delete(conn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use activitypub::activity::{Announce, Undo};
|
use activitypub::activity::{Announce, Undo};
|
||||||
use chrono::NaiveDateTime;
|
|
||||||
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
|
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
|
||||||
|
|
||||||
use plume_common::activity_pub::{Id, IntoId, inbox::{FromActivity, Notify, Deletable}, PUBLIC_VISIBILTY};
|
use plume_common::activity_pub::{Id, IntoId, inbox::{FromActivity, Notify, Deletable}, PUBLIC_VISIBILTY};
|
||||||
|
use {Connection, SqlDateTime};
|
||||||
use notifications::*;
|
use notifications::*;
|
||||||
use posts::Post;
|
use posts::Post;
|
||||||
use users::User;
|
use users::User;
|
||||||
@ -14,7 +14,7 @@ pub struct Reshare {
|
|||||||
pub user_id: i32,
|
pub user_id: i32,
|
||||||
pub post_id: i32,
|
pub post_id: i32,
|
||||||
pub ap_url: String,
|
pub ap_url: String,
|
||||||
pub creation_date: NaiveDateTime
|
pub creation_date: SqlDateTime
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable)]
|
#[derive(Insertable)]
|
||||||
@ -31,7 +31,7 @@ impl Reshare {
|
|||||||
find_by!(reshares, find_by_ap_url, ap_url as String);
|
find_by!(reshares, find_by_ap_url, ap_url as String);
|
||||||
find_by!(reshares, find_by_user_on_post, user_id as i32, post_id as i32);
|
find_by!(reshares, find_by_user_on_post, user_id as i32, post_id as i32);
|
||||||
|
|
||||||
pub fn update_ap_url(&self, conn: &PgConnection) {
|
pub fn update_ap_url(&self, conn: &Connection) {
|
||||||
if self.ap_url.len() == 0 {
|
if self.ap_url.len() == 0 {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(reshares::ap_url.eq(format!(
|
.set(reshares::ap_url.eq(format!(
|
||||||
@ -43,7 +43,7 @@ impl Reshare {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_recents_for_author(conn: &PgConnection, user: &User, limit: i64) -> Vec<Reshare> {
|
pub fn get_recents_for_author(conn: &Connection, user: &User, limit: i64) -> Vec<Reshare> {
|
||||||
reshares::table.filter(reshares::user_id.eq(user.id))
|
reshares::table.filter(reshares::user_id.eq(user.id))
|
||||||
.order(reshares::creation_date.desc())
|
.order(reshares::creation_date.desc())
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
@ -51,15 +51,15 @@ impl Reshare {
|
|||||||
.expect("Error loading recent reshares for user")
|
.expect("Error loading recent reshares for user")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_post(&self, conn: &PgConnection) -> Option<Post> {
|
pub fn get_post(&self, conn: &Connection) -> Option<Post> {
|
||||||
Post::get(conn, self.post_id)
|
Post::get(conn, self.post_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_user(&self, conn: &PgConnection) -> Option<User> {
|
pub fn get_user(&self, conn: &Connection) -> Option<User> {
|
||||||
User::get(conn, self.user_id)
|
User::get(conn, self.user_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_activity(&self, conn: &PgConnection) -> Announce {
|
pub fn into_activity(&self, conn: &Connection) -> Announce {
|
||||||
let mut act = Announce::default();
|
let mut act = Announce::default();
|
||||||
act.announce_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap();
|
act.announce_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap();
|
||||||
act.announce_props.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).unwrap();
|
act.announce_props.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).unwrap();
|
||||||
@ -72,7 +72,7 @@ impl Reshare {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromActivity<Announce, PgConnection> for Reshare {
|
impl FromActivity<Announce, PgConnection> for Reshare {
|
||||||
fn from_activity(conn: &PgConnection, announce: Announce, _actor: Id) -> Reshare {
|
fn from_activity(conn: &Connection, announce: Announce, _actor: Id) -> Reshare {
|
||||||
let user = User::from_url(conn, announce.announce_props.actor_link::<Id>().expect("Reshare::from_activity: actor error").into());
|
let user = User::from_url(conn, announce.announce_props.actor_link::<Id>().expect("Reshare::from_activity: actor error").into());
|
||||||
let post = Post::find_by_ap_url(conn, announce.announce_props.object_link::<Id>().expect("Reshare::from_activity: object error").into());
|
let post = Post::find_by_ap_url(conn, announce.announce_props.object_link::<Id>().expect("Reshare::from_activity: object error").into());
|
||||||
let reshare = Reshare::insert(conn, NewReshare {
|
let reshare = Reshare::insert(conn, NewReshare {
|
||||||
@ -86,7 +86,7 @@ impl FromActivity<Announce, PgConnection> for Reshare {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Notify<PgConnection> for Reshare {
|
impl Notify<PgConnection> for Reshare {
|
||||||
fn notify(&self, conn: &PgConnection) {
|
fn notify(&self, conn: &Connection) {
|
||||||
let post = self.get_post(conn).unwrap();
|
let post = self.get_post(conn).unwrap();
|
||||||
for author in post.get_authors(conn) {
|
for author in post.get_authors(conn) {
|
||||||
Notification::insert(conn, NewNotification {
|
Notification::insert(conn, NewNotification {
|
||||||
@ -99,7 +99,7 @@ impl Notify<PgConnection> for Reshare {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Deletable<PgConnection, Undo> for Reshare {
|
impl Deletable<PgConnection, Undo> for Reshare {
|
||||||
fn delete(&self, conn: &PgConnection) -> Undo {
|
fn delete(&self, conn: &Connection) -> Undo {
|
||||||
diesel::delete(self).execute(conn).unwrap();
|
diesel::delete(self).execute(conn).unwrap();
|
||||||
|
|
||||||
// delete associated notification if any
|
// delete associated notification if any
|
||||||
@ -117,7 +117,7 @@ impl Deletable<PgConnection, Undo> for Reshare {
|
|||||||
act
|
act
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_id(id: String, conn: &PgConnection) {
|
fn delete_id(id: String, conn: &Connection) {
|
||||||
if let Some(reshare) = Reshare::find_by_ap_url(conn, id) {
|
if let Some(reshare) = Reshare::find_by_ap_url(conn, id) {
|
||||||
reshare.delete(conn);
|
reshare.delete(conn);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
table! {
|
table! {
|
||||||
blog_authors (id) {
|
blog_authors (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
blog_id -> Integer,
|
blog_id -> Int4,
|
||||||
author_id -> Integer,
|
author_id -> Int4,
|
||||||
is_owner -> Bool,
|
is_owner -> Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
blogs (id) {
|
blogs (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
actor_id -> Text,
|
actor_id -> Varchar,
|
||||||
title -> Text,
|
title -> Varchar,
|
||||||
summary -> Text,
|
summary -> Text,
|
||||||
outbox_url -> Text,
|
outbox_url -> Varchar,
|
||||||
inbox_url -> Text,
|
inbox_url -> Varchar,
|
||||||
instance_id -> Integer,
|
instance_id -> Int4,
|
||||||
creation_date -> Timestamp,
|
creation_date -> Timestamp,
|
||||||
ap_url -> Text,
|
ap_url -> Text,
|
||||||
private_key -> Nullable<Text>,
|
private_key -> Nullable<Text>,
|
||||||
@ -25,13 +25,13 @@ table! {
|
|||||||
|
|
||||||
table! {
|
table! {
|
||||||
comments (id) {
|
comments (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
content -> Text,
|
content -> Text,
|
||||||
in_response_to_id -> Nullable<Integer>,
|
in_response_to_id -> Nullable<Int4>,
|
||||||
post_id -> Integer,
|
post_id -> Int4,
|
||||||
author_id -> Integer,
|
author_id -> Int4,
|
||||||
creation_date -> Timestamp,
|
creation_date -> Timestamp,
|
||||||
ap_url -> Nullable<Text>,
|
ap_url -> Nullable<Varchar>,
|
||||||
sensitive -> Bool,
|
sensitive -> Bool,
|
||||||
spoiler_text -> Text,
|
spoiler_text -> Text,
|
||||||
}
|
}
|
||||||
@ -39,18 +39,18 @@ table! {
|
|||||||
|
|
||||||
table! {
|
table! {
|
||||||
follows (id) {
|
follows (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
follower_id -> Integer,
|
follower_id -> Int4,
|
||||||
following_id -> Integer,
|
following_id -> Int4,
|
||||||
ap_url -> Text,
|
ap_url -> Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
instances (id) {
|
instances (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
public_domain -> Text,
|
public_domain -> Varchar,
|
||||||
name -> Text,
|
name -> Varchar,
|
||||||
local -> Bool,
|
local -> Bool,
|
||||||
blocked -> Bool,
|
blocked -> Bool,
|
||||||
creation_date -> Timestamp,
|
creation_date -> Timestamp,
|
||||||
@ -58,73 +58,73 @@ table! {
|
|||||||
short_description -> Text,
|
short_description -> Text,
|
||||||
long_description -> Text,
|
long_description -> Text,
|
||||||
default_license -> Text,
|
default_license -> Text,
|
||||||
long_description_html -> Text,
|
long_description_html -> Varchar,
|
||||||
short_description_html -> Text,
|
short_description_html -> Varchar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
likes (id) {
|
likes (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
user_id -> Integer,
|
user_id -> Int4,
|
||||||
post_id -> Integer,
|
post_id -> Int4,
|
||||||
ap_url -> Text,
|
|
||||||
creation_date -> Timestamp,
|
creation_date -> Timestamp,
|
||||||
|
ap_url -> Varchar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
medias (id) {
|
medias (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
file_path -> Text,
|
file_path -> Text,
|
||||||
alt_text -> Text,
|
alt_text -> Text,
|
||||||
is_remote -> Bool,
|
is_remote -> Bool,
|
||||||
remote_url -> Nullable<Text>,
|
remote_url -> Nullable<Text>,
|
||||||
sensitive -> Bool,
|
sensitive -> Bool,
|
||||||
content_warning -> Nullable<Text>,
|
content_warning -> Nullable<Text>,
|
||||||
owner_id -> Integer,
|
owner_id -> Int4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
mentions (id) {
|
mentions (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
mentioned_id -> Integer,
|
mentioned_id -> Int4,
|
||||||
post_id -> Nullable<Integer>,
|
post_id -> Nullable<Int4>,
|
||||||
comment_id -> Nullable<Integer>,
|
comment_id -> Nullable<Int4>,
|
||||||
ap_url -> Text,
|
ap_url -> Varchar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
notifications (id) {
|
notifications (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
user_id -> Integer,
|
user_id -> Int4,
|
||||||
creation_date -> Timestamp,
|
creation_date -> Timestamp,
|
||||||
kind -> Text,
|
kind -> Varchar,
|
||||||
object_id -> Integer,
|
object_id -> Int4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
post_authors (id) {
|
post_authors (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
post_id -> Integer,
|
post_id -> Int4,
|
||||||
author_id -> Integer,
|
author_id -> Int4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
posts (id) {
|
posts (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
blog_id -> Integer,
|
blog_id -> Int4,
|
||||||
slug -> Text,
|
slug -> Varchar,
|
||||||
title -> Text,
|
title -> Varchar,
|
||||||
content -> Text,
|
content -> Text,
|
||||||
published -> Bool,
|
published -> Bool,
|
||||||
license -> Text,
|
license -> Varchar,
|
||||||
creation_date -> Timestamp,
|
creation_date -> Timestamp,
|
||||||
ap_url -> Text,
|
ap_url -> Varchar,
|
||||||
subtitle -> Text,
|
subtitle -> Text,
|
||||||
source -> Text,
|
source -> Text,
|
||||||
}
|
}
|
||||||
@ -132,42 +132,42 @@ table! {
|
|||||||
|
|
||||||
table! {
|
table! {
|
||||||
reshares (id) {
|
reshares (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
user_id -> Integer,
|
user_id -> Int4,
|
||||||
post_id -> Integer,
|
post_id -> Int4,
|
||||||
ap_url -> Text,
|
ap_url -> Varchar,
|
||||||
creation_date -> Timestamp,
|
creation_date -> Timestamp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
tags (id) {
|
tags (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
tag -> Text,
|
tag -> Text,
|
||||||
is_hastag -> Bool,
|
is_hastag -> Bool,
|
||||||
post_id -> Integer,
|
post_id -> Int4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
users (id) {
|
users (id) {
|
||||||
id -> Integer,
|
id -> Int4,
|
||||||
username -> Text,
|
username -> Varchar,
|
||||||
display_name -> Text,
|
display_name -> Varchar,
|
||||||
outbox_url -> Text,
|
outbox_url -> Varchar,
|
||||||
inbox_url -> Text,
|
inbox_url -> Varchar,
|
||||||
is_admin -> Bool,
|
is_admin -> Bool,
|
||||||
summary -> Text,
|
summary -> Text,
|
||||||
email -> Nullable<Text>,
|
email -> Nullable<Text>,
|
||||||
hashed_password -> Nullable<Text>,
|
hashed_password -> Nullable<Text>,
|
||||||
instance_id -> Integer,
|
instance_id -> Int4,
|
||||||
creation_date -> Timestamp,
|
creation_date -> Timestamp,
|
||||||
ap_url -> Text,
|
ap_url -> Text,
|
||||||
private_key -> Nullable<Text>,
|
private_key -> Nullable<Text>,
|
||||||
public_key -> Text,
|
public_key -> Text,
|
||||||
shared_inbox_url -> Nullable<Text>,
|
shared_inbox_url -> Nullable<Varchar>,
|
||||||
followers_endpoint -> Text,
|
followers_endpoint -> Varchar,
|
||||||
avatar_id -> Nullable<Integer>,
|
avatar_id -> Nullable<Int4>,
|
||||||
last_fetched_date -> Timestamp,
|
last_fetched_date -> Timestamp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use diesel::{self, PgConnection, ExpressionMethods, RunQueryDsl, QueryDsl};
|
use diesel::{self, ExpressionMethods, RunQueryDsl, QueryDsl};
|
||||||
|
|
||||||
use plume_common::activity_pub::Hashtag;
|
use plume_common::activity_pub::Hashtag;
|
||||||
use ap_url;
|
use {ap_url, Connection};
|
||||||
use instance::Instance;
|
use instance::Instance;
|
||||||
use schema::tags;
|
use schema::tags;
|
||||||
|
|
||||||
@ -27,14 +27,14 @@ impl Tag {
|
|||||||
find_by!(tags, find_by_name, tag as String);
|
find_by!(tags, find_by_name, tag as String);
|
||||||
list_by!(tags, for_post, post_id as i32);
|
list_by!(tags, for_post, post_id as i32);
|
||||||
|
|
||||||
pub fn into_activity(&self, conn: &PgConnection) -> Hashtag {
|
pub fn into_activity(&self, conn: &Connection) -> Hashtag {
|
||||||
let mut ht = Hashtag::default();
|
let mut ht = Hashtag::default();
|
||||||
ht.set_href_string(ap_url(format!("{}/tag/{}", Instance::get_local(conn).unwrap().public_domain, self.tag))).expect("Tag::into_activity: href error");
|
ht.set_href_string(ap_url(format!("{}/tag/{}", Instance::get_local(conn).unwrap().public_domain, self.tag))).expect("Tag::into_activity: href error");
|
||||||
ht.set_name_string(self.tag.clone()).expect("Tag::into_activity: name error");
|
ht.set_name_string(self.tag.clone()).expect("Tag::into_activity: name error");
|
||||||
ht
|
ht
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_activity(conn: &PgConnection, tag: Hashtag, post: i32) -> Tag {
|
pub fn from_activity(conn: &Connection, tag: Hashtag, post: i32) -> Tag {
|
||||||
Tag::insert(conn, NewTag {
|
Tag::insert(conn, NewTag {
|
||||||
tag: tag.name_string().expect("Tag::from_activity: name error"),
|
tag: tag.name_string().expect("Tag::from_activity: name error"),
|
||||||
is_hastag: false,
|
is_hastag: false,
|
||||||
|
@ -5,8 +5,8 @@ use activitypub::{
|
|||||||
object::Image,
|
object::Image,
|
||||||
};
|
};
|
||||||
use bcrypt;
|
use bcrypt;
|
||||||
use chrono::{NaiveDateTime, Utc};
|
use chrono::{Utc, NaiveDateTime};
|
||||||
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods, BelongingToDsl, PgConnection, dsl::any};
|
use diesel::{self, QueryDsl, RunQueryDsl, ExpressionMethods, BelongingToDsl, dsl::any};
|
||||||
use openssl::{
|
use openssl::{
|
||||||
hash::MessageDigest,
|
hash::MessageDigest,
|
||||||
pkey::{PKey, Private},
|
pkey::{PKey, Private},
|
||||||
@ -31,7 +31,7 @@ use serde_json;
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
use webfinger::*;
|
use webfinger::*;
|
||||||
|
|
||||||
use {BASE_URL, USE_HTTPS, ap_url};
|
use {BASE_URL, USE_HTTPS, ap_url, Connection};
|
||||||
use db_conn::DbConn;
|
use db_conn::DbConn;
|
||||||
use blogs::Blog;
|
use blogs::Blog;
|
||||||
use blog_authors::BlogAuthor;
|
use blog_authors::BlogAuthor;
|
||||||
@ -100,28 +100,28 @@ impl User {
|
|||||||
find_by!(users, find_by_name, username as String, instance_id as i32);
|
find_by!(users, find_by_name, username as String, instance_id as i32);
|
||||||
find_by!(users, find_by_ap_url, ap_url as String);
|
find_by!(users, find_by_ap_url, ap_url as String);
|
||||||
|
|
||||||
pub fn one_by_instance(conn: &PgConnection) -> Vec<User> {
|
pub fn one_by_instance(conn: &Connection) -> Vec<User> {
|
||||||
users::table.distinct_on(users::instance_id)
|
users::table.distinct_on(users::instance_id)
|
||||||
.get_results::<User>(conn)
|
.get_results::<User>(conn)
|
||||||
.expect("Error in User::on_by_instance")
|
.expect("Error in User::on_by_instance")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(&self, conn: &PgConnection) {
|
pub fn delete(&self, conn: &Connection) {
|
||||||
diesel::delete(self).execute(conn).expect("Couldn't remove user from DB");
|
diesel::delete(self).execute(conn).expect("Couldn't remove user from DB");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_instance(&self, conn: &PgConnection) -> Instance {
|
pub fn get_instance(&self, conn: &Connection) -> Instance {
|
||||||
Instance::get(conn, self.instance_id).expect("Couldn't find instance")
|
Instance::get(conn, self.instance_id).expect("Couldn't find instance")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grant_admin_rights(&self, conn: &PgConnection) {
|
pub fn grant_admin_rights(&self, conn: &Connection) {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(users::is_admin.eq(true))
|
.set(users::is_admin.eq(true))
|
||||||
.load::<User>(conn)
|
.load::<User>(conn)
|
||||||
.expect("Couldn't grant admin rights");
|
.expect("Couldn't grant admin rights");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&self, conn: &PgConnection, name: String, email: String, summary: String) -> User {
|
pub fn update(&self, conn: &Connection, name: String, email: String, summary: String) -> User {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set((
|
.set((
|
||||||
users::display_name.eq(name),
|
users::display_name.eq(name),
|
||||||
@ -132,18 +132,18 @@ impl User {
|
|||||||
.into_iter().nth(0).unwrap()
|
.into_iter().nth(0).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count_local(conn: &PgConnection) -> usize {
|
pub fn count_local(conn: &Connection) -> usize {
|
||||||
users::table.filter(users::instance_id.eq(Instance::local_id(conn)))
|
users::table.filter(users::instance_id.eq(Instance::local_id(conn)))
|
||||||
.load::<User>(conn)
|
.load::<User>(conn)
|
||||||
.expect("Couldn't load local users")
|
.expect("Couldn't load local users")
|
||||||
.len()
|
.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_local(conn: &PgConnection, username: String) -> Option<User> {
|
pub fn find_local(conn: &Connection, username: String) -> Option<User> {
|
||||||
User::find_by_name(conn, username, Instance::local_id(conn))
|
User::find_by_name(conn, username, Instance::local_id(conn))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_by_fqn(conn: &PgConnection, fqn: String) -> Option<User> {
|
pub fn find_by_fqn(conn: &Connection, fqn: String) -> Option<User> {
|
||||||
if fqn.contains("@") { // remote user
|
if fqn.contains("@") { // remote user
|
||||||
match Instance::find_by_domain(conn, String::from(fqn.split("@").last().unwrap())) {
|
match Instance::find_by_domain(conn, String::from(fqn.split("@").last().unwrap())) {
|
||||||
Some(instance) => {
|
Some(instance) => {
|
||||||
@ -159,7 +159,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_from_webfinger(conn: &PgConnection, acct: String) -> Option<User> {
|
fn fetch_from_webfinger(conn: &Connection, acct: String) -> Option<User> {
|
||||||
match resolve(acct.clone(), *USE_HTTPS) {
|
match resolve(acct.clone(), *USE_HTTPS) {
|
||||||
Ok(wf) => wf.links.into_iter().find(|l| l.mime_type == Some(String::from("application/activity+json"))).and_then(|l| User::fetch_from_url(conn, l.href.expect("No href for AP WF link"))),
|
Ok(wf) => wf.links.into_iter().find(|l| l.mime_type == Some(String::from("application/activity+json"))).and_then(|l| User::fetch_from_url(conn, l.href.expect("No href for AP WF link"))),
|
||||||
Err(details) => {
|
Err(details) => {
|
||||||
@ -192,11 +192,11 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_from_url(conn: &PgConnection, url: String) -> Option<User> {
|
pub fn fetch_from_url(conn: &Connection, url: String) -> Option<User> {
|
||||||
User::fetch(url.clone()).map(|json| (User::from_activity(conn, json, Url::parse(url.as_ref()).unwrap().host_str().unwrap().to_string())))
|
User::fetch(url.clone()).map(|json| (User::from_activity(conn, json, Url::parse(url.as_ref()).unwrap().host_str().unwrap().to_string())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_activity(conn: &PgConnection, acct: CustomPerson, inst: String) -> User {
|
fn from_activity(conn: &Connection, acct: CustomPerson, inst: String) -> User {
|
||||||
let instance = match Instance::find_by_domain(conn, inst.clone()) {
|
let instance = match Instance::find_by_domain(conn, inst.clone()) {
|
||||||
Some(instance) => instance,
|
Some(instance) => instance,
|
||||||
None => {
|
None => {
|
||||||
@ -242,7 +242,7 @@ impl User {
|
|||||||
user
|
user
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refetch(&self, conn: &PgConnection) {
|
pub fn refetch(&self, conn: &Connection) {
|
||||||
User::fetch(self.ap_url.clone()).map(|json| {
|
User::fetch(self.ap_url.clone()).map(|json| {
|
||||||
let avatar = Media::save_remote(conn, json.object.object_props.icon_image().expect("User::refetch: icon error")
|
let avatar = Media::save_remote(conn, json.object.object_props.icon_image().expect("User::refetch: icon error")
|
||||||
.object_props.url_string().expect("User::refetch: icon.url error"));
|
.object_props.url_string().expect("User::refetch: icon.url error"));
|
||||||
@ -274,7 +274,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_boxes(&self, conn: &PgConnection) {
|
pub fn update_boxes(&self, conn: &Connection) {
|
||||||
let instance = self.get_instance(conn);
|
let instance = self.get_instance(conn);
|
||||||
if self.outbox_url.len() == 0 {
|
if self.outbox_url.len() == 0 {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
@ -307,7 +307,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_local_page(conn: &PgConnection, (min, max): (i32, i32)) -> Vec<User> {
|
pub fn get_local_page(conn: &Connection, (min, max): (i32, i32)) -> Vec<User> {
|
||||||
users::table.filter(users::instance_id.eq(1))
|
users::table.filter(users::instance_id.eq(1))
|
||||||
.order(users::username.asc())
|
.order(users::username.asc())
|
||||||
.offset(min.into())
|
.offset(min.into())
|
||||||
@ -316,7 +316,7 @@ impl User {
|
|||||||
.expect("Error getting local users page")
|
.expect("Error getting local users page")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outbox(&self, conn: &PgConnection) -> ActivityStream<OrderedCollection> {
|
pub fn outbox(&self, conn: &Connection) -> ActivityStream<OrderedCollection> {
|
||||||
let acts = self.get_activities(conn);
|
let acts = self.get_activities(conn);
|
||||||
let n_acts = acts.len();
|
let n_acts = acts.len();
|
||||||
let mut coll = OrderedCollection::default();
|
let mut coll = OrderedCollection::default();
|
||||||
@ -369,7 +369,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_activities(&self, conn: &PgConnection) -> Vec<serde_json::Value> {
|
fn get_activities(&self, conn: &Connection) -> Vec<serde_json::Value> {
|
||||||
use schema::posts;
|
use schema::posts;
|
||||||
use schema::post_authors;
|
use schema::post_authors;
|
||||||
let posts_by_self = PostAuthor::belonging_to(self).select(post_authors::post_id);
|
let posts_by_self = PostAuthor::belonging_to(self).select(post_authors::post_id);
|
||||||
@ -382,7 +382,7 @@ impl User {
|
|||||||
}).collect::<Vec<serde_json::Value>>()
|
}).collect::<Vec<serde_json::Value>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fqn(&self, conn: &PgConnection) -> String {
|
pub fn get_fqn(&self, conn: &Connection) -> String {
|
||||||
if self.instance_id == Instance::local_id(conn) {
|
if self.instance_id == Instance::local_id(conn) {
|
||||||
self.username.clone()
|
self.username.clone()
|
||||||
} else {
|
} else {
|
||||||
@ -390,13 +390,13 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_followers(&self, conn: &PgConnection) -> Vec<User> {
|
pub fn get_followers(&self, conn: &Connection) -> Vec<User> {
|
||||||
use schema::follows;
|
use schema::follows;
|
||||||
let follows = Follow::belonging_to(self).select(follows::follower_id);
|
let follows = Follow::belonging_to(self).select(follows::follower_id);
|
||||||
users::table.filter(users::id.eq(any(follows))).load::<User>(conn).unwrap()
|
users::table.filter(users::id.eq(any(follows))).load::<User>(conn).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_followers_page(&self, conn: &PgConnection, (min, max): (i32, i32)) -> Vec<User> {
|
pub fn get_followers_page(&self, conn: &Connection, (min, max): (i32, i32)) -> Vec<User> {
|
||||||
use schema::follows;
|
use schema::follows;
|
||||||
let follows = Follow::belonging_to(self).select(follows::follower_id);
|
let follows = Follow::belonging_to(self).select(follows::follower_id);
|
||||||
users::table.filter(users::id.eq(any(follows)))
|
users::table.filter(users::id.eq(any(follows)))
|
||||||
@ -405,13 +405,13 @@ impl User {
|
|||||||
.load::<User>(conn).unwrap()
|
.load::<User>(conn).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_following(&self, conn: &PgConnection) -> Vec<User> {
|
pub fn get_following(&self, conn: &Connection) -> Vec<User> {
|
||||||
use schema::follows;
|
use schema::follows;
|
||||||
let follows = follows::table.filter(follows::follower_id.eq(self.id)).select(follows::following_id);
|
let follows = follows::table.filter(follows::follower_id.eq(self.id)).select(follows::following_id);
|
||||||
users::table.filter(users::id.eq(any(follows))).load::<User>(conn).unwrap()
|
users::table.filter(users::id.eq(any(follows))).load::<User>(conn).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_followed_by(&self, conn: &PgConnection, other_id: i32) -> bool {
|
pub fn is_followed_by(&self, conn: &Connection, other_id: i32) -> bool {
|
||||||
use schema::follows;
|
use schema::follows;
|
||||||
follows::table
|
follows::table
|
||||||
.filter(follows::follower_id.eq(other_id))
|
.filter(follows::follower_id.eq(other_id))
|
||||||
@ -421,7 +421,7 @@ impl User {
|
|||||||
.len() > 0
|
.len() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_following(&self, conn: &PgConnection, other_id: i32) -> bool {
|
pub fn is_following(&self, conn: &Connection, other_id: i32) -> bool {
|
||||||
use schema::follows;
|
use schema::follows;
|
||||||
follows::table
|
follows::table
|
||||||
.filter(follows::follower_id.eq(self.id))
|
.filter(follows::follower_id.eq(self.id))
|
||||||
@ -431,7 +431,7 @@ impl User {
|
|||||||
.len() > 0
|
.len() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_liked(&self, conn: &PgConnection, post: &Post) -> bool {
|
pub fn has_liked(&self, conn: &Connection, post: &Post) -> bool {
|
||||||
use schema::likes;
|
use schema::likes;
|
||||||
likes::table
|
likes::table
|
||||||
.filter(likes::post_id.eq(post.id))
|
.filter(likes::post_id.eq(post.id))
|
||||||
@ -441,7 +441,7 @@ impl User {
|
|||||||
.len() > 0
|
.len() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_reshared(&self, conn: &PgConnection, post: &Post) -> bool {
|
pub fn has_reshared(&self, conn: &Connection, post: &Post) -> bool {
|
||||||
use schema::reshares;
|
use schema::reshares;
|
||||||
reshares::table
|
reshares::table
|
||||||
.filter(reshares::post_id.eq(post.id))
|
.filter(reshares::post_id.eq(post.id))
|
||||||
@ -451,7 +451,7 @@ impl User {
|
|||||||
.len() > 0
|
.len() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_author_in(&self, conn: &PgConnection, blog: Blog) -> bool {
|
pub fn is_author_in(&self, conn: &Connection, blog: Blog) -> bool {
|
||||||
use schema::blog_authors;
|
use schema::blog_authors;
|
||||||
blog_authors::table.filter(blog_authors::author_id.eq(self.id))
|
blog_authors::table.filter(blog_authors::author_id.eq(self.id))
|
||||||
.filter(blog_authors::blog_id.eq(blog.id))
|
.filter(blog_authors::blog_id.eq(blog.id))
|
||||||
@ -464,7 +464,7 @@ impl User {
|
|||||||
PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.clone().unwrap().as_ref()).unwrap()).unwrap()
|
PKey::from_rsa(Rsa::private_key_from_pem(self.private_key.clone().unwrap().as_ref()).unwrap()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_activity(&self, conn: &PgConnection) -> CustomPerson {
|
pub fn into_activity(&self, conn: &Connection) -> CustomPerson {
|
||||||
let mut actor = Person::default();
|
let mut actor = Person::default();
|
||||||
actor.object_props.set_id_string(self.ap_url.clone()).expect("User::into_activity: id error");
|
actor.object_props.set_id_string(self.ap_url.clone()).expect("User::into_activity: id error");
|
||||||
actor.object_props.set_name_string(self.display_name.clone()).expect("User::into_activity: name error");
|
actor.object_props.set_name_string(self.display_name.clone()).expect("User::into_activity: name error");
|
||||||
@ -494,7 +494,7 @@ impl User {
|
|||||||
CustomPerson::new(actor, ap_signature)
|
CustomPerson::new(actor, ap_signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_json(&self, conn: &PgConnection) -> serde_json::Value {
|
pub fn to_json(&self, conn: &Connection) -> serde_json::Value {
|
||||||
let mut json = serde_json::to_value(self).unwrap();
|
let mut json = serde_json::to_value(self).unwrap();
|
||||||
json["fqn"] = serde_json::Value::String(self.get_fqn(conn));
|
json["fqn"] = serde_json::Value::String(self.get_fqn(conn));
|
||||||
json["name"] = if self.display_name.len() > 0 {
|
json["name"] = if self.display_name.len() > 0 {
|
||||||
@ -506,7 +506,7 @@ impl User {
|
|||||||
json
|
json
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webfinger(&self, conn: &PgConnection) -> Webfinger {
|
pub fn webfinger(&self, conn: &Connection) -> Webfinger {
|
||||||
Webfinger {
|
Webfinger {
|
||||||
subject: format!("acct:{}@{}", self.username, self.get_instance(conn).public_domain),
|
subject: format!("acct:{}@{}", self.username, self.get_instance(conn).public_domain),
|
||||||
aliases: vec![self.ap_url.clone()],
|
aliases: vec![self.ap_url.clone()],
|
||||||
@ -533,7 +533,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_url(conn: &PgConnection, url: String) -> Option<User> {
|
pub fn from_url(conn: &Connection, url: String) -> Option<User> {
|
||||||
User::find_by_ap_url(conn, url.clone()).or_else(|| {
|
User::find_by_ap_url(conn, url.clone()).or_else(|| {
|
||||||
// The requested user was not in the DB
|
// The requested user was not in the DB
|
||||||
// We try to fetch it if it is remote
|
// We try to fetch it if it is remote
|
||||||
@ -545,7 +545,7 @@ impl User {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_avatar(&self, conn: &PgConnection, id: i32) {
|
pub fn set_avatar(&self, conn: &Connection, id: i32) {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(users::avatar_id.eq(id))
|
.set(users::avatar_id.eq(id))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
@ -609,7 +609,7 @@ impl Signer for User {
|
|||||||
impl NewUser {
|
impl NewUser {
|
||||||
/// Creates a new local user
|
/// Creates a new local user
|
||||||
pub fn new_local(
|
pub fn new_local(
|
||||||
conn: &PgConnection,
|
conn: &Connection,
|
||||||
username: String,
|
username: String,
|
||||||
display_name: String,
|
display_name: String,
|
||||||
is_admin: bool,
|
is_admin: bool,
|
||||||
|
Loading…
Reference in New Issue
Block a user