2018-12-29 09:36:07 +01:00
|
|
|
#![feature(try_trait)]
|
2019-03-19 14:37:56 +01:00
|
|
|
#![feature(never_type)]
|
2019-04-29 16:30:20 +02:00
|
|
|
#![feature(proc_macro_hygiene)]
|
2018-09-08 01:11:27 +02:00
|
|
|
|
2018-06-23 18:36:11 +02:00
|
|
|
#[macro_use]
|
|
|
|
extern crate diesel;
|
|
|
|
#[macro_use]
|
|
|
|
extern crate lazy_static;
|
2019-04-29 16:30:20 +02:00
|
|
|
#[macro_use]
|
|
|
|
extern crate plume_macro;
|
2020-01-12 19:41:35 +01:00
|
|
|
#[macro_use]
|
2018-06-23 18:36:11 +02:00
|
|
|
extern crate rocket;
|
|
|
|
#[macro_use]
|
2019-03-21 11:51:41 +01:00
|
|
|
extern crate serde_derive;
|
|
|
|
#[macro_use]
|
2018-06-23 18:36:11 +02:00
|
|
|
extern crate serde_json;
|
2018-12-02 17:37:51 +01:00
|
|
|
#[macro_use]
|
|
|
|
extern crate tantivy;
|
2018-06-23 18:36:11 +02:00
|
|
|
|
2019-04-17 19:31:47 +02:00
|
|
|
use plume_common::activity_pub::inbox::InboxError;
|
|
|
|
|
2018-11-26 10:21:52 +01:00
|
|
|
#[cfg(not(any(feature = "sqlite", feature = "postgres")))]
|
|
|
|
compile_error!("Either feature \"sqlite\" or \"postgres\" must be enabled for this crate.");
|
|
|
|
#[cfg(all(feature = "sqlite", feature = "postgres"))]
|
|
|
|
compile_error!("Either feature \"sqlite\" or \"postgres\" must be enabled for this crate.");
|
|
|
|
|
2018-09-27 23:06:40 +02:00
|
|
|
#[cfg(all(feature = "sqlite", not(feature = "postgres")))]
|
|
|
|
pub type Connection = diesel::SqliteConnection;
|
|
|
|
|
|
|
|
#[cfg(all(not(feature = "sqlite"), feature = "postgres"))]
|
|
|
|
pub type Connection = diesel::PgConnection;
|
|
|
|
|
2018-12-29 09:36:07 +01:00
|
|
|
/// All the possible errors that can be encoutered in this crate
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
2020-01-12 19:41:35 +01:00
|
|
|
Blocklisted(bool, String),
|
2018-12-29 09:36:07 +01:00
|
|
|
Db(diesel::result::Error),
|
2019-04-17 19:31:47 +02:00
|
|
|
Inbox(Box<InboxError<Error>>),
|
2018-12-29 09:36:07 +01:00
|
|
|
InvalidValue,
|
|
|
|
Io(std::io::Error),
|
|
|
|
MissingApProperty,
|
|
|
|
NotFound,
|
|
|
|
Request,
|
|
|
|
SerDe,
|
|
|
|
Search(search::SearcherError),
|
|
|
|
Signature,
|
2019-10-07 19:08:20 +02:00
|
|
|
TimelineQuery(timeline::query::QueryError),
|
2018-12-29 09:36:07 +01:00
|
|
|
Unauthorized,
|
|
|
|
Url,
|
|
|
|
Webfinger,
|
2019-06-04 20:55:17 +02:00
|
|
|
Expired,
|
2018-12-29 09:36:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<bcrypt::BcryptError> for Error {
|
|
|
|
fn from(_: bcrypt::BcryptError) -> Self {
|
|
|
|
Error::Signature
|
|
|
|
}
|
|
|
|
}
|
2019-10-30 11:22:28 +01:00
|
|
|
pub const ITEMS_PER_PAGE: i32 = 12;
|
2018-12-29 09:36:07 +01:00
|
|
|
impl From<openssl::error::ErrorStack> for Error {
|
|
|
|
fn from(_: openssl::error::ErrorStack) -> Self {
|
|
|
|
Error::Signature
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<diesel::result::Error> for Error {
|
|
|
|
fn from(err: diesel::result::Error) -> Self {
|
|
|
|
Error::Db(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<std::option::NoneError> for Error {
|
|
|
|
fn from(_: std::option::NoneError) -> Self {
|
|
|
|
Error::NotFound
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<url::ParseError> for Error {
|
|
|
|
fn from(_: url::ParseError) -> Self {
|
|
|
|
Error::Url
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<serde_json::Error> for Error {
|
|
|
|
fn from(_: serde_json::Error) -> Self {
|
|
|
|
Error::SerDe
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<reqwest::Error> for Error {
|
|
|
|
fn from(_: reqwest::Error) -> Self {
|
|
|
|
Error::Request
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<reqwest::header::InvalidHeaderValue> for Error {
|
|
|
|
fn from(_: reqwest::header::InvalidHeaderValue) -> Self {
|
|
|
|
Error::Request
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<activitypub::Error> for Error {
|
|
|
|
fn from(err: activitypub::Error) -> Self {
|
|
|
|
match err {
|
|
|
|
activitypub::Error::NotFound => Error::MissingApProperty,
|
|
|
|
_ => Error::SerDe,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<webfinger::WebfingerError> for Error {
|
|
|
|
fn from(_: webfinger::WebfingerError) -> Self {
|
|
|
|
Error::Webfinger
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<search::SearcherError> for Error {
|
|
|
|
fn from(err: search::SearcherError) -> Self {
|
|
|
|
Error::Search(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-07 19:08:20 +02:00
|
|
|
impl From<timeline::query::QueryError> for Error {
|
|
|
|
fn from(err: timeline::query::QueryError) -> Self {
|
|
|
|
Error::TimelineQuery(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-29 09:36:07 +01:00
|
|
|
impl From<std::io::Error> for Error {
|
|
|
|
fn from(err: std::io::Error) -> Self {
|
|
|
|
Error::Io(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-17 19:31:47 +02:00
|
|
|
impl From<InboxError<Error>> for Error {
|
|
|
|
fn from(err: InboxError<Error>) -> Error {
|
|
|
|
match err {
|
|
|
|
InboxError::InvalidActor(Some(e)) | InboxError::InvalidObject(Some(e)) => e,
|
|
|
|
e => Error::Inbox(Box::new(e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-29 09:36:07 +01:00
|
|
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
|
|
|
2018-09-29 12:05:05 +02:00
|
|
|
/// Adds a function to a model, that returns the first
|
|
|
|
/// matching row for a given list of fields.
|
|
|
|
///
|
|
|
|
/// Usage:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// impl Model {
|
|
|
|
/// find_by!(model_table, name_of_the_function, field1 as String, field2 as i32);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // Get the Model with field1 == "", and field2 == 0
|
|
|
|
/// Model::name_of_the_function(connection, String::new(), 0);
|
|
|
|
/// ```
|
2018-06-18 15:37:49 +02:00
|
|
|
macro_rules! find_by {
|
2018-11-26 10:21:52 +01:00
|
|
|
($table:ident, $fn:ident, $($col:ident as $type:ty),+) => {
|
2018-06-18 15:37:49 +02:00
|
|
|
/// Try to find a $table with a given $col
|
2018-12-29 09:36:07 +01:00
|
|
|
pub fn $fn(conn: &crate::Connection, $($col: $type),+) -> Result<Self> {
|
2018-06-18 17:13:09 +02:00
|
|
|
$table::table
|
|
|
|
$(.filter($table::$col.eq($col)))+
|
2019-10-07 19:08:20 +02:00
|
|
|
.first(conn)
|
|
|
|
.map_err(Error::from)
|
2018-06-18 15:37:49 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-29 12:05:05 +02:00
|
|
|
/// List all rows of a model, with field-based filtering.
|
|
|
|
///
|
|
|
|
/// Usage:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// impl Model {
|
|
|
|
/// list_by!(model_table, name_of_the_function, field1 as String);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // To get all Models with field1 == ""
|
|
|
|
/// Model::name_of_the_function(connection, String::new());
|
|
|
|
/// ```
|
2018-06-20 20:23:54 +02:00
|
|
|
macro_rules! list_by {
|
2018-11-26 10:21:52 +01:00
|
|
|
($table:ident, $fn:ident, $($col:ident as $type:ty),+) => {
|
2018-06-20 20:23:54 +02:00
|
|
|
/// Try to find a $table with a given $col
|
2018-12-29 09:36:07 +01:00
|
|
|
pub fn $fn(conn: &crate::Connection, $($col: $type),+) -> Result<Vec<Self>> {
|
2018-06-20 20:23:54 +02:00
|
|
|
$table::table
|
|
|
|
$(.filter($table::$col.eq($col)))+
|
|
|
|
.load::<Self>(conn)
|
2018-12-29 09:36:07 +01:00
|
|
|
.map_err(Error::from)
|
2018-06-20 20:23:54 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-29 12:05:05 +02:00
|
|
|
/// Adds a function to a model to retrieve a row by ID
|
|
|
|
///
|
|
|
|
/// # Usage
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// impl Model {
|
|
|
|
/// get!(model_table);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // Get the Model with ID 1
|
|
|
|
/// Model::get(connection, 1);
|
|
|
|
/// ```
|
2018-06-18 15:44:23 +02:00
|
|
|
macro_rules! get {
|
|
|
|
($table:ident) => {
|
2018-12-29 09:36:07 +01:00
|
|
|
pub fn get(conn: &crate::Connection, id: i32) -> Result<Self> {
|
2018-11-24 12:44:17 +01:00
|
|
|
$table::table
|
|
|
|
.filter($table::id.eq(id))
|
2019-10-07 19:08:20 +02:00
|
|
|
.first(conn)
|
|
|
|
.map_err(Error::from)
|
2018-06-18 15:44:23 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-29 12:05:05 +02:00
|
|
|
/// Adds a function to a model to insert a new row
|
|
|
|
///
|
|
|
|
/// # Usage
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// impl Model {
|
|
|
|
/// insert!(model_table, NewModelType);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // Insert a new row
|
|
|
|
/// Model::insert(connection, NewModelType::new());
|
|
|
|
/// ```
|
2018-06-18 15:57:38 +02:00
|
|
|
macro_rules! insert {
|
2020-01-21 07:02:03 +01:00
|
|
|
($table:ident, $from:ty) => {
|
2019-03-22 19:51:36 +01:00
|
|
|
insert!($table, $from, |x, _conn| Ok(x));
|
2019-03-04 21:35:03 +01:00
|
|
|
};
|
2020-01-21 07:02:03 +01:00
|
|
|
($table:ident, $from:ty, |$val:ident, $conn:ident | $( $after:tt )+) => {
|
2018-09-27 23:06:40 +02:00
|
|
|
last!($table);
|
|
|
|
|
2020-01-19 12:52:32 +01:00
|
|
|
#[allow(dead_code)]
|
2018-12-29 09:36:07 +01:00
|
|
|
pub fn insert(conn: &crate::Connection, new: $from) -> Result<Self> {
|
2018-06-18 15:57:38 +02:00
|
|
|
diesel::insert_into($table::table)
|
|
|
|
.values(new)
|
2018-12-29 09:36:07 +01:00
|
|
|
.execute(conn)?;
|
2019-03-04 21:35:03 +01:00
|
|
|
#[allow(unused_mut)]
|
|
|
|
let mut $val = Self::last(conn)?;
|
|
|
|
let $conn = conn;
|
2019-03-22 19:51:36 +01:00
|
|
|
$( $after )+
|
2018-06-18 15:57:38 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-09-29 12:05:05 +02:00
|
|
|
/// Returns the last row of a table.
|
|
|
|
///
|
|
|
|
/// # Usage
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// impl Model {
|
|
|
|
/// last!(model_table);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // Get the last Model
|
|
|
|
/// Model::last(connection)
|
|
|
|
/// ```
|
2018-09-27 23:06:40 +02:00
|
|
|
macro_rules! last {
|
|
|
|
($table:ident) => {
|
2020-01-19 12:52:32 +01:00
|
|
|
#[allow(dead_code)]
|
2018-12-29 09:36:07 +01:00
|
|
|
pub fn last(conn: &crate::Connection) -> Result<Self> {
|
2018-11-24 12:44:17 +01:00
|
|
|
$table::table
|
|
|
|
.order_by($table::id.desc())
|
2019-10-07 19:08:20 +02:00
|
|
|
.first(conn)
|
|
|
|
.map_err(Error::from)
|
2018-09-06 23:39:22 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-03-21 10:30:33 +01:00
|
|
|
mod config;
|
|
|
|
pub use config::CONFIG;
|
2018-10-06 20:17:36 +02:00
|
|
|
|
2018-11-26 10:21:52 +01:00
|
|
|
pub fn ap_url(url: &str) -> String {
|
2019-03-21 10:30:33 +01:00
|
|
|
format!("https://{}", url)
|
2018-06-26 16:21:58 +02:00
|
|
|
}
|
|
|
|
|
2018-11-24 12:44:17 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
#[macro_use]
|
|
|
|
mod tests {
|
2020-01-21 07:02:03 +01:00
|
|
|
use crate::{db_conn, migrations::IMPORTED_MIGRATIONS, search, Connection as Conn, CONFIG};
|
2019-04-17 19:31:47 +02:00
|
|
|
use diesel::r2d2::ConnectionManager;
|
2019-04-29 16:30:20 +02:00
|
|
|
use plume_common::utils::random_hex;
|
2019-04-17 19:31:47 +02:00
|
|
|
use scheduled_thread_pool::ScheduledThreadPool;
|
2019-04-29 16:30:20 +02:00
|
|
|
use std::env::temp_dir;
|
2019-04-17 19:31:47 +02:00
|
|
|
use std::sync::Arc;
|
2018-11-24 12:44:17 +01:00
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! part_eq {
|
|
|
|
( $x:expr, $y:expr, [$( $var:ident ),*] ) => {
|
|
|
|
{
|
|
|
|
$(
|
|
|
|
assert_eq!($x.$var, $y.$var);
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-04-17 19:31:47 +02:00
|
|
|
pub fn db<'a>() -> db_conn::DbConn {
|
|
|
|
db_conn::DbConn((*DB_POOL).get().unwrap())
|
|
|
|
}
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
static ref DB_POOL: db_conn::DbPool = {
|
|
|
|
let pool = db_conn::DbPool::builder()
|
2019-10-07 19:08:20 +02:00
|
|
|
.connection_customizer(Box::new(db_conn::tests::TestConnectionCustomizer))
|
2019-04-17 19:31:47 +02:00
|
|
|
.build(ConnectionManager::<Conn>::new(CONFIG.database_url.as_str()))
|
|
|
|
.unwrap();
|
2019-04-29 16:30:20 +02:00
|
|
|
let dir = temp_dir().join(format!("plume-test-{}", random_hex()));
|
|
|
|
IMPORTED_MIGRATIONS
|
|
|
|
.run_pending_migrations(&pool.get().unwrap(), &dir)
|
|
|
|
.expect("Migrations error");
|
2019-04-17 19:31:47 +02:00
|
|
|
pool
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn rockets() -> super::PlumeRocket {
|
|
|
|
super::PlumeRocket {
|
|
|
|
conn: db_conn::DbConn((*DB_POOL).get().unwrap()),
|
|
|
|
searcher: Arc::new(search::tests::get_searcher()),
|
|
|
|
worker: Arc::new(ScheduledThreadPool::new(2)),
|
|
|
|
user: None,
|
|
|
|
}
|
2018-11-24 12:44:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-27 19:05:36 +02:00
|
|
|
pub mod admin;
|
2018-10-22 15:30:04 +02:00
|
|
|
pub mod api_tokens;
|
2018-10-21 15:19:07 +02:00
|
|
|
pub mod apps;
|
2020-01-12 19:41:35 +01:00
|
|
|
pub mod blocklisted_emails;
|
2018-04-23 13:27:27 +02:00
|
|
|
pub mod blog_authors;
|
2018-04-23 12:29:27 +02:00
|
|
|
pub mod blogs;
|
2018-12-24 11:23:04 +01:00
|
|
|
pub mod comment_seers;
|
2019-03-20 17:56:17 +01:00
|
|
|
pub mod comments;
|
2018-06-23 18:36:11 +02:00
|
|
|
pub mod db_conn;
|
2018-05-01 15:06:31 +02:00
|
|
|
pub mod follows;
|
2018-10-03 20:48:25 +02:00
|
|
|
pub mod headers;
|
2019-04-17 19:31:47 +02:00
|
|
|
pub mod inbox;
|
2018-04-22 15:35:37 +02:00
|
|
|
pub mod instance;
|
2018-05-10 17:54:35 +02:00
|
|
|
pub mod likes;
|
2019-10-07 19:08:20 +02:00
|
|
|
pub mod lists;
|
2018-09-02 13:34:48 +02:00
|
|
|
pub mod medias;
|
2018-06-20 20:22:34 +02:00
|
|
|
pub mod mentions;
|
2019-04-29 16:30:20 +02:00
|
|
|
pub mod migrations;
|
2018-05-13 14:44:18 +02:00
|
|
|
pub mod notifications;
|
2019-06-04 20:55:17 +02:00
|
|
|
pub mod password_reset_requests;
|
2019-04-17 19:31:47 +02:00
|
|
|
pub mod plume_rocket;
|
2018-04-23 16:37:49 +02:00
|
|
|
pub mod post_authors;
|
2018-04-23 17:19:28 +02:00
|
|
|
pub mod posts;
|
2018-05-19 11:23:02 +02:00
|
|
|
pub mod reshares;
|
2018-06-23 18:36:11 +02:00
|
|
|
pub mod safe_string;
|
2019-09-13 12:28:36 +02:00
|
|
|
#[allow(unused_imports)]
|
2018-06-23 18:36:11 +02:00
|
|
|
pub mod schema;
|
2019-03-20 17:56:17 +01:00
|
|
|
pub mod search;
|
2018-09-05 20:05:53 +02:00
|
|
|
pub mod tags;
|
2019-10-07 19:08:20 +02:00
|
|
|
pub mod timeline;
|
2018-04-23 17:19:28 +02:00
|
|
|
pub mod users;
|
2019-04-17 19:31:47 +02:00
|
|
|
pub use plume_rocket::PlumeRocket;
|