"@context": "https://www.w3.org/ns/activitystreams",
"type": "Person",
"id": "https://rust-reddit-fediverse/api/v1/user/sally_smith",
- "name": "sally_smith", // TODO can't find an activitypub vocab for alias.
+ "inbox": "https://rust-reddit-fediverse/api/v1/user/sally_smith/inbox",
+ "outbox": "https://rust-reddit-fediverse/api/v1/user/sally_smith/outbox",
+ "liked": "https://rust-reddit-fediverse/api/v1/user/sally_smith/liked",
+ "disliked": "https://rust-reddit-fediverse/api/v1/user/sally_smith/disliked",
+ "following": "https://rust-reddit-fediverse/api/v1/user/sally_smith/following",
+ "name": "sally_smith",
+ "preferredUsername": "Sally",
"icon"?: {
"type": "Image",
"name": "User icon",
```
### [Community / Group](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-group)
-
```
{
"@context": "https://www.w3.org/ns/activitystreams",
"attributedTo": [ // The moderators
"http://joe.example.org",
],
+ "followers": "https://rust-reddit-fediverse/api/v1/community/today_i_learned/followers",
"startTime": "2014-12-31T23:00:00-08:00",
"summary"?: "The group's tagline",
"attachment: [{}] // TBD, these would be where strong types for custom styles, and images would work.
"url": "https://news.blah.com"
"attributedTo": "http://joe.example.org", // The poster
"startTime": "2014-12-31T23:00:00-08:00",
-
}
```
### [Post Listings / Ordered CollectionPage](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollectionpage)
-
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Page 1 of Sally's front page",
"type": "OrderedCollectionPage",
"id": "https://rust-reddit-fediverse/api/v1/posts?type={all, best, front}&sort={}&page=1,
"partOf": "http://example.org/foo",
}
```
### [Comment Listings / Ordered CollectionPage](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollectionpage)
-
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Page 1 of comments for",
"type": "OrderedCollectionPage",
"id": "https://rust-reddit-fediverse/api/v1/comments?type={all,user,community,post,parent_comment}&id=1&page=1,
"partOf": "http://example.org/foo",
```
## Actions
+- These are all posts to a user's outbox.
+- The server then creates a post to the necessary inbox of the recipient, or the followers.
+- Whenever a user accesses the site, they do a get from their inbox.
+
### Comments
#### [Create](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally created a note",
"type": "Create",
"actor": id,
"object": comment_id, or post_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally deleted a note",
"type": "Delete",
"actor": id,
"object": comment_id, or post_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally created a note",
"type": "Create",
"actor": id,
"object": comment_id, or post_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally read a comment",
"type": "Read",
"actor": user_id
"object": comment_id
```
#### [Like](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like)
+- TODO: Should likes be notifications? IE, have a to?
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally liked a comment",
"type": "Like",
"actor": user_id
"object": comment_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally disliked a comment",
"type": "Dislike",
"actor": user_id
"object": comment_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally created a post",
"type": "Create",
"actor": id,
+ "to": community_id/followers
"object": post_id
}
```
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally deleted a post",
"type": "Delete",
"actor": id,
"object": comment_id, or post_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally created a post",
"type": "Create",
"actor": id,
"object": comment_id, or post_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally read a post",
"type": "Read",
"actor": user_id
"object": post_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally created a community",
"type": "Create",
"actor": id,
"object": community_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally deleted a community",
"type": "Delete",
"actor": id,
"object": community_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally created a community",
"type": "Create",
"actor": id,
"object": community_id
}
```
-#### [Join](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join)
+#### [Follow / Subscribe](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Follow",
+ "actor": id
+ "object": community_id
+}
+```
+
+#### [Ignore/ Unsubscribe](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-ignore)
+```
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Follow",
+ "actor": id
+ "object": community_id
+}
+```
+#### [Join / Become a Mod](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join)
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally joined a community",
"type": "Join",
"actor": user_id,
"object": community_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally left a community",
"type": "Leave",
"actor": user_id,
"object": community_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "The moderator blocked Sally from a group",
"type": "Remove",
"actor": mod_id,
"object": user_id,
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally deleted a users comment",
"type": "Delete",
"actor": id,
"object": community_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "Sally invited John to mod a community",
"type": "Invite",
"id": "https://rust-reddit-fediverse/api/v1/invite/1",
"actor": sally_id,
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "John Accepted an invitation to mod a community",
"type": "Accept",
"actor": john_id,
"object": invite_id
```
{
"@context": "https://www.w3.org/ns/activitystreams",
- "summary": "John Rejected an invitation to mod a community",
"type": "Reject",
"actor": john_id,
"object": invite_id
- Must have communities.
- Must have threaded comments.
- Must be federated: liking and following communities across instances.
+- Be live-updating: have a right pane for new comments, and a main pain for the full threaded view.
+ - Use websockets for post / gets to your own instance.
## Questions
- How does voting work? Should we go back to the old way of showing up and downvote counts? Or just a score?
- Use the [activitypub crate.](https://docs.rs/activitypub/0.1.4/activitypub/)
- https://docs.rs/activitypub/0.1.4/activitypub/
- [Activitypub vocab.](https://www.w3.org/TR/activitystreams-vocabulary/)
+- [Activitypub main](https://www.w3.org/TR/activitypub/)
- [Diesel to Postgres data types](https://kotiri.com/2018/01/31/postgresql-diesel-rust-types.html)
- [helpful diesel examples](http://siciarz.net/24-days-rust-diesel/)
+- [Mastodan public key server example](https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/)
create table user_ (
id serial primary key,
name varchar(20) not null,
- password_encrypted varchar(200) not null,
- email varchar(200),
+ preferred_username varchar(20),
+ password_encrypted text not null,
+ email text,
icon bytea,
- startTime timestamp not null default now()
-)
+ start_time timestamp not null default now()
+);
+
-drop table community
+drop table community_user;
+drop table community_follower;
+drop table community;
create table community (
id serial primary key,
name varchar(20) not null,
- starttime timestamp not null default now()
-)
+ start_time timestamp not null default now()
+);
+
+create table community_user (
+ id serial primary key,
+ community_id int references community on update cascade on delete cascade not null,
+ fedi_user_id text not null,
+ start_time timestamp not null default now()
+);
+
+create table community_follower (
+ id serial primary key,
+ community_id int references community on update cascade on delete cascade not null,
+ fedi_user_id text not null,
+ start_time timestamp not null default now()
+);
+++ /dev/null
-drop table community_user;
--- drop type community_user_type;
+++ /dev/null
--- No support for types yet, so just do 0,1,2
--- create type community_user_type as enum ('creator', 'moderator', 'user');
-
-create table community_user (
- id serial primary key,
- fedi_user_id varchar(100) not null,
- community_id int references community on update cascade on delete cascade,
- community_user_type smallint not null default 2,
- starttime timestamp not null default now()
-)
--- /dev/null
+drop table post_like;
+drop table post_dislike;
+drop table post;
--- /dev/null
+create table post (
+ id serial primary key,
+ name varchar(100) not null,
+ url text not null,
+ attributed_to text not null,
+ start_time timestamp not null default now()
+);
+
+create table post_like (
+ id serial primary key,
+ fedi_user_id text not null,
+ post_id int references post on update cascade on delete cascade,
+ start_time timestamp not null default now()
+);
+
+create table post_dislike (
+ id serial primary key,
+ fedi_user_id text not null,
+ post_id int references post on update cascade on delete cascade,
+ start_time timestamp not null default now()
+);
+
--- /dev/null
+extern crate diesel;
+use schema::{community, community_user, community_follower};
+use diesel::*;
+use diesel::result::Error;
+use {Crud, Followable, Joinable};
+
+#[derive(Queryable, Identifiable, PartialEq, Debug)]
+#[table_name="community"]
+pub struct Community {
+ pub id: i32,
+ pub name: String,
+ pub start_time: chrono::NaiveDateTime
+}
+
+#[derive(Insertable, AsChangeset, Clone, Copy)]
+#[table_name="community"]
+pub struct CommunityForm<'a> {
+ pub name: &'a str,
+}
+
+#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
+#[belongs_to(Community)]
+#[table_name = "community_user"]
+pub struct CommunityUser {
+ pub id: i32,
+ pub community_id: i32,
+ pub fedi_user_id: String,
+ pub start_time: chrono::NaiveDateTime
+}
+
+#[derive(Insertable, AsChangeset, Clone, Copy)]
+#[table_name="community_user"]
+pub struct CommunityUserForm<'a> {
+ pub community_id: &'a i32,
+ pub fedi_user_id: &'a str,
+}
+
+#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
+#[belongs_to(Community)]
+#[table_name = "community_follower"]
+pub struct CommunityFollower {
+ pub id: i32,
+ pub community_id: i32,
+ pub fedi_user_id: String,
+ pub start_time: chrono::NaiveDateTime
+}
+
+#[derive(Insertable, AsChangeset, Clone, Copy)]
+#[table_name="community_follower"]
+pub struct CommunityFollowerForm<'a> {
+ pub community_id: &'a i32,
+ pub fedi_user_id: &'a str,
+}
+
+
+impl<'a> Crud<CommunityForm<'a>> for Community {
+ fn read(conn: &PgConnection, community_id: i32) -> Community {
+ use schema::community::dsl::*;
+ community.find(community_id)
+ .first::<Community>(conn)
+ .expect("Error in query")
+ }
+
+ fn delete(conn: &PgConnection, community_id: i32) -> usize {
+ use schema::community::dsl::*;
+ diesel::delete(community.find(community_id))
+ .execute(conn)
+ .expect("Error deleting.")
+ }
+
+ fn create(conn: &PgConnection, new_community: CommunityForm) -> Result<Community, Error> {
+ use schema::community::dsl::*;
+ insert_into(community)
+ .values(new_community)
+ .get_result::<Community>(conn)
+ }
+
+ fn update(conn: &PgConnection, community_id: i32, new_community: CommunityForm) -> Community {
+ use schema::community::dsl::*;
+ diesel::update(community.find(community_id))
+ .set(new_community)
+ .get_result::<Community>(conn)
+ .expect(&format!("Unable to find {}", community_id))
+ }
+}
+
+impl<'a> Followable<CommunityFollowerForm<'a>> for CommunityFollower {
+ fn follow(conn: &PgConnection, community_follower_form: CommunityFollowerForm) -> Result<CommunityFollower, Error> {
+ use schema::community_follower::dsl::*;
+ insert_into(community_follower)
+ .values(community_follower_form)
+ .get_result::<CommunityFollower>(conn)
+ }
+ fn ignore(conn: &PgConnection, community_follower_form: CommunityFollowerForm) -> usize {
+ use schema::community_follower::dsl::*;
+ diesel::delete(community_follower
+ .filter(community_id.eq(community_follower_form.community_id))
+ .filter(fedi_user_id.eq(community_follower_form.fedi_user_id)))
+ .execute(conn)
+ .expect("Error deleting.")
+ }
+}
+
+impl<'a> Joinable<CommunityUserForm<'a>> for CommunityUser {
+ fn join(conn: &PgConnection, community_user_form: CommunityUserForm) -> Result<CommunityUser, Error> {
+ use schema::community_user::dsl::*;
+ insert_into(community_user)
+ .values(community_user_form)
+ .get_result::<CommunityUser>(conn)
+ }
+ fn leave(conn: &PgConnection, community_user_form: CommunityUserForm) -> usize {
+ use schema::community_user::dsl::*;
+ diesel::delete(community_user
+ .filter(community_id.eq(community_user_form.community_id))
+ .filter(fedi_user_id.eq(community_user_form.fedi_user_id)))
+ .execute(conn)
+ .expect("Error deleting.")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use establish_connection;
+ use super::*;
+ use actions::user::*;
+ use Crud;
+ #[test]
+ fn test_crud() {
+ let conn = establish_connection();
+
+ let new_community = CommunityForm {
+ name: "TIL".into(),
+ };
+
+ let inserted_community = Community::create(&conn, new_community).unwrap();
+
+ let expected_community = Community {
+ id: inserted_community.id,
+ name: "TIL".into(),
+ start_time: inserted_community.start_time
+ };
+
+ let new_user = UserForm {
+ name: "thom".into(),
+ preferred_username: None,
+ password_encrypted: "nope".into(),
+ email: None
+ };
+
+ let inserted_user = User_::create(&conn, new_user).unwrap();
+
+ let community_follower_form = CommunityFollowerForm {
+ community_id: &inserted_community.id,
+ fedi_user_id: "test".into()
+ };
+
+ let inserted_community_follower = CommunityFollower::follow(&conn, community_follower_form).unwrap();
+
+ let expected_community_follower = CommunityFollower {
+ id: inserted_community_follower.id,
+ community_id: inserted_community.id,
+ fedi_user_id: "test".into(),
+ start_time: inserted_community_follower.start_time
+ };
+
+ let community_user_form = CommunityUserForm {
+ community_id: &inserted_community.id,
+ fedi_user_id: "test".into()
+ };
+
+ let inserted_community_user = CommunityUser::join(&conn, community_user_form).unwrap();
+
+ let expected_community_user = CommunityUser {
+ id: inserted_community_user.id,
+ community_id: inserted_community.id,
+ fedi_user_id: "test".into(),
+ start_time: inserted_community_user.start_time
+ };
+
+ let read_community = Community::read(&conn, inserted_community.id);
+ let updated_community = Community::update(&conn, inserted_community.id, new_community);
+ let ignored_community = CommunityFollower::ignore(&conn, community_follower_form);
+ let left_community = CommunityUser::leave(&conn, community_user_form);
+ let num_deleted = Community::delete(&conn, inserted_community.id);
+ User_::delete(&conn, inserted_user.id);
+
+ assert_eq!(expected_community, read_community);
+ assert_eq!(expected_community, inserted_community);
+ assert_eq!(expected_community, updated_community);
+ assert_eq!(expected_community_follower, inserted_community_follower);
+ assert_eq!(expected_community_user, inserted_community_user);
+ assert_eq!(1, ignored_community);
+ assert_eq!(1, left_community);
+ assert_eq!(1, num_deleted);
+
+ }
+}
-use diesel::*;
pub mod user;
-
+pub mod community;
+pub mod post;
--- /dev/null
+extern crate diesel;
+use schema::user_;
+use diesel::*;
+use diesel::result::Error;
+use schema::user_::dsl::*;
+
+#[derive(Queryable, PartialEq, Debug)]
+pub struct User_ {
+ pub id: i32,
+ pub name: String,
+ pub preferred_username: Option<String>,
+ pub password_encrypted: String,
+ pub email: Option<String>,
+ pub icon: Option<Vec<u8>>,
+ pub start_time: chrono::NaiveDateTime
+}
+
+#[derive(Insertable, AsChangeset, Clone, Copy)]
+#[table_name="user_"]
+pub struct NewUser<'a> {
+ pub name: &'a str,
+ pub preferred_username: Option<&'a str>,
+ pub password_encrypted: &'a str,
+ pub email: Option<&'a str>,
+}
+
+pub fn read(conn: &PgConnection, user_id: i32) -> User_ {
+ user_.find(user_id)
+ .first::<User_>(conn)
+ .expect("Error in query")
+}
+
+pub fn delete(conn: &PgConnection, user_id: i32) -> usize {
+ diesel::delete(user_.find(user_id))
+ .execute(conn)
+ .expect("Error deleting.")
+}
+
+pub fn create(conn: &PgConnection, new_user: &NewUser) -> Result<User_, Error> {
+ let mut edited_user = new_user.clone();
+ // Add the rust crypt
+ edited_user.password_encrypted = "here";
+ // edited_user.password_encrypted;
+ insert_into(user_)
+ .values(edited_user)
+ .get_result::<User_>(conn)
+}
+
+pub fn update(conn: &PgConnection, user_id: i32, new_user: &NewUser) -> User_ {
+ let mut edited_user = new_user.clone();
+ edited_user.password_encrypted = "here";
+ diesel::update(user_.find(user_id))
+ .set(edited_user)
+ .get_result::<User_>(conn)
+ .expect(&format!("Unable to find user {}", user_id))
+}
+
+#[cfg(test)]
+mod tests {
+ use establish_connection;
+ use super::*;
+ #[test]
+ fn test_crud() {
+ let conn = establish_connection();
+
+ let new_user = NewUser {
+ name: "thom".into(),
+ preferred_username: None,
+ password_encrypted: "nope".into(),
+ email: None
+ };
+
+ let inserted_user = create(&conn, &new_user).unwrap();
+
+ let expected_user = User_ {
+ id: inserted_user.id,
+ name: "thom".into(),
+ preferred_username: None,
+ password_encrypted: "here".into(),
+ email: None,
+ icon: None,
+ start_time: inserted_user.start_time
+ };
+
+ let read_user = read(&conn, inserted_user.id);
+ let updated_user = update(&conn, inserted_user.id, &new_user);
+ let num_deleted = delete(&conn, inserted_user.id);
+
+ assert_eq!(expected_user, read_user);
+ assert_eq!(expected_user, inserted_user);
+ assert_eq!(expected_user, updated_user);
+ assert_eq!(1, num_deleted);
+
+ }
+}
--- /dev/null
+table! {
+ community (id) {
+ id -> Int4,
+ name -> Varchar,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ community_follower (id) {
+ id -> Int4,
+ fedi_user_id -> Text,
+ community_id -> Nullable<Int4>,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ community_user (id) {
+ id -> Int4,
+ fedi_user_id -> Text,
+ community_id -> Nullable<Int4>,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ post (id) {
+ id -> Int4,
+ name -> Varchar,
+ url -> Text,
+ attributed_to -> Text,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ post_dislike (id) {
+ id -> Int4,
+ fedi_user_id -> Text,
+ post_id -> Nullable<Int4>,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ post_like (id) {
+ id -> Int4,
+ fedi_user_id -> Text,
+ post_id -> Nullable<Int4>,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ user_ (id) {
+ id -> Int4,
+ name -> Varchar,
+ preferred_username -> Nullable<Varchar>,
+ password_encrypted -> Text,
+ email -> Nullable<Text>,
+ icon -> Nullable<Bytea>,
+ start_time -> Timestamp,
+ }
+}
+
+joinable!(community_follower -> community (community_id));
+joinable!(community_user -> community (community_id));
+joinable!(post_dislike -> post (post_id));
+joinable!(post_like -> post (post_id));
+
+allow_tables_to_appear_in_same_query!(
+ community,
+ community_follower,
+ community_user,
+ post,
+ post_dislike,
+ post_like,
+ user_,
+);
extern crate diesel;
+extern crate activitypub;
use schema::user_;
use diesel::*;
use diesel::result::Error;
use schema::user_::dsl::*;
+// use self::activitypub::{context, actor::Person};
use Crud;
-#[derive(Queryable, PartialEq, Debug)]
+#[derive(Queryable, Identifiable, PartialEq, Debug)]
+#[table_name="user_"]
pub struct User_ {
pub id: i32,
pub name: String,
+ pub preferred_username: Option<String>,
pub password_encrypted: String,
pub email: Option<String>,
pub icon: Option<Vec<u8>>,
pub start_time: chrono::NaiveDateTime
}
-#[derive(Insertable)]
+#[derive(Insertable, AsChangeset, Clone, Copy)]
#[table_name="user_"]
-pub struct NewUser<'a> {
+pub struct UserForm<'a> {
pub name: &'a str,
+ pub preferred_username: Option<&'a str>,
pub password_encrypted: &'a str,
pub email: Option<&'a str>,
}
-impl Crud for User_ {
+impl<'a> Crud<UserForm<'a>> for User_ {
fn read(conn: &PgConnection, user_id: i32) -> User_ {
user_.find(user_id)
.first::<User_>(conn)
.expect("Error in query")
}
-
- fn delete(conn: &PgConnection, user_id: i32) -> usize {
+ fn delete(conn: &PgConnection, user_id: i32) -> usize {
diesel::delete(user_.find(user_id))
.execute(conn)
.expect("Error deleting.")
}
-
-// fn create<NewUser>(conn: &PgConnection, mut new_user: NewUser) -> Result<User_, Error> {
+ fn create(conn: &PgConnection, form: UserForm) -> Result<User_, Error> {
+ let mut edited_user = form.clone();
+ // Add the rust crypt
+ edited_user.password_encrypted = "here";
+ // edited_user.password_encrypted;
+ insert_into(user_)
+ .values(edited_user)
+ .get_result::<User_>(conn)
+ }
+ fn update(conn: &PgConnection, user_id: i32, form: UserForm) -> User_ {
+ let mut edited_user = form.clone();
+ edited_user.password_encrypted = "here";
+ diesel::update(user_.find(user_id))
+ .set(edited_user)
+ .get_result::<User_>(conn)
+ .expect(&format!("Unable to find user {}", user_id))
+ }
}
-pub fn create(conn: &PgConnection, mut new_user: NewUser) -> Result<User_, Error> {
- new_user.password_encrypted = "here";
- // new_user.password_encrypted;
- insert_into(user_)
- .values(new_user)
- .get_result(conn)
-}
+
+// TODO
+// pub fn person(user: &User_) -> Person {
+// let mut person = Person::default();
+// person.object_props.set_context_object(context());
+// person.ap_actor_props.set_preferred_username_string("set".into());
+
+// person
+// }
#[cfg(test)]
mod tests {
use establish_connection;
- use super::*;
+ use super::{User_, UserForm};
+ use Crud;
#[test]
fn test_crud() {
let conn = establish_connection();
- let new_user = NewUser {
+ let new_user = UserForm {
name: "thom".into(),
+ preferred_username: None,
password_encrypted: "nope".into(),
email: None
};
- let inserted_user = create(&conn, new_user).unwrap();
+ let inserted_user = User_::create(&conn, new_user).unwrap();
let expected_user = User_ {
id: inserted_user.id,
name: "thom".into(),
+ preferred_username: None,
password_encrypted: "here".into(),
email: None,
icon: None,
start_time: inserted_user.start_time
};
-
+
let read_user = User_::read(&conn, inserted_user.id);
+ let updated_user = User_::update(&conn, inserted_user.id, new_user);
let num_deleted = User_::delete(&conn, inserted_user.id);
-
+
assert_eq!(expected_user, read_user);
assert_eq!(expected_user, inserted_user);
+ assert_eq!(expected_user, updated_user);
assert_eq!(1, num_deleted);
-
}
}
+++ /dev/null
-extern crate activitypub;
-extern crate failure;
-extern crate serde_json;
-
-// fn user -> Result<(), Error> {
-
-// }
extern crate diesel;
extern crate dotenv;
-use diesel::prelude::*;
+use diesel::*;
use diesel::pg::PgConnection;
+use diesel::result::Error;
use dotenv::dotenv;
use std::env;
pub mod schema;
pub mod models;
-pub mod activitypub;
pub mod actions;
+// pub trait Likeable;
+pub trait Crud<T> {
+ fn create(conn: &PgConnection, form: T) -> Result<Self, Error> where Self: Sized;
+ fn read(conn: &PgConnection, id: i32) -> Self;
+ fn update(conn: &PgConnection, id: i32, form: T) -> Self;
+ fn delete(conn: &PgConnection, id: i32) -> usize;
+}
+
+pub trait Followable<T> {
+ fn follow(conn: &PgConnection, form: T) -> Result<Self, Error> where Self: Sized;
+ fn ignore(conn: &PgConnection, form: T) -> usize;
+}
+
+pub trait Joinable<T> {
+ fn join(conn: &PgConnection, form: T) -> Result<Self, Error> where Self: Sized;
+ fn leave(conn: &PgConnection, form: T) -> usize;
+}
+
+
pub fn establish_connection() -> PgConnection {
dotenv().ok();
.expect(&format!("Error connecting to {}", database_url))
}
-trait Crud {
- fn read(conn: &PgConnection, id: i32) -> Self;
- fn delete(conn: &PgConnection, id: i32) -> usize;
- // fn create<T: Insertable>(conn: &PgConnection, item: T) -> Result<Self, Error> where Self: Sized;
-}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn it_works() {
- assert_eq!(2 + 2, 4);
- }
-
- #[test]
- fn db_fetch() {
-
- }
-}
-enum CommunityUserType {
- CREATOR = 0,
- MODERATOR = 1,
- USER = 2
-}
+// enum CommunityUserType {
+// CREATOR = 0,
+// MODERATOR = 1,
+// USER = 2
+// }
-impl CommunityUserType {
- fn from_u32(value: u32) -> CommunityUserType {
- match value {
- 0 => CommunityUserType::CREATOR,
- 1 => CommunityUserType::MODERATOR,
- 2 => CommunityUserType::USER,
- _ => panic!("Unknown value: {}", value),
- }
- }
-}
+// impl CommunityUserType {
+// fn from_u32(value: u32) -> CommunityUserType {
+// match value {
+// 0 => CommunityUserType::CREATOR,
+// 1 => CommunityUserType::MODERATOR,
+// 2 => CommunityUserType::USER,
+// _ => panic!("Unknown value: {}", value),
+// }
+// }
+// }
community (id) {
id -> Int4,
name -> Varchar,
- starttime -> Timestamp,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ community_follower (id) {
+ id -> Int4,
+ community_id -> Int4,
+ fedi_user_id -> Text,
+ start_time -> Timestamp,
}
}
table! {
community_user (id) {
id -> Int4,
- fedi_user_id -> Varchar,
- community_id -> Nullable<Int4>,
- community_user_type -> Int2,
- starttime -> Timestamp,
+ community_id -> Int4,
+ fedi_user_id -> Text,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ post (id) {
+ id -> Int4,
+ name -> Varchar,
+ url -> Text,
+ attributed_to -> Text,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ post_dislike (id) {
+ id -> Int4,
+ fedi_user_id -> Text,
+ post_id -> Nullable<Int4>,
+ start_time -> Timestamp,
+ }
+}
+
+table! {
+ post_like (id) {
+ id -> Int4,
+ fedi_user_id -> Text,
+ post_id -> Nullable<Int4>,
+ start_time -> Timestamp,
}
}
user_ (id) {
id -> Int4,
name -> Varchar,
- password_encrypted -> Varchar,
- email -> Nullable<Varchar>,
+ preferred_username -> Nullable<Varchar>,
+ password_encrypted -> Text,
+ email -> Nullable<Text>,
icon -> Nullable<Bytea>,
- starttime -> Timestamp,
+ start_time -> Timestamp,
}
}
+joinable!(community_follower -> community (community_id));
joinable!(community_user -> community (community_id));
+joinable!(post_dislike -> post (post_id));
+joinable!(post_like -> post (post_id));
allow_tables_to_appear_in_same_query!(
community,
+ community_follower,
community_user,
+ post,
+ post_dislike,
+ post_like,
user_,
);