use crate::routes::well_known::{FingerRequestQuery, FingerResponse};
use crate::{CommentLocalID, CommunityLocalID, PostLocalID, UserLocalID};
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::future::Future;
use std::sync::Arc;
mod comments;
mod communities;
mod forgot_password;
mod media;
mod posts;
mod stable;
mod users;
lazy_static::lazy_static! {
static ref USERNAME_ALLOWED_CHARS: HashSet<char> = {
use unic_char_range::chars;
chars!('a'..='z').into_iter().chain(chars!('A'..='Z')).chain(chars!('0'..='9')).chain(std::iter::once('_'))
.collect()
};
}
#[derive(Deserialize)]
#[serde(rename_all = "snake_case")]
enum SortType {
Hot,
New,
}
impl SortType {
pub fn post_sort_sql(&self) -> &'static str {
match self {
SortType::Hot => "hot_rank((SELECT COUNT(*) FROM post_like WHERE post = post.id AND person != post.author), post.created) DESC",
SortType::New => "post.created DESC",
}
}
}
#[derive(Serialize)]
struct JustID<T: serde::Serialize> {
pub id: T,
}
#[derive(Deserialize)]
struct MaybeIncludeYour {
#[serde(default)]
pub include_your: bool,
}
#[derive(Serialize)]
struct RespAvatarInfo<'a> {
url: Cow<'a, str>,
}
#[derive(Serialize)]
struct RespMinimalAuthorInfo<'a> {
id: UserLocalID,
username: Cow<'a, str>,
local: bool,
host: Cow<'a, str>,
remote_url: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
avatar: Option<RespAvatarInfo<'a>>,
}
#[derive(Serialize)]
struct RespLoginUserInfo<'a> {
id: UserLocalID,
username: &'a str,
is_site_admin: bool,
has_unread_notifications: bool,
}
#[derive(Serialize)]
struct JustUser<'a> {
user: RespMinimalAuthorInfo<'a>,
}
#[derive(Serialize)]
struct RespMinimalCommunityInfo<'a> {
id: CommunityLocalID,
name: &'a str,
local: bool,
host: Cow<'a, str>,
remote_url: Option<&'a str>,
}
#[derive(Serialize)]
struct RespMinimalPostInfo<'a> {
id: PostLocalID,
title: &'a str,
}
#[derive(Serialize)]
struct RespPostListPost<'a> {
id: PostLocalID,
title: &'a str,
href: Option<Cow<'a, str>>,
content_text: Option<&'a str>,
#[serde(rename = "content_html")]
content_html_safe: Option<String>,
author: Option<&'a RespMinimalAuthorInfo<'a>>,
created: &'a str,
community: &'a RespMinimalCommunityInfo<'a>,
score: i64,
#[serde(skip_serializing_if = "Option::is_none")]
your_vote: Option<Option<crate::Empty>>,
}
#[derive(Serialize)]
struct RespMinimalCommentInfo<'a> {
id: CommentLocalID,
content_text: Option<Cow<'a, str>>,
#[serde(rename = "content_html")]
content_html_safe: Option<String>,
}
#[derive(Serialize)]
struct JustURL<'a> {
url: Cow<'a, str>,
}
#[derive(Serialize)]
struct RespPostCommentInfo<'a> {
#[serde(flatten)]
base: RespMinimalCommentInfo<'a>,
attachments: Vec<JustURL<'a>>,
author: Option<RespMinimalAuthorInfo<'a>>,
created: String,
deleted: bool,
local: bool,
replies: Option<Vec<RespPostCommentInfo<'a>>>,
has_replies: bool,
score: i64,
#[serde(skip_serializing_if = "Option::is_none")]
your_vote: Option<Option<crate::Empty>>,
}
#[derive(Serialize)]
#[serde(tag = "type")]
enum RespThingInfo<'a> {
#[serde(rename = "post")]
Post {
id: PostLocalID,
href: Option<Cow<'a, str>>,
title: &'a str,
created: String,
community: RespMinimalCommunityInfo<'a>,
},
#[serde(rename = "comment")]
Comment {
#[serde(flatten)]
base: RespMinimalCommentInfo<'a>,
created: String,
post: RespMinimalPostInfo<'a>,
},
}
pub fn route_api() -> crate::RouteNode<()> {
crate::RouteNode::new()
.with_child(
"unstable",
crate::RouteNode::new()
.with_child(
"actors:lookup",
crate::RouteNode::new().with_child_str(
crate::RouteNode::new()
.with_handler_async("GET", route_unstable_actors_lookup),
),
)
.with_child(
"logins",
crate::RouteNode::new()
.with_handler_async("POST", route_unstable_logins_create)
.with_child(
"~current",
crate::RouteNode::new()
.with_handler_async("GET", route_unstable_logins_current_get)
.with_handler_async("DELETE", route_unstable_logins_current_delete),
),
)
.with_child("media", media::route_media())
.with_child(
"nodeinfo/2.0",
crate::RouteNode::new()
.with_handler_async("GET", route_unstable_nodeinfo_20_get),
)
.