Skip to content

Commit

Permalink
Post endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
SirEndii committed Nov 25, 2024
1 parent 7fc09e0 commit 5a73689
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 16 deletions.
106 changes: 106 additions & 0 deletions src/api/post.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use std::path::PathBuf;
use actix_web::{Error, get, HttpResponse, patch, put, Scope, web, post, delete};
use actix_web::web::Json;
use futures_util::StreamExt;
use log::error;
use crate::definitions::{BodyPost, BodyUser, Post, User};
use crate::storage::database_manager::DatabaseManager;
use crate::storage::storage_manager::StorageManager;

pub fn blog_service() -> Scope {
web::scope("/api/v1/posts")
.service(posts_get)
.service(post_get)
.service(post_delete)
.service(post_post)
}

#[get("")]
async fn posts_get(
user: User,
database_manager: web::Data<DatabaseManager>) -> Result<HttpResponse, Error> {

if !user.admin {
return Ok(HttpResponse::Unauthorized().finish())
}

let posts = match database_manager.fetch_posts().await {
Ok(posts) => posts,
Err(_) => {
return Ok(HttpResponse::InternalServerError().finish());
}
};
Ok(HttpResponse::Ok().json(posts))
}

#[get("/{postId}")]
async fn post_get(
path: web::Path<String>,
database_manager: web::Data<DatabaseManager>) -> Result<HttpResponse, Error> {

let post_id = path.into_inner();

let found_post: Option<Post> = match database_manager.fetch_post(post_id).await {
Ok(found_post) => {
found_post
}
Err(_) => {
return Ok(HttpResponse::InternalServerError().finish());
}
};

match found_post {
Some(found_user) => {
Ok(HttpResponse::Ok().json(found_user))
}
None => {
Ok(HttpResponse::NotFound().finish())
}
}
}

#[delete("/{postId}")]
async fn post_delete(
user: User,
path: web::Path<String>,
database_manager: web::Data<DatabaseManager>) -> Result<HttpResponse, Error> {

let post_id = path.into_inner();

if !user.admin {
return Ok(HttpResponse::Unauthorized().finish())
}

match database_manager.delete_post(post_id).await {
Ok(_) => {
Ok(HttpResponse::Ok().finish())
},
Err(_) => {
Ok(HttpResponse::InternalServerError().finish())
}
}
}

#[post("")]
async fn post_post(
user: User,
body: Json<BodyPost>,
database_manager: web::Data<DatabaseManager>) -> Result<HttpResponse, Error> {

if !user.admin {
return Ok(HttpResponse::Unauthorized().finish())
}

let post = body.into_inner();

match database_manager.add_post(post).await {
Ok(_) => {
}
Err(err) => {
error!("Could not post post {err}");
return Ok(HttpResponse::InternalServerError().finish())
}
}

Ok(HttpResponse::Ok().finish())
}
4 changes: 2 additions & 2 deletions src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use actix_web::web::{Data, Json};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use jsonwebtoken::{encode, decode, Header as JwtHeader, Algorithm, Validation, EncodingKey, DecodingKey, errors::Result as JwtResult};
use serde::{Deserialize, Serialize};
use crate::definitions::User;
use crate::definitions::{User};
use crate::storage::database_manager::DatabaseManager;

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -111,7 +111,7 @@ async fn auth_login(
if user.validate_password(login_credentials.password.clone()) {
let iat = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as usize;
let claims = Claims {
exp: iat + (24 * 60 * 60),
exp: iat + (30 * 24 * 60 * 60),
iat,
iss: "intelligence".to_string(),
sub: user.id.to_string(),
Expand Down
37 changes: 30 additions & 7 deletions src/definitions.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
use std::cmp::PartialEq;
use std::fmt;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use surrealdb::Datetime;
use surrealdb::sql::Id;

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct IntelliThing {
pub(crate) id: Id,
}

impl fmt::Display for IntelliThing {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.id)
}
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct IntelliThing {
pub(crate) id: Id,
impl PartialEq for IntelliThing {
fn eq(&self, other: &Self) -> bool {
other.id == self.id
}
}

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -27,10 +34,16 @@ pub struct User {
pub(crate) lastname: Option<String>,
}

impl PartialEq for IntelliThing {
fn eq(&self, other: &Self) -> bool {
other.id == self.id
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Post {
#[serde(serialize_with = "serialize_record_id")]
pub(crate) id: IntelliThing,
#[serde(serialize_with = "serialize_record_id")]
pub(crate) author: IntelliThing,
pub(crate) likes: i32,
pub(crate) views: i32,
pub(crate) title: String,
pub(crate) posted: Datetime,
}

impl User {
Expand Down Expand Up @@ -59,6 +72,16 @@ pub struct BodyUser {
pub(crate) lastname: Option<String>,
}

// Used by the http endpoint to allow patching the post
#[derive(Serialize, Deserialize, Debug)]
pub struct BodyPost {
#[serde(serialize_with = "serialize_option_record_id", deserialize_with = "deserialize_record_id")]
pub(crate) author: Option<IntelliThing>,
pub(crate) likes: Option<i32>,
pub(crate) views: Option<i32>,
pub(crate) title: Option<String>,
pub(crate) posted: Option<Datetime>,
}

fn serialize_record_id<S>(record_id: &IntelliThing, serializer: S) -> Result<S::Ok, S::Error>
where
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey};
use crate::auth::auth_service;

mod api { // Declare the 'api' module

pub mod post;
pub mod users;
}

Expand Down Expand Up @@ -64,6 +64,7 @@ async fn main() -> Result<(), Error> {

.service(auth_service())
.service(api::users::user_service())
.service(api::post::blog_service())
})
.workers(2)
.bind("0.0.0.0:6969")?
Expand Down
43 changes: 37 additions & 6 deletions src/storage/database_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use surrealdb::engine::remote::ws::{Client, Ws};
use surrealdb::opt::auth::{Root};
use surrealdb::{Response, Surreal};
use log::info;
use crate::definitions::{BodyUser, User};
use crate::definitions::{BodyPost, BodyUser, IntelliThing, Post, User};

#[derive(Clone)]
pub struct DatabaseManager {
Expand Down Expand Up @@ -58,11 +58,6 @@ impl DatabaseManager {
Ok(users)
}

pub async fn delete_user(&self, id: String) -> surrealdb::Result<Option<User>> {
let deleted: Option<User> = self.database.delete(("user", id)).await?;
Ok(deleted)
}

pub async fn fetch_user(&self, name_or_email: String) -> surrealdb::Result<Option<User>> {
let user: Vec<User> = self.database
.query("SELECT * FROM user WHERE name = $name OR email = $name OR id = type::thing(\"user\", $name) LIMIT 1")
Expand All @@ -73,13 +68,49 @@ impl DatabaseManager {
Ok(user.into_iter().nth(0))
}

pub async fn fetch_posts(&self) -> surrealdb::Result<Vec<Post>> {
let posts: Vec<Post> = self.database
.query("SELECT * FROM post ORDER BY posted ASC")
.await?
.take(0)?;

Ok(posts)
}

pub async fn fetch_post(&self, title_or_id: String) -> surrealdb::Result<Option<Post>> {
let post: Vec<Post> = self.database
.query("SELECT * FROM post WHERE title = $name OR id = type::thing(\"post\", $name) LIMIT 1")
.bind(("name", title_or_id))
.await?
.take(0)?;

Ok(post.into_iter().nth(0))
}

pub async fn delete_user(&self, id: String) -> surrealdb::Result<Option<User>> {
let deleted: Option<User> = self.database.delete(("user", id)).await?;
Ok(deleted)
}

pub async fn delete_post(&self, id: String) -> surrealdb::Result<Option<Post>> {
let deleted: Option<Post> = self.database.delete(("post", id)).await?;
Ok(deleted)
}

pub async fn add_user(&self, user: BodyUser) -> surrealdb::Result<Vec<User>> {
self.database
.insert("user")
.content(user)
.await
}

pub async fn add_post(&self, post: BodyPost) -> surrealdb::Result<Vec<Post>> {
self.database
.insert("post")
.content(post)
.await
}

pub async fn update_user(&self, user: &User) -> surrealdb::Result<Option<User>> {
self.database
.update(("user", user.id.to_string()))
Expand Down

0 comments on commit 5a73689

Please sign in to comment.