mirror of
https://github.com/nullishamy/ferri.git
synced 2025-04-29 20:29:23 +00:00
Compare commits
3 commits
d59660da37
...
d252131e0d
Author | SHA1 | Date | |
---|---|---|---|
d252131e0d | |||
62931ee20b | |||
76fb8838c2 |
11 changed files with 370 additions and 124 deletions
|
@ -47,17 +47,26 @@ async fn main() {
|
|||
)
|
||||
.execute(&mut *conn)
|
||||
.await
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
|
||||
let ts = main::ap::new_ts();
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO user (id, username, actor_id, display_name)
|
||||
VALUES (?1, ?2, ?3, ?4)
|
||||
INSERT INTO user (
|
||||
id, acct, url, remote, username,
|
||||
actor_id, display_name, created_at
|
||||
)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)
|
||||
"#,
|
||||
"9b9d497b-2731-435f-a929-e609ca69dac9",
|
||||
"amy",
|
||||
"https://ferri.amy.mov/@amy",
|
||||
false,
|
||||
"amy",
|
||||
"https://ferri.amy.mov/users/9b9d497b-2731-435f-a929-e609ca69dac9",
|
||||
"amy"
|
||||
"amy",
|
||||
ts
|
||||
)
|
||||
.execute(&mut *conn)
|
||||
.await
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
pub mod ap;
|
||||
pub mod config;
|
||||
mod types_rewrite;
|
||||
pub mod types_rewrite;
|
||||
|
||||
use rand::{Rng, distributions::Alphanumeric};
|
||||
|
||||
|
|
|
@ -26,3 +26,36 @@ impl From<ap::Actor> for db::Actor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<db::User> for api::Account {
|
||||
fn from(val: db::User) -> api::Account {
|
||||
api::Account {
|
||||
id: val.id,
|
||||
username: val.username,
|
||||
acct: val.acct,
|
||||
display_name: val.display_name,
|
||||
|
||||
locked: false,
|
||||
bot: false,
|
||||
|
||||
created_at: val.created_at.to_rfc3339(),
|
||||
attribution_domains: vec![],
|
||||
|
||||
note: "".to_string(),
|
||||
url: val.url,
|
||||
|
||||
avatar: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
avatar_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
header: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
header_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
|
||||
followers_count: 0,
|
||||
following_count: 0,
|
||||
statuses_count: 0,
|
||||
last_status_at: val.posts.last_post_at.map(|ts| ts.to_rfc3339()),
|
||||
|
||||
emojis: vec![],
|
||||
fields: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
90
ferri-main/src/types_rewrite/fetch.rs
Normal file
90
ferri-main/src/types_rewrite/fetch.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
use crate::types_rewrite::{ObjectUuid, ObjectUri, db};
|
||||
use sqlx::SqliteConnection;
|
||||
use thiserror::Error;
|
||||
use tracing::info;
|
||||
use chrono::{NaiveDateTime, DateTime, Utc};
|
||||
|
||||
const SQLITE_TIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S";
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FetchError {
|
||||
#[error("an unknown error occured when fetching: {0}")]
|
||||
Unknown(String)
|
||||
}
|
||||
|
||||
fn parse_ts(ts: String) -> Option<DateTime<Utc>> {
|
||||
NaiveDateTime::parse_from_str(&ts, SQLITE_TIME_FMT)
|
||||
.ok()
|
||||
.map(|nt| nt.and_utc())
|
||||
}
|
||||
|
||||
pub async fn user_by_id(id: ObjectUuid, conn: &mut SqliteConnection) -> Result<db::User, FetchError> {
|
||||
info!("fetching user by uuid '{:?}' from the database", id);
|
||||
|
||||
let record = sqlx::query!(r#"
|
||||
SELECT
|
||||
u.id as "user_id",
|
||||
u.username,
|
||||
u.actor_id,
|
||||
u.display_name,
|
||||
a.inbox,
|
||||
a.outbox,
|
||||
u.url,
|
||||
u.acct,
|
||||
u.remote,
|
||||
u.created_at
|
||||
FROM "user" u
|
||||
INNER JOIN "actor" a ON u.actor_id = a.id
|
||||
WHERE u.id = ?1
|
||||
"#, id.0)
|
||||
.fetch_one(&mut *conn)
|
||||
.await
|
||||
.map_err(|e| FetchError::Unknown(e.to_string()))?;
|
||||
|
||||
let follower_count = sqlx::query_scalar!(r#"
|
||||
SELECT COUNT(follower_id)
|
||||
FROM "follow"
|
||||
WHERE followed_id = ?1
|
||||
"#, record.actor_id)
|
||||
.fetch_one(&mut *conn)
|
||||
.await
|
||||
.map_err(|e| FetchError::Unknown(e.to_string()))?;
|
||||
|
||||
let last_post_at = sqlx::query_scalar!(r#"
|
||||
SELECT datetime(p.created_at)
|
||||
FROM post p
|
||||
WHERE p.user_id = ?1
|
||||
ORDER BY datetime(p.created_at) DESC
|
||||
LIMIT 1
|
||||
"#, record.user_id)
|
||||
.fetch_one(&mut *conn)
|
||||
.await
|
||||
.map_err(|e| FetchError::Unknown(e.to_string()))?
|
||||
.and_then(|ts| {
|
||||
info!("parsing timestamp {}", ts);
|
||||
parse_ts(ts)
|
||||
});
|
||||
|
||||
let user_created = parse_ts(record.created_at).expect("no db corruption");
|
||||
|
||||
info!("user {:?} has {} followers", id, follower_count);
|
||||
info!("user {:?} last posted {:?}", id, last_post_at);
|
||||
|
||||
Ok(db::User {
|
||||
id: ObjectUuid(record.user_id),
|
||||
actor: db::Actor {
|
||||
id: ObjectUri(record.actor_id),
|
||||
inbox: record.inbox,
|
||||
outbox: record.outbox
|
||||
},
|
||||
acct: record.acct,
|
||||
remote: record.remote,
|
||||
username: record.username,
|
||||
display_name: record.display_name,
|
||||
created_at: user_created,
|
||||
url: record.url,
|
||||
posts: db::UserPosts {
|
||||
last_post_at
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
|
||||
mod convert;
|
||||
pub use convert::*;
|
||||
pub mod convert;
|
||||
pub mod fetch;
|
||||
|
||||
pub const AS_CONTEXT_RAW: &'static str = "https://www.w3.org/ns/activitystreams";
|
||||
pub fn as_context() -> ObjectContext {
|
||||
|
@ -16,7 +16,10 @@ pub enum ObjectContext {
|
|||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct ObjectUri(String);
|
||||
pub struct ObjectUri(pub String);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct ObjectUuid(pub String);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct Object {
|
||||
|
@ -26,15 +29,35 @@ pub struct Object {
|
|||
}
|
||||
|
||||
pub mod db {
|
||||
use serde::{Serialize, Deserialize};
|
||||
use chrono::{DateTime, Utc};
|
||||
use super::*;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Actor {
|
||||
pub id: ObjectUri,
|
||||
pub inbox: String,
|
||||
pub outbox: String,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct UserPosts {
|
||||
// User may have no posts
|
||||
pub last_post_at: Option<DateTime<Utc>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct User {
|
||||
pub id: ObjectUuid,
|
||||
pub actor: Actor,
|
||||
pub username: String,
|
||||
pub display_name: String,
|
||||
pub acct: String,
|
||||
pub remote: bool,
|
||||
pub url: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
pub posts: UserPosts
|
||||
}
|
||||
}
|
||||
|
||||
pub mod ap {
|
||||
|
@ -49,6 +72,33 @@ pub mod ap {
|
|||
pub inbox: String,
|
||||
pub outbox: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct Person {
|
||||
#[serde(flatten)]
|
||||
pub obj: Object,
|
||||
|
||||
pub following: String,
|
||||
pub followers: String,
|
||||
|
||||
pub summary: String,
|
||||
pub inbox: String,
|
||||
pub outbox: String,
|
||||
|
||||
pub preferred_username: String,
|
||||
pub name: String,
|
||||
|
||||
pub public_key: Option<UserKey>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct UserKey {
|
||||
pub id: String,
|
||||
pub owner: String,
|
||||
|
||||
#[serde(rename = "publicKeyPem")]
|
||||
pub public_key: String,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod api {
|
||||
|
@ -58,6 +108,51 @@ pub mod api {
|
|||
// API will not really use actors so treat them as DB actors
|
||||
// until we require specificity
|
||||
pub type Actor = db::Actor;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct Account {
|
||||
pub id: ObjectUuid,
|
||||
pub username: String,
|
||||
pub acct: String,
|
||||
pub display_name: String,
|
||||
|
||||
pub locked: bool,
|
||||
pub bot: bool,
|
||||
|
||||
pub created_at: String,
|
||||
pub attribution_domains: Vec<String>,
|
||||
|
||||
pub note: String,
|
||||
pub url: String,
|
||||
|
||||
pub avatar: String,
|
||||
pub avatar_static: String,
|
||||
pub header: String,
|
||||
pub header_static: String,
|
||||
|
||||
pub followers_count: i64,
|
||||
pub following_count: i64,
|
||||
pub statuses_count: i64,
|
||||
pub last_status_at: Option<String>,
|
||||
|
||||
pub emojis: Vec<Emoji>,
|
||||
pub fields: Vec<CustomField>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct Emoji {
|
||||
pub shortcode: String,
|
||||
pub url: String,
|
||||
pub static_url: String,
|
||||
pub visible_in_picker: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct CustomField {
|
||||
pub name: String,
|
||||
pub value: String,
|
||||
pub verified_at: Option<String>,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -67,6 +162,7 @@ mod tests {
|
|||
#[test]
|
||||
fn ap_actor_to_db() {
|
||||
let domain = "https://example.com";
|
||||
|
||||
let ap = ap::Actor {
|
||||
obj: Object {
|
||||
context: as_context(),
|
||||
|
|
|
@ -39,35 +39,60 @@ pub async fn home(
|
|||
config: &State<Config>,
|
||||
_user: AuthenticatedUser,
|
||||
) -> Json<Vec<TimelineStatus>> {
|
||||
let posts = sqlx::query!(
|
||||
r#"
|
||||
SELECT p.id as "post_id", u.id as "user_id", p.content, p.uri as "post_uri",
|
||||
u.username, u.display_name, u.actor_id, p.created_at, p.boosted_post_id
|
||||
FROM post p
|
||||
INNER JOIN user u on p.user_id = u.id
|
||||
#[derive(sqlx::FromRow, Debug)]
|
||||
struct Post {
|
||||
is_boost_source: bool,
|
||||
post_id: String,
|
||||
user_id: String,
|
||||
post_uri: String,
|
||||
content: String,
|
||||
created_at: String,
|
||||
boosted_post_id: Option<String>,
|
||||
display_name: String,
|
||||
username: String
|
||||
}
|
||||
|
||||
let posts = sqlx::query_as::<_, Post>(
|
||||
r#"
|
||||
WITH RECURSIVE get_home_timeline_with_boosts(
|
||||
id, boosted_post_id, is_boost_source
|
||||
) AS
|
||||
(
|
||||
SELECT p.id, p.boosted_post_id, 0 as is_boost_source
|
||||
FROM post p
|
||||
WHERE p.user_id IN (
|
||||
SELECT u.id
|
||||
FROM follow f
|
||||
INNER JOIN user u ON u.actor_id = f.followed_id
|
||||
WHERE f.follower_id = $1
|
||||
)
|
||||
UNION
|
||||
SELECT p.id, p.boosted_post_id, 1 as is_boost_source
|
||||
FROM post p
|
||||
JOIN get_home_timeline_with_boosts tl ON tl.boosted_post_id = p.id
|
||||
)
|
||||
SELECT is_boost_source, p.id as "post_id", u.id as "user_id",
|
||||
p.content, p.uri as "post_uri", u.username, u.display_name,
|
||||
u.actor_id, p.created_at, p.boosted_post_id
|
||||
FROM get_home_timeline_with_boosts
|
||||
JOIN post p ON p.id = get_home_timeline_with_boosts.id
|
||||
JOIN user u ON u.id = p.user_id;
|
||||
"#
|
||||
)
|
||||
.fetch_all(&mut **db)
|
||||
.await
|
||||
.unwrap();
|
||||
.bind("https://ferri.amy.mov/users/9b9d497b-2731-435f-a929-e609ca69dac9")
|
||||
.fetch_all(&mut **db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
dbg!(&posts);
|
||||
|
||||
let mut out = Vec::<TimelineStatus>::new();
|
||||
for record in posts {
|
||||
for record in posts.iter() {
|
||||
let mut boost: Option<Box<TimelineStatus>> = None;
|
||||
if let Some(boosted_id) = record.boosted_post_id {
|
||||
let record = sqlx::query!(
|
||||
r#"
|
||||
SELECT p.id as "post_id", u.id as "user_id", p.content, p.uri as "post_uri",
|
||||
u.username, u.display_name, u.actor_id, p.created_at, p.boosted_post_id
|
||||
FROM post p
|
||||
INNER JOIN user u on p.user_id = u.id
|
||||
WHERE p.id = ?1
|
||||
"#, boosted_id)
|
||||
.fetch_one(&mut **db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if let Some(ref boosted_id) = record.boosted_post_id {
|
||||
let user_uri = config.user_url(&record.user_id);
|
||||
let record = posts.iter().find(|p| &p.post_id == boosted_id).unwrap();
|
||||
|
||||
boost = Some(Box::new(TimelineStatus {
|
||||
id: record.post_id.clone(),
|
||||
created_at: record.created_at.clone(),
|
||||
|
@ -110,49 +135,51 @@ pub async fn home(
|
|||
},
|
||||
}))
|
||||
}
|
||||
|
||||
let user_uri = config.user_web_url(&record.username);
|
||||
out.push(TimelineStatus {
|
||||
id: record.post_id.clone(),
|
||||
created_at: record.created_at.clone(),
|
||||
in_reply_to_id: None,
|
||||
in_reply_to_account_id: None,
|
||||
content: record.content.clone(),
|
||||
visibility: "public".to_string(),
|
||||
spoiler_text: "".to_string(),
|
||||
sensitive: false,
|
||||
uri: record.post_uri.clone(),
|
||||
url: record.post_uri.clone(),
|
||||
replies_count: 0,
|
||||
reblogs_count: 0,
|
||||
favourites_count: 0,
|
||||
favourited: false,
|
||||
reblogged: false,
|
||||
reblog: boost,
|
||||
muted: false,
|
||||
bookmarked: false,
|
||||
media_attachments: vec![],
|
||||
account: CredentialAcount {
|
||||
id: record.user_id.clone(),
|
||||
username: record.username.clone(),
|
||||
acct: record.username.clone(),
|
||||
display_name: record.display_name.clone(),
|
||||
locked: false,
|
||||
bot: false,
|
||||
created_at: "2025-04-10T22:12:09Z".to_string(),
|
||||
attribution_domains: vec![],
|
||||
note: "".to_string(),
|
||||
url: user_uri,
|
||||
avatar: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
avatar_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
header: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
header_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
followers_count: 1,
|
||||
following_count: 1,
|
||||
statuses_count: 1,
|
||||
last_status_at: "2025-04-10T22:14:34Z".to_string(),
|
||||
},
|
||||
});
|
||||
|
||||
if !record.is_boost_source {
|
||||
let user_uri = config.user_web_url(&record.username);
|
||||
out.push(TimelineStatus {
|
||||
id: record.post_id.clone(),
|
||||
created_at: record.created_at.clone(),
|
||||
in_reply_to_id: None,
|
||||
in_reply_to_account_id: None,
|
||||
content: record.content.clone(),
|
||||
visibility: "public".to_string(),
|
||||
spoiler_text: "".to_string(),
|
||||
sensitive: false,
|
||||
uri: record.post_uri.clone(),
|
||||
url: record.post_uri.clone(),
|
||||
replies_count: 0,
|
||||
reblogs_count: 0,
|
||||
favourites_count: 0,
|
||||
favourited: false,
|
||||
reblogged: false,
|
||||
reblog: boost,
|
||||
muted: false,
|
||||
bookmarked: false,
|
||||
media_attachments: vec![],
|
||||
account: CredentialAcount {
|
||||
id: record.user_id.clone(),
|
||||
username: record.username.clone(),
|
||||
acct: record.username.clone(),
|
||||
display_name: record.display_name.clone(),
|
||||
locked: false,
|
||||
bot: false,
|
||||
created_at: "2025-04-10T22:12:09Z".to_string(),
|
||||
attribution_domains: vec![],
|
||||
note: "".to_string(),
|
||||
url: user_uri,
|
||||
avatar: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
avatar_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
header: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
header_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
||||
followers_count: 1,
|
||||
following_count: 1,
|
||||
statuses_count: 1,
|
||||
last_status_at: "2025-04-10T22:14:34Z".to_string(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Json(out)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use main::ap::http::HttpClient;
|
||||
use rocket::{State, get, response::status};
|
||||
use rocket_db_pools::Connection;
|
||||
use main::ap;
|
||||
|
@ -8,7 +7,7 @@ use uuid::Uuid;
|
|||
|
||||
use crate::{
|
||||
Db,
|
||||
types::{self, activity, content, webfinger},
|
||||
types::{self, webfinger},
|
||||
};
|
||||
|
||||
#[get("/finger/<account>")]
|
||||
|
@ -86,44 +85,17 @@ pub async fn resolve_user(acct: &str, host: &str) -> types::Person {
|
|||
}
|
||||
|
||||
#[get("/test")]
|
||||
pub async fn test(http: &State<HttpClient>, outbound: &State<OutboundQueue>) -> &'static str {
|
||||
pub async fn test(
|
||||
outbound: &State<OutboundQueue>,
|
||||
mut db: Connection<Db>
|
||||
) -> &'static str {
|
||||
use main::types_rewrite::{ObjectUuid, fetch, api};
|
||||
outbound.0.send(ap::QueueMessage::Heartbeat);
|
||||
|
||||
let user = resolve_user("amy@fedi.amy.mov", "fedi.amy.mov").await;
|
||||
|
||||
let post = activity::CreateActivity {
|
||||
id: "https://ferri.amy.mov/activities/amy/20".to_string(),
|
||||
ty: "Create".to_string(),
|
||||
actor: "https://ferri.amy.mov/users/amy".to_string(),
|
||||
object: content::Post {
|
||||
context: "https://www.w3.org/ns/activitystreams".to_string(),
|
||||
id: "https://ferri.amy.mov/users/amy/posts/20".to_string(),
|
||||
ty: "Note".to_string(),
|
||||
content: "My first post".to_string(),
|
||||
ts: "2025-04-10T10:48:11Z".to_string(),
|
||||
to: vec!["https://ferri.amy.mov/users/amy/followers".to_string()],
|
||||
cc: vec!["https://www.w3.org/ns/activitystreams#Public".to_string()],
|
||||
attributed_to: None
|
||||
},
|
||||
ts: "2025-04-10T10:48:11Z".to_string(),
|
||||
to: vec!["https://ferri.amy.mov/users/amy/followers".to_string()],
|
||||
cc: vec![],
|
||||
};
|
||||
|
||||
let key_id = "https://ferri.amy.mov/users/amy#main-key";
|
||||
let follow = http
|
||||
.post(user.inbox)
|
||||
.json(&post)
|
||||
.sign(key_id)
|
||||
.activity()
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.text()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
dbg!(follow);
|
||||
let id = ObjectUuid("9b9d497b-2731-435f-a929-e609ca69dac9".to_string());
|
||||
let user= dbg!(fetch::user_by_id(id, &mut **db).await.unwrap());
|
||||
let apu: api::Account = user.into();
|
||||
dbg!(apu);
|
||||
|
||||
"Hello, world!"
|
||||
}
|
||||
|
|
|
@ -50,19 +50,34 @@ async fn create_user(
|
|||
let host = url.host_str().unwrap();
|
||||
info!("creating user '{}'@'{}' ({:#?})", user.preferred_username, host, user);
|
||||
|
||||
let username = format!("{}@{}", user.preferred_username, host);
|
||||
let (acct, remote) = if host != "ferri.amy.mov" {
|
||||
(format!("{}@{}", user.preferred_username, host), true)
|
||||
} else {
|
||||
(user.preferred_username.clone(), false)
|
||||
};
|
||||
|
||||
let url = format!("https://ferri.amy.mov/{}", acct);
|
||||
|
||||
let uuid = Uuid::new_v4().to_string();
|
||||
// FIXME: Pull from user
|
||||
let ts = main::ap::new_ts();
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO user (id, username, actor_id, display_name)
|
||||
VALUES (?1, ?2, ?3, ?4)
|
||||
INSERT INTO user (
|
||||
id, acct, url, remote, username,
|
||||
actor_id, display_name, created_at
|
||||
)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)
|
||||
ON CONFLICT(actor_id) DO NOTHING;
|
||||
"#,
|
||||
uuid,
|
||||
username,
|
||||
acct,
|
||||
url,
|
||||
remote,
|
||||
user.preferred_username,
|
||||
actor,
|
||||
user.name
|
||||
user.name,
|
||||
ts
|
||||
)
|
||||
.execute(conn)
|
||||
.await
|
||||
|
|
|
@ -8,12 +8,12 @@ use rocket::{
|
|||
};
|
||||
use rocket_db_pools::Connection;
|
||||
|
||||
#[get("/oauth/authorize?<client_id>&<scope>&<redirect_uri>&<_response_type>")]
|
||||
#[get("/oauth/authorize?<client_id>&<scope>&<redirect_uri>&<response_type>")]
|
||||
pub async fn authorize(
|
||||
client_id: &str,
|
||||
scope: &str,
|
||||
redirect_uri: &str,
|
||||
_response_type: &str,
|
||||
response_type: &str,
|
||||
mut db: Connection<Db>,
|
||||
) -> Redirect {
|
||||
// For now, we will always authorize the request and assign it to an admin user
|
||||
|
|
|
@ -2,6 +2,10 @@ CREATE TABLE IF NOT EXISTS user
|
|||
(
|
||||
-- UUID
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
acct TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
remote BOOLEAN NOT NULL,
|
||||
username TEXT NOT NULL,
|
||||
actor_id TEXT NOT NULL UNIQUE,
|
||||
display_name TEXT NOT NULL,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
CREATE TABLE IF NOT EXISTS post
|
||||
(
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
uri TEXT NOT NULL,
|
||||
uri TEXT NOT NULL UNIQUE,
|
||||
user_id TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
|
|
Loading…
Add table
Reference in a new issue