Add canapi and try to use for the API

This commit is contained in:
Bat 2018-09-19 15:49:34 +01:00
parent eb24ba1774
commit 1500267125
16 changed files with 211 additions and 10 deletions

22
Cargo.lock generated
View File

@ -236,6 +236,14 @@ dependencies = [
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "canapi"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cc"
version = "1.0.24"
@ -1478,6 +1486,15 @@ dependencies = [
"workerpool 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "plume-api"
version = "0.1.0"
dependencies = [
"canapi 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.77 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "plume-common"
version = "0.2.0"
@ -1510,11 +1527,13 @@ dependencies = [
"activitypub 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ammonia 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bcrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"canapi 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.11 (registry+https://github.com/rust-lang/crates.io-index)",
"plume-api 0.1.0",
"plume-common 0.2.0",
"reqwest 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=55459db7732b9a240826a5c120c650f87e3372ce)",
@ -2745,6 +2764,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781"
"checksum bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0ce55bd354b095246fc34caf4e9e242f5297a7fd938b090cadfea6eee614aa62"
"checksum canapi 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3e02a04f44b531d851d2db62f95aabf65d033a6724767a4bed9732563e9bc4"
"checksum cc 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "70f2a88c2e69ceee91c209d8ef25b81fc1a65f42c7f14dfd59d1fed189e514d1"
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
"checksum chomp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f74ad218e66339b11fd23f693fb8f1d621e80ba6ac218297be26073365d163d"

View File

@ -58,4 +58,4 @@ git = "https://github.com/BaptisteGelez/rocket_i18n"
rev = "75a3bfd7b847324c078a355a7f101f8241a9f59b"
[workspace]
members = ["plume-models", "plume-common"]
members = ["plume-api", "plume-models", "plume-common"]

15
docs/API.md Normal file
View File

@ -0,0 +1,15 @@
<script src="//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
<div id="api"></div>
<script>
const ui = SwaggerUIBundle({
url: "/Plume/api.yaml",
dom_id: '#api',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
layout: "StandaloneLayout"
})
</script>

45
docs/api.yaml Normal file
View File

@ -0,0 +1,45 @@
openapi: "3.0"
info:
version: "1.0.0"
title: "Plume REST API"
servers:
- url: http://localhost:7878/api/v1
description: Your local instance
- url: https://baptiste.gelez.xyz/api/v1
description: Demo instance
paths:
/posts/{id}:
get:
description:
Retrieves a post by its ID.
responses:
'200':
The post was found
'403':
The post exists, but you don't have the rights to fetch it (it is probably a private draft)
'404':
The post was not found
/posts/:
get:
description:
List posts.
definitions:
Post:
type: "object"
properties:
title:
type: "string"
example: "Hello, world!"
id:
type: "integer"
format: "int64"
example: 42
subtitle:
type: "string"
example: "My first post."
content:
type: "string"
format: "<p>This is my first post. Thanks for reading.</p>"

9
plume-api/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "plume-api"
version = "0.1.0"
authors = ["Bat' <baptiste@gelez.xyz>"]
[dependencies]
canapi = "0.1"
serde = "1.0"
serde_derive = "1.0"

18
plume-api/src/lib.rs Normal file
View File

@ -0,0 +1,18 @@
extern crate canapi;
extern crate serde;
#[macro_use]
extern crate serde_derive;
macro_rules! api {
($url:expr => $ep:ty) => {
impl Endpoint for $ep {
type Id = i32;
fn endpoint() -> &'static str {
$url
}
}
};
}
pub mod posts;

11
plume-api/src/posts.rs Normal file
View File

@ -0,0 +1,11 @@
use canapi::Endpoint;
#[derive(Default, Serialize, Deserialize)]
pub struct PostEndpoint {
pub id: Option<i32>,
pub title: Option<String>,
pub subtitle: Option<String>,
pub content: Option<String>
}
api!("/api/v1/posts" => PostEndpoint);

View File

@ -7,6 +7,7 @@ authors = ["Baptiste Gelez <baptiste@gelez.xyz>"]
activitypub = "0.1.1"
ammonia = "1.2.0"
bcrypt = "0.2"
canapi = "0.1"
heck = "0.3.0"
lazy_static = "*"
openssl = "0.10.11"
@ -25,6 +26,9 @@ version = "0.4"
features = ["postgres", "r2d2", "chrono"]
version = "1.3.2"
[dependencies.plume-api]
path = "../plume-api"
[dependencies.plume-common]
path = "../plume-common"

View File

@ -3,6 +3,7 @@ use activitypub::{
link,
object::{Note}
};
use canapi::Provider;
use chrono;
use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, dsl::any};
use serde_json;

View File

@ -3,6 +3,7 @@
extern crate activitypub;
extern crate ammonia;
extern crate bcrypt;
extern crate canapi;
extern crate chrono;
#[macro_use]
extern crate diesel;
@ -10,6 +11,7 @@ extern crate heck;
#[macro_use]
extern crate lazy_static;
extern crate openssl;
extern crate plume_api;
extern crate plume_common;
extern crate reqwest;
extern crate rocket;

View File

@ -1,4 +1,5 @@
use activitypub::activity;
use canapi::Provider;
use chrono;
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};

View File

@ -3,11 +3,13 @@ use activitypub::{
link,
object::{Article, Tombstone}
};
use canapi::{Error, Provider};
use chrono::{NaiveDateTime, TimeZone, Utc};
use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, BelongingToDsl, dsl::any};
use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, BelongingToDsl, dsl::any, Expression, BoolExpressionMethods};
use heck::KebabCase;
use serde_json;
use plume_api::posts::PostEndpoint;
use plume_common::activity_pub::{
Hashtag, Source,
PUBLIC_VISIBILTY, Id, IntoId,
@ -55,6 +57,56 @@ pub struct NewPost {
pub source: String,
}
impl Provider<PgConnection> for Post {
type Data = PostEndpoint;
fn get(conn: &PgConnection, id: i32) -> Result<PostEndpoint, Error> {
Post::get(conn, id).map(|p| Ok(PostEndpoint {
id: Some(p.id),
title: Some(p.title.clone()),
subtitle: Some(p.subtitle.clone()),
content: Some(p.content.get().clone())
})).unwrap_or(Err(Error::NotFound("Get Post".to_string())))
}
fn list(conn: &PgConnection, filter: PostEndpoint) -> Vec<PostEndpoint> {
let mut filters = Vec::new();
if let Some(title) = filter.title {
filters.push(posts::title.eq(title));
}
let filters = filters.into_iter();
let res = if let Some(first_filter) = filters.next() {
posts::table.filter(filters.fold(first_filter, |q, f| q.and(f)))
.get_results::<Post>(conn)
} else {
posts::table.get_results::<Post>(conn)
};
res.map(|ps| ps.into_iter()
.map(|p| PostEndpoint {
id: Some(p.id),
title: Some(p.title.clone()),
subtitle: Some(p.subtitle.clone()),
content: Some(p.content.get().clone())
})
.collect()
).unwrap_or(vec![])
}
fn create(conn: &PgConnection, query: PostEndpoint) -> Result<PostEndpoint, Error> {
}
fn update(conn: &PgConnection, id: i32, new_data: PostEndpoint) -> Result<PostEndpoint, Error> {
}
fn delete(conn: &PgConnection, id: i32) {
Post::get(conn, id).map(|p| p.delete(conn));
}
}
impl Post {
insert!(posts, NewPost);
get!(posts);

View File

@ -325,7 +325,8 @@ msgstr[1] "{{ count }} autoras en este blog: "
msgid "Login or use your Fediverse account to interact with this article"
msgstr ""
"Conéctese ou utilice a súa conta no fediverso para interactuar con este artigo"
"Conéctese ou utilice a súa conta no fediverso para interactuar con este "
"artigo"
msgid "Optional"
msgstr "Opcional"
@ -486,7 +487,6 @@ msgstr "Descrición"
msgid "Content warning"
msgstr "Aviso sobre o contido"
msgid "File"
msgstr "Ficheiro"
@ -496,7 +496,8 @@ msgstr "Enviar"
msgid ""
"Sorry, but registrations are closed on this instance. Try to find another one"
msgstr ""
"Lamentámolo, pero o rexistro está pechado en esta instancia. Intente atopar outra"
"Lamentámolo, pero o rexistro está pechado en esta instancia. Intente atopar "
"outra"
msgid "Subtitle"
msgstr "Subtítulo"
@ -553,9 +554,10 @@ msgid ""
"Something is wrong with your CSRF token. Make sure cookies are enabled in "
"you browser, and try reloading this page. If you continue to see this error "
"message, please report it."
msgstr "Hai un problema co seu testemuño CSRF. Asegúrese de ter as cookies activadas "
"no navegador, e recargue a páxina. Si persiste o aviso de este fallo, "
" informe por favor."
msgstr ""
"Hai un problema co seu testemuño CSRF. Asegúrese de ter as cookies activadas "
"no navegador, e recargue a páxina. Si persiste o aviso de este fallo, "
"informe por favor."
msgid "Administration of {{ instance.name }}"
msgstr "Administración de {{ instance_name }}"
@ -600,7 +602,12 @@ msgid "Delete your account"
msgstr "Eliminar a súa conta"
msgid "Sorry, but as an admin, you can't leave your instance."
msgstr "Lamentámolo, pero como administradora, non pode deixar a súa instancia."
msgstr ""
"Lamentámolo, pero como administradora, non pode deixar a súa instancia."
msgid "Users"
msgstr "Usuarias"
#, fuzzy
msgid "This post isn't published yet."
msgstr "Esto é un borrador, non publicar por agora."

1
src/api/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod posts;

11
src/api/posts.rs Normal file
View File

@ -0,0 +1,11 @@
use rocket_contrib::Json;
use serde_json;
use plume_models::db_conn::DbConn;
use plume_models::posts::Post;
#[get("/posts/<id>")]
fn get(id: i32, conn: DbConn) -> Json<serde_json::Value> {
let post = Post::get(&*conn, id).unwrap();
Json(post.to_json(&*conn))
}

View File

@ -36,6 +36,7 @@ use rocket_contrib::Template;
use rocket_csrf::CsrfFairingBuilder;
use workerpool::{Pool, thunk::ThunkWorker};
mod api;
mod inbox;
mod setup;
mod routes;
@ -142,6 +143,9 @@ fn main() {
routes::errors::csrf_violation
])
.mount("/api/v1", routes![
api::posts::get
])
.catch(catchers![
routes::errors::not_found,
routes::errors::server_error