forked from alemi/upub
feat: db model for activity and object + routes
This commit is contained in:
parent
40cee0fc87
commit
85c9b363f6
14 changed files with 365 additions and 73 deletions
|
@ -1,4 +1,11 @@
|
|||
pub trait Activity : super::Object {
|
||||
fn actor(&self) -> Option<&super::ObjectOrLink> { None }
|
||||
fn object(&self) -> Option<&super::ObjectOrLink> { None }
|
||||
fn activity_type(&self) -> Option<super::types::ActivityType> { None }
|
||||
|
||||
fn actor_id(&self) -> Option<&str> { None }
|
||||
fn actor(&self) -> Option<&impl super::Object> { None::<&()> }
|
||||
|
||||
fn object_id(&self) -> Option<&str> { None }
|
||||
fn object(&self) -> Option<&impl super::Object> { None::<&()> }
|
||||
|
||||
fn target(&self) -> Option<&str> { None }
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ pub trait Link {
|
|||
|
||||
pub trait Object {
|
||||
fn id(&self) -> Option<&str> { None }
|
||||
fn object_type(&self) -> Option<super::Type> { None }
|
||||
fn full_type(&self) -> Option<super::Type> { None }
|
||||
fn attachment (&self) -> Option<&str> { None }
|
||||
fn attributed_to (&self) -> Option<&str> { None }
|
||||
fn audience (&self) -> Option<&str> { None }
|
||||
|
@ -41,7 +41,7 @@ pub trait Object {
|
|||
fn in_reply_to (&self) -> Option<&str> { None }
|
||||
fn location (&self) -> Option<&str> { None }
|
||||
fn preview (&self) -> Option<&str> { None }
|
||||
fn published (&self) -> Option<&str> { None }
|
||||
fn published (&self) -> Option<chrono::DateTime<chrono::Utc>> { None }
|
||||
fn replies (&self) -> Option<&str> { None }
|
||||
fn start_time (&self) -> Option<&str> { None }
|
||||
fn summary (&self) -> Option<&str> { None }
|
||||
|
@ -66,7 +66,7 @@ impl Object for serde_json::Value {
|
|||
self.get("id")?.as_str()
|
||||
}
|
||||
|
||||
fn object_type(&self) -> Option<super::Type> {
|
||||
fn full_type(&self) -> Option<super::Type> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -88,11 +88,25 @@ pub trait ToJson : Object {
|
|||
impl<T> ToJson for T where T : Object {
|
||||
fn json(&self) -> serde_json::Value {
|
||||
let mut map = serde_json::Map::new();
|
||||
let mp = &mut map;
|
||||
|
||||
if let Some(id) = self.id() {
|
||||
put_str(mp, "id", self.id());
|
||||
put_str(mp, "attributedTo", self.attributed_to());
|
||||
put_str(mp, "name", self.name());
|
||||
put_str(mp, "summary", self.summary());
|
||||
put_str(mp, "content", self.content());
|
||||
|
||||
if let Some(t) = self.full_type() {
|
||||
map.insert(
|
||||
"id".to_string(),
|
||||
serde_json::Value::String(id.to_string())
|
||||
"type".to_string(),
|
||||
serde_json::Value::String(format!("{t}")),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(published) = self.published() {
|
||||
map.insert(
|
||||
"published".to_string(),
|
||||
serde_json::Value::String(published.to_rfc3339()),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -101,3 +115,12 @@ impl<T> ToJson for T where T : Object {
|
|||
serde_json::Value::Object(map)
|
||||
}
|
||||
}
|
||||
|
||||
fn put_str(map: &mut serde_json::Map<String, serde_json::Value>, k: &str, v: Option<&str>) {
|
||||
if let Some(v) = v {
|
||||
map.insert(
|
||||
k.to_string(),
|
||||
serde_json::Value::String(v.to_string()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// TODO merge these flat maybe?
|
||||
// but then db could theoretically hold an actor with type "Like" ... idk!
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Type {
|
||||
Object,
|
||||
ObjectType(ObjectType),
|
||||
|
@ -13,56 +16,73 @@ pub enum Type {
|
|||
ActorType(ActorType),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Type {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ObjectType(x) => write!(f, "{:?}", x),
|
||||
Self::ActivityType(x) => write!(f, "{:?}", x),
|
||||
Self::ActorType(x) => write!(f, "{:?}", x),
|
||||
_ => write!(f, "{:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(sea_orm::EnumIter, sea_orm::DeriveActiveEnum, PartialEq, Eq, Debug, Clone, Copy)]
|
||||
#[sea_orm(rs_type = "i32", db_type = "Integer")]
|
||||
pub enum ActivityType {
|
||||
Accept,
|
||||
Add,
|
||||
Announce,
|
||||
Arrive,
|
||||
Block,
|
||||
Create,
|
||||
Delete,
|
||||
Dislike,
|
||||
Flag,
|
||||
Follow,
|
||||
Ignore,
|
||||
Invite,
|
||||
Join,
|
||||
Leave,
|
||||
Like,
|
||||
Listen,
|
||||
Move,
|
||||
Offer,
|
||||
Question,
|
||||
Reject,
|
||||
Read,
|
||||
Remove,
|
||||
TentativeReject,
|
||||
TentativeAccept,
|
||||
Travel,
|
||||
Undo,
|
||||
Update,
|
||||
View,
|
||||
Accept = 1,
|
||||
Add = 2,
|
||||
Announce = 3,
|
||||
Arrive = 4,
|
||||
Block = 5,
|
||||
Create = 6,
|
||||
Delete = 7,
|
||||
Dislike = 8,
|
||||
Flag = 9,
|
||||
Follow = 10,
|
||||
Ignore = 11,
|
||||
Invite = 12,
|
||||
Join = 13,
|
||||
Leave = 14,
|
||||
Like = 15,
|
||||
Listen = 16,
|
||||
Move = 17,
|
||||
Offer = 18,
|
||||
Question = 19,
|
||||
Reject = 20,
|
||||
Read = 21,
|
||||
Remove = 22,
|
||||
TentativeReject = 23,
|
||||
TentativeAccept = 24,
|
||||
Travel = 25,
|
||||
Undo = 26,
|
||||
Update = 27,
|
||||
View = 28,
|
||||
}
|
||||
|
||||
#[derive(sea_orm::EnumIter, sea_orm::DeriveActiveEnum, PartialEq, Eq, Debug, Clone, Copy)]
|
||||
#[sea_orm(rs_type = "i32", db_type = "Integer")]
|
||||
pub enum ActorType {
|
||||
Application,
|
||||
Group,
|
||||
Organization,
|
||||
Person,
|
||||
Service,
|
||||
Application = 1,
|
||||
Group = 2,
|
||||
Organization = 3,
|
||||
Person = 4,
|
||||
Service = 5,
|
||||
}
|
||||
|
||||
#[derive(sea_orm::EnumIter, sea_orm::DeriveActiveEnum, PartialEq, Eq, Debug, Clone, Copy)]
|
||||
#[sea_orm(rs_type = "i32", db_type = "Integer")]
|
||||
pub enum ObjectType {
|
||||
Article,
|
||||
Audio,
|
||||
Document,
|
||||
Event,
|
||||
Image,
|
||||
Note,
|
||||
Page,
|
||||
Place,
|
||||
Profile,
|
||||
Relationship,
|
||||
Tombstone,
|
||||
Video,
|
||||
Article = 1,
|
||||
Audio = 2,
|
||||
Document = 3,
|
||||
Event = 4,
|
||||
Image = 5,
|
||||
Note = 6,
|
||||
Page = 7,
|
||||
Place = 8,
|
||||
Profile = 9,
|
||||
Relationship = 10,
|
||||
Tombstone = 11,
|
||||
Video = 12,
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
pub mod model;
|
||||
pub mod migrations;
|
||||
pub mod activitystream;
|
||||
pub mod activitypub;
|
||||
pub mod server;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use sea_orm::Database;
|
||||
use sea_orm::{ConnectOptions, Database};
|
||||
use sea_orm_migration::MigratorTrait;
|
||||
|
||||
#[derive(Parser)]
|
||||
|
@ -43,7 +42,11 @@ async fn main() {
|
|||
.with_max_level(if args.debug { tracing::Level::DEBUG } else { tracing::Level::INFO })
|
||||
.init();
|
||||
|
||||
let db = Database::connect(&args.database)
|
||||
let mut opts = ConnectOptions::new(&args.database);
|
||||
opts
|
||||
.max_connections(1);
|
||||
|
||||
let db = Database::connect(opts)
|
||||
.await.expect("error connecting to db");
|
||||
|
||||
match args.command {
|
||||
|
|
|
@ -6,8 +6,8 @@ pub struct Migration;
|
|||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.
|
||||
create_table(
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Users::Table)
|
||||
.if_not_exists()
|
||||
|
@ -17,17 +17,65 @@ impl MigrationTrait for Migration {
|
|||
.not_null()
|
||||
.primary_key()
|
||||
)
|
||||
.col(ColumnDef::new(Users::Name).string().null())
|
||||
.col(ColumnDef::new(Users::ActorType).integer().not_null())
|
||||
.col(ColumnDef::new(Users::Name).string().not_null())
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Activities::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Activities::Id)
|
||||
.string()
|
||||
.not_null()
|
||||
.primary_key()
|
||||
)
|
||||
.col(ColumnDef::new(Activities::ActivityType).integer().not_null())
|
||||
.col(ColumnDef::new(Activities::Actor).string().not_null())
|
||||
.col(ColumnDef::new(Activities::Object).string().null())
|
||||
.col(ColumnDef::new(Activities::Target).string().null())
|
||||
.col(ColumnDef::new(Activities::Published).string().null())
|
||||
.to_owned()
|
||||
).await?;
|
||||
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Objects::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Objects::Id)
|
||||
.string()
|
||||
.not_null()
|
||||
.primary_key()
|
||||
)
|
||||
.col(ColumnDef::new(Objects::ObjectType).integer().not_null())
|
||||
.col(ColumnDef::new(Objects::AttributedTo).string().null())
|
||||
.col(ColumnDef::new(Objects::Name).string().null())
|
||||
.col(ColumnDef::new(Objects::Summary).string().null())
|
||||
.col(ColumnDef::new(Objects::Content).string().null())
|
||||
.col(ColumnDef::new(Objects::Published).string().null())
|
||||
.to_owned()
|
||||
).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager.
|
||||
drop_table(Table::drop().table(Users::Table).to_owned())
|
||||
manager
|
||||
.drop_table(Table::drop().table(Users::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_table(Table::drop().table(Activities::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.drop_table(Table::drop().table(Objects::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
@ -38,5 +86,29 @@ impl MigrationTrait for Migration {
|
|||
enum Users {
|
||||
Table,
|
||||
Id,
|
||||
ActorType,
|
||||
Name,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Activities {
|
||||
Table,
|
||||
Id,
|
||||
ActivityType,
|
||||
Actor,
|
||||
Object,
|
||||
Target,
|
||||
Published
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Objects {
|
||||
Table,
|
||||
Id,
|
||||
ObjectType,
|
||||
Name,
|
||||
Summary,
|
||||
AttributedTo,
|
||||
Content,
|
||||
Published,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
use sea_orm::entity::prelude::*;
|
||||
|
||||
use crate::activitystream;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "activities")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
/// must be https://instance.org/users/:user , even if local! TODO bad design...
|
||||
pub id: String,
|
||||
|
||||
pub activity_type: activitystream::types::ActivityType,
|
||||
pub actor: String, // TODO relates to USER
|
||||
pub object: Option<String>, // TODO relates to NOTES maybe????? maybe other tables??????
|
||||
pub target: Option<String>, // TODO relates to USER maybe??
|
||||
pub published: ChronoDateTimeUtc,
|
||||
|
||||
// TODO: origin, result, instrument
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl activitystream::Object for Model {
|
||||
fn id(&self) -> Option<&str> {
|
||||
Some(&self.id)
|
||||
}
|
||||
|
||||
fn full_type(&self) -> Option<activitystream::Type> {
|
||||
Some(activitystream::Type::ActivityType(self.activity_type))
|
||||
}
|
||||
|
||||
fn published(&self) -> Option<chrono::DateTime<chrono::Utc>> {
|
||||
Some(self.published)
|
||||
}
|
||||
}
|
||||
|
||||
impl activitystream::Activity for Model {
|
||||
fn activity_type(&self) -> Option<activitystream::types::ActivityType> {
|
||||
Some(self.activity_type)
|
||||
}
|
||||
|
||||
fn actor_id(&self) -> Option<&str> {
|
||||
Some(&self.actor)
|
||||
}
|
||||
|
||||
fn object_id(&self) -> Option<&str> {
|
||||
self.object.as_deref()
|
||||
}
|
||||
|
||||
fn target(&self) -> Option<&str> {
|
||||
self.target.as_deref()
|
||||
}
|
||||
}
|
|
@ -1,6 +1,34 @@
|
|||
|
||||
pub mod user;
|
||||
pub mod status;
|
||||
pub mod object;
|
||||
pub mod activity;
|
||||
pub mod like;
|
||||
pub mod relation;
|
||||
|
||||
pub async fn faker(db: &sea_orm::DatabaseConnection) -> Result<(), sea_orm::DbErr> {
|
||||
use sea_orm::EntityTrait;
|
||||
|
||||
user::Entity::insert(user::ActiveModel {
|
||||
id: sea_orm::Set("http://localhost:3000/users/root".into()),
|
||||
name: sea_orm::Set("root".into()),
|
||||
actor_type: sea_orm::Set(super::activitystream::types::ActorType::Person),
|
||||
}).exec(db).await?;
|
||||
|
||||
object::Entity::insert(object::ActiveModel {
|
||||
id: sea_orm::Set("http://localhost:3000/objects/4e28d30b-33c1-4336-918b-6fbe592bdd44".into()),
|
||||
name: sea_orm::Set(None),
|
||||
object_type: sea_orm::Set(crate::activitystream::types::ObjectType::Note),
|
||||
attributed_to: sea_orm::Set(Some("http://localhost:3000/users/root".into())),
|
||||
summary: sea_orm::Set(None),
|
||||
content: sea_orm::Set(Some("Hello world!".into())),
|
||||
published: sea_orm::Set(chrono::Utc::now()),
|
||||
}).exec(db).await?;
|
||||
|
||||
activity::Entity::insert(activity::ActiveModel {
|
||||
id: sea_orm::Set("http://localhost:3000/activities/ebac57e1-9828-438c-be34-a44a52de7641".into()),
|
||||
activity_type: sea_orm::Set(crate::activitystream::types::ActivityType::Create),
|
||||
actor: sea_orm::Set("http://localhost:3000/users/root".into()),
|
||||
object: sea_orm::Set(Some("http://localhost:3000/obkects/4e28d30b-33c1-4336-918b-6fbe592bdd44".into())),
|
||||
target: sea_orm::Set(None),
|
||||
published: sea_orm::Set(chrono::Utc::now()),
|
||||
}).exec(db).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
52
src/model/object.rs
Normal file
52
src/model/object.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use sea_orm::entity::prelude::*;
|
||||
|
||||
use crate::activitystream::types::ObjectType;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "objects")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
/// must be full uri!!! maybe not great?
|
||||
pub id: String,
|
||||
pub object_type: ObjectType,
|
||||
pub attributed_to: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub summary: Option<String>,
|
||||
pub content: Option<String>,
|
||||
pub published: ChronoDateTimeUtc,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl crate::activitystream::Object for Model {
|
||||
fn id(&self) -> Option<&str> {
|
||||
Some(&self.id)
|
||||
}
|
||||
|
||||
fn full_type(&self) -> Option<crate::activitystream::Type> {
|
||||
Some(crate::activitystream::Type::ObjectType(self.object_type))
|
||||
}
|
||||
|
||||
fn attributed_to (&self) -> Option<&str> {
|
||||
self.attributed_to.as_deref()
|
||||
}
|
||||
|
||||
fn name (&self) -> Option<&str> {
|
||||
self.name.as_deref()
|
||||
}
|
||||
|
||||
fn summary (&self) -> Option<&str> {
|
||||
self.summary.as_deref()
|
||||
}
|
||||
|
||||
fn content(&self) -> Option<&str> {
|
||||
self.content.as_deref()
|
||||
}
|
||||
|
||||
fn published (&self) -> Option<chrono::DateTime<chrono::Utc>> {
|
||||
Some(self.published)
|
||||
}
|
||||
}
|
|
@ -1,13 +1,18 @@
|
|||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
use crate::activitystream::{self, types::ActorType};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "users")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
/// must be user@instance.org, even if local! TODO bad design...
|
||||
pub id: String,
|
||||
pub name: Option<String>,
|
||||
|
||||
pub actor_type: ActorType,
|
||||
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
|
@ -15,12 +20,16 @@ pub enum Relation {}
|
|||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl crate::activitystream::Object for Model {
|
||||
impl activitystream::Object for Model {
|
||||
fn id(&self) -> Option<&str> {
|
||||
Some(&self.id)
|
||||
}
|
||||
|
||||
fn full_type(&self) -> Option<activitystream::Type> {
|
||||
Some(activitystream::Type::ActorType(self.actor_type))
|
||||
}
|
||||
|
||||
fn name (&self) -> Option<&str> {
|
||||
self.name.as_deref()
|
||||
Some(&self.name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||
|
||||
use crate::activitystream::object::ToJson;
|
||||
use crate::activitystream::{types::ActivityType, Object, Type};
|
||||
use crate::model::user;
|
||||
use crate::model::{activity, object, user};
|
||||
use axum::{extract::{Path, State}, http::StatusCode, routing::{get, post}, Json, Router};
|
||||
use sea_orm::{DatabaseConnection, EntityTrait};
|
||||
|
||||
|
@ -13,6 +13,7 @@ pub async fn serve(db: DatabaseConnection) {
|
|||
.route("/inbox", post(inbox))
|
||||
.route("/outbox", get(|| async { todo!() }))
|
||||
.route("/users/:id", get(user))
|
||||
.route("/activities/:id", get(activity))
|
||||
.route("/objects/:id", get(object))
|
||||
.with_state(Arc::new(db));
|
||||
|
||||
|
@ -25,7 +26,7 @@ pub async fn serve(db: DatabaseConnection) {
|
|||
}
|
||||
|
||||
async fn inbox(State(_db) : State<Arc<DatabaseConnection>>, Json(object): Json<serde_json::Value>) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||
match object.object_type() {
|
||||
match object.full_type() {
|
||||
None => { Err(StatusCode::BAD_REQUEST) },
|
||||
Some(Type::Activity) => { Err(StatusCode::UNPROCESSABLE_ENTITY) },
|
||||
Some(Type::ActivityType(ActivityType::Follow)) => { todo!() },
|
||||
|
@ -37,7 +38,8 @@ async fn inbox(State(_db) : State<Arc<DatabaseConnection>>, Json(object): Json<s
|
|||
}
|
||||
|
||||
async fn user(State(db) : State<Arc<DatabaseConnection>>, Path(id): Path<String>) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||
match user::Entity::find_by_id(id).one(db.deref()).await {
|
||||
let uri = format!("http://localhost:3000/users/{id}");
|
||||
match user::Entity::find_by_id(uri).one(db.deref()).await {
|
||||
Ok(Some(user)) => Ok(Json(user.json())),
|
||||
Ok(None) => Err(StatusCode::NOT_FOUND),
|
||||
Err(e) => {
|
||||
|
@ -47,6 +49,26 @@ async fn user(State(db) : State<Arc<DatabaseConnection>>, Path(id): Path<String>
|
|||
}
|
||||
}
|
||||
|
||||
async fn object(State(_db) : State<Arc<DatabaseConnection>>, Path(_id): Path<String>) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||
todo!()
|
||||
async fn activity(State(db) : State<Arc<DatabaseConnection>>, Path(id): Path<String>) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||
let uri = format!("http://localhost:3000/activities/{id}");
|
||||
match activity::Entity::find_by_id(uri).one(db.deref()).await {
|
||||
Ok(Some(activity)) => Ok(Json(activity.json())),
|
||||
Ok(None) => Err(StatusCode::NOT_FOUND),
|
||||
Err(e) => {
|
||||
tracing::error!("error querying for activity: {e}");
|
||||
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn object(State(db) : State<Arc<DatabaseConnection>>, Path(id): Path<String>) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||
let uri = format!("http://localhost:3000/objects/{id}");
|
||||
match object::Entity::find_by_id(uri).one(db.deref()).await {
|
||||
Ok(Some(object)) => Ok(Json(object.json())),
|
||||
Ok(None) => Err(StatusCode::NOT_FOUND),
|
||||
Err(e) => {
|
||||
tracing::error!("error querying for object: {e}");
|
||||
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue