mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-25 19:01:09 +00:00
stuff
This commit is contained in:
parent
dc50483e5c
commit
bda146cf05
7 changed files with 141 additions and 39 deletions
|
@ -2,4 +2,6 @@ drop table conflict;
|
||||||
drop table edit;
|
drop table edit;
|
||||||
drop table article;
|
drop table article;
|
||||||
drop table instance_follow;
|
drop table instance_follow;
|
||||||
|
drop table local_user;
|
||||||
|
drop table person;
|
||||||
drop table instance;
|
drop table instance;
|
||||||
|
|
|
@ -9,20 +9,27 @@ create table instance (
|
||||||
local bool not null
|
local bool not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table user_ (
|
create table person (
|
||||||
id serial primary key,
|
id serial primary key,
|
||||||
ap_id varchar(255) not null unique,
|
username text not null,
|
||||||
inbox_url text not null,
|
ap_id varchar(255) not null unique,
|
||||||
public_key text not null,
|
inbox_url text not null,
|
||||||
private_key text,
|
public_key text not null,
|
||||||
last_refreshed_at timestamptz not null default now(),
|
private_key text,
|
||||||
local bool not null
|
last_refreshed_at timestamptz not null default now(),
|
||||||
);
|
local bool not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table local_user (
|
||||||
|
id serial primary key,
|
||||||
|
password_encrypted text not null,
|
||||||
|
person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
create table instance_follow (
|
create table instance_follow (
|
||||||
id serial primary key,
|
id serial primary key,
|
||||||
instance_id int REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
instance_id int REFERENCES instance ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||||
follower_id int REFERENCES user_ ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
follower_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||||
pending boolean not null,
|
pending boolean not null,
|
||||||
unique(instance_id, follower_id)
|
unique(instance_id, follower_id)
|
||||||
);
|
);
|
||||||
|
|
42
src/api.rs
42
src/api.rs
|
@ -19,6 +19,7 @@ use diffy::create_patch;
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
use crate::database::user::{DbLocalUserForm, DbPerson, DbPersonForm};
|
||||||
|
|
||||||
pub fn api_routes() -> Router {
|
pub fn api_routes() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
@ -33,6 +34,8 @@ pub fn api_routes() -> Router {
|
||||||
.route("/instance", get(get_local_instance))
|
.route("/instance", get(get_local_instance))
|
||||||
.route("/instance/follow", post(follow_instance))
|
.route("/instance/follow", post(follow_instance))
|
||||||
.route("/search", get(search_article))
|
.route("/search", get(search_article))
|
||||||
|
.route("/user/register", post(register_user))
|
||||||
|
.route("/user/login", post(login_user))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
@ -291,3 +294,42 @@ async fn fork_article(
|
||||||
|
|
||||||
Ok(Json(DbArticle::read_view(article.id, &data.db_connection)?))
|
Ok(Json(DbArticle::read_view(article.id, &data.db_connection)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct RegisterUserData {
|
||||||
|
name: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct Jwt(String);
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
async fn register_user(
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
Form(form): Form<RegisterUserData>,
|
||||||
|
) -> MyResult<Json<Jwt>> {
|
||||||
|
let local_user_form = DbLocalUserForm {
|
||||||
|
|
||||||
|
};
|
||||||
|
let person_form = DbPersonForm {
|
||||||
|
|
||||||
|
};
|
||||||
|
DbPerson::create(&person_form, Some(&local_user_form), &data.db_connection)?;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct LoginUserData {
|
||||||
|
name: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
async fn login_user(
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
Form(form): Form<Jwt>,
|
||||||
|
) -> MyResult<Json<ArticleView>> {
|
||||||
|
todo!()
|
||||||
|
}
|
|
@ -58,8 +58,17 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
user_ (id) {
|
local_user (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
|
password_encrypted -> Text,
|
||||||
|
person_id -> Int4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
person (id) {
|
||||||
|
id -> Int4,
|
||||||
|
username -> Text,
|
||||||
#[max_length = 255]
|
#[max_length = 255]
|
||||||
ap_id -> Varchar,
|
ap_id -> Varchar,
|
||||||
inbox_url -> Text,
|
inbox_url -> Text,
|
||||||
|
@ -74,7 +83,8 @@ diesel::joinable!(article -> instance (instance_id));
|
||||||
diesel::joinable!(conflict -> article (article_id));
|
diesel::joinable!(conflict -> article (article_id));
|
||||||
diesel::joinable!(edit -> article (article_id));
|
diesel::joinable!(edit -> article (article_id));
|
||||||
diesel::joinable!(instance_follow -> instance (instance_id));
|
diesel::joinable!(instance_follow -> instance (instance_id));
|
||||||
diesel::joinable!(instance_follow -> user_ (follower_id));
|
diesel::joinable!(instance_follow -> person (follower_id));
|
||||||
|
diesel::joinable!(local_user -> person (person_id));
|
||||||
|
|
||||||
diesel::allow_tables_to_appear_in_same_query!(
|
diesel::allow_tables_to_appear_in_same_query!(
|
||||||
article,
|
article,
|
||||||
|
@ -82,5 +92,6 @@ diesel::allow_tables_to_appear_in_same_query!(
|
||||||
edit,
|
edit,
|
||||||
instance,
|
instance,
|
||||||
instance_follow,
|
instance_follow,
|
||||||
user_,
|
local_user,
|
||||||
|
person,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::database::schema::user_;
|
use crate::database::schema::{local_user, person};
|
||||||
use crate::database::MyDataHandle;
|
use crate::database::MyDataHandle;
|
||||||
use crate::error::MyResult;
|
use crate::error::MyResult;
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
|
@ -14,11 +14,29 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
/// A user with account registered on local instance.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Queryable, Selectable, Identifiable)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Queryable, Selectable, Identifiable)]
|
||||||
#[diesel(table_name = user_, check_for_backend(diesel::pg::Pg))]
|
#[diesel(table_name = local_user, check_for_backend(diesel::pg::Pg))]
|
||||||
pub struct DbUser {
|
pub struct DbLocalUser {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub ap_id: ObjectId<DbUser>,
|
pub password_encrypted: String,
|
||||||
|
pub person_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Insertable, AsChangeset)]
|
||||||
|
#[diesel(table_name = local_user, check_for_backend(diesel::pg::Pg))]
|
||||||
|
pub struct DbLocalUserForm {
|
||||||
|
pub password_encrypted: String,
|
||||||
|
pub person_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Federation related data from a local or remote user.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Queryable, Selectable, Identifiable)]
|
||||||
|
#[diesel(table_name = person, check_for_backend(diesel::pg::Pg))]
|
||||||
|
pub struct DbPerson {
|
||||||
|
pub id: i32,
|
||||||
|
pub username: String,
|
||||||
|
pub ap_id: ObjectId<DbPerson>,
|
||||||
pub inbox_url: String,
|
pub inbox_url: String,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub public_key: String,
|
pub public_key: String,
|
||||||
|
@ -30,9 +48,10 @@ pub struct DbUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Insertable, AsChangeset)]
|
#[derive(Debug, Clone, Insertable, AsChangeset)]
|
||||||
#[diesel(table_name = user_, check_for_backend(diesel::pg::Pg))]
|
#[diesel(table_name = person, check_for_backend(diesel::pg::Pg))]
|
||||||
pub struct DbUserForm {
|
pub struct DbPersonForm {
|
||||||
pub ap_id: ObjectId<DbUser>,
|
pub username: String,
|
||||||
|
pub ap_id: ObjectId<DbPerson>,
|
||||||
pub inbox_url: String,
|
pub inbox_url: String,
|
||||||
pub public_key: String,
|
pub public_key: String,
|
||||||
pub private_key: Option<String>,
|
pub private_key: Option<String>,
|
||||||
|
@ -40,24 +59,32 @@ pub struct DbUserForm {
|
||||||
pub local: bool,
|
pub local: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DbUser {
|
impl DbPerson {
|
||||||
pub fn create(form: &DbUserForm, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
pub fn create(person_form: &DbPersonForm, local_user_form: Option<&DbLocalUserForm>, conn: &Mutex<PgConnection>) -> MyResult<Self> {
|
||||||
let mut conn = conn.lock().unwrap();
|
let mut conn = conn.lock().unwrap();
|
||||||
Ok(insert_into(user_::table)
|
let person = insert_into(person::table)
|
||||||
.values(form)
|
.values(person_form)
|
||||||
.on_conflict(user_::dsl::ap_id)
|
.on_conflict(person::dsl::ap_id)
|
||||||
.do_update()
|
.do_update()
|
||||||
.set(form)
|
.set(person_form)
|
||||||
.get_result(conn.deref_mut())?)
|
.get_result::<DbPerson>(conn.deref_mut())?;
|
||||||
|
|
||||||
|
if let Some(local_user_form) = local_user_form {
|
||||||
|
insert_into(local_user::table)
|
||||||
|
.values(local_user_form)
|
||||||
|
.get_result::<DbLocalUser>(conn.deref_mut())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(person)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from_ap_id(
|
pub fn read_from_ap_id(
|
||||||
ap_id: &ObjectId<DbUser>,
|
ap_id: &ObjectId<DbPerson>,
|
||||||
data: &Data<MyDataHandle>,
|
data: &Data<MyDataHandle>,
|
||||||
) -> MyResult<DbUser> {
|
) -> MyResult<DbPerson> {
|
||||||
let mut conn = data.db_connection.lock().unwrap();
|
let mut conn = data.db_connection.lock().unwrap();
|
||||||
Ok(user_::table
|
Ok(person::table
|
||||||
.filter(user_::dsl::ap_id.eq(ap_id))
|
.filter(person::dsl::ap_id.eq(ap_id))
|
||||||
.get_result(conn.deref_mut())?)
|
.get_result(conn.deref_mut())?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::database::user::{DbUser, DbUserForm};
|
use crate::database::user::{DbLocalUser, DbLocalUserForm, DbPerson, DbPersonForm};
|
||||||
use crate::database::MyDataHandle;
|
use crate::database::MyDataHandle;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use activitypub_federation::kinds::actor::PersonType;
|
use activitypub_federation::kinds::actor::PersonType;
|
||||||
|
@ -18,13 +18,14 @@ use url::Url;
|
||||||
pub struct ApubUser {
|
pub struct ApubUser {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
kind: PersonType,
|
kind: PersonType,
|
||||||
id: ObjectId<DbUser>,
|
id: ObjectId<DbPerson>,
|
||||||
|
preferred_username: String,
|
||||||
inbox: Url,
|
inbox: Url,
|
||||||
public_key: PublicKey,
|
public_key: PublicKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Object for DbUser {
|
impl Object for DbPerson {
|
||||||
type DataType = MyDataHandle;
|
type DataType = MyDataHandle;
|
||||||
type Kind = ApubUser;
|
type Kind = ApubUser;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
@ -37,13 +38,14 @@ impl Object for DbUser {
|
||||||
object_id: Url,
|
object_id: Url,
|
||||||
data: &Data<Self::DataType>,
|
data: &Data<Self::DataType>,
|
||||||
) -> Result<Option<Self>, Self::Error> {
|
) -> Result<Option<Self>, Self::Error> {
|
||||||
Ok(DbUser::read_from_ap_id(&object_id.into(), data).ok())
|
Ok(DbPerson::read_from_ap_id(&object_id.into(), data).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
|
async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
|
||||||
Ok(ApubUser {
|
Ok(ApubUser {
|
||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
id: self.ap_id.clone(),
|
id: self.ap_id.clone(),
|
||||||
|
preferred_username: self.username.clone(),
|
||||||
inbox: Url::parse(&self.inbox_url)?,
|
inbox: Url::parse(&self.inbox_url)?,
|
||||||
public_key: self.public_key(),
|
public_key: self.public_key(),
|
||||||
})
|
})
|
||||||
|
@ -59,7 +61,8 @@ impl Object for DbUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error> {
|
async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error> {
|
||||||
let form = DbUserForm {
|
let form = DbPersonForm {
|
||||||
|
username: json.preferred_username,
|
||||||
ap_id: json.id,
|
ap_id: json.id,
|
||||||
inbox_url: json.inbox.to_string(),
|
inbox_url: json.inbox.to_string(),
|
||||||
public_key: json.public_key.public_key_pem,
|
public_key: json.public_key.public_key_pem,
|
||||||
|
@ -67,11 +70,11 @@ impl Object for DbUser {
|
||||||
last_refreshed_at: Local::now().into(),
|
last_refreshed_at: Local::now().into(),
|
||||||
local: false,
|
local: false,
|
||||||
};
|
};
|
||||||
DbUser::create(&form, &data.db_connection)
|
DbPerson::create(&form, None, &data.db_connection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Actor for DbUser {
|
impl Actor for DbPerson {
|
||||||
fn id(&self) -> Url {
|
fn id(&self) -> Url {
|
||||||
self.ap_id.inner().clone()
|
self.ap_id.inner().clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::common::{
|
||||||
get_query, post, TestData, TEST_ARTICLE_DEFAULT_TEXT,
|
get_query, post, TestData, TEST_ARTICLE_DEFAULT_TEXT,
|
||||||
};
|
};
|
||||||
use common::get;
|
use common::get;
|
||||||
use fediwiki::api::{EditArticleData, ForkArticleData, ResolveObject, SearchArticleData};
|
use fediwiki::api::{EditArticleData, ForkArticleData, RegisterUserData, ResolveObject, SearchArticleData};
|
||||||
use fediwiki::database::article::{ArticleView, DbArticle};
|
use fediwiki::database::article::{ArticleView, DbArticle};
|
||||||
use fediwiki::error::MyResult;
|
use fediwiki::error::MyResult;
|
||||||
|
|
||||||
|
@ -464,3 +464,13 @@ async fn test_fork_article() -> MyResult<()> {
|
||||||
|
|
||||||
data.stop()
|
data.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_user_registration_login() -> MyResult<()> {
|
||||||
|
let data = TestData::start();
|
||||||
|
let data = RegisterUserData {
|
||||||
|
|
||||||
|
}
|
||||||
|
post(data.alpha.hostname, "user/register")
|
||||||
|
data.stop()
|
||||||
|
}
|
Loading…
Reference in a new issue