initial commit

This commit is contained in:
postscriptum 2025-07-01 17:39:30 +03:00
commit 63f53528dc
10 changed files with 443 additions and 0 deletions

52
src/snac/user.rs Normal file
View file

@ -0,0 +1,52 @@
mod public;
use anyhow::{Result, bail};
use public::Post;
use std::path::PathBuf;
pub struct User {
pub name: String,
pub public: PathBuf,
}
impl User {
pub fn init(storage: &PathBuf, name: String) -> Result<Self> {
Ok(Self {
public: init(storage, &name, "public")?,
name,
})
}
pub fn public(&self) -> Result<Vec<Post>> {
use std::{
fs::{File, read_dir},
io::BufReader,
};
let entries = read_dir(&self.public)?;
let mut posts = Vec::with_capacity(100); // @TODO
for entry in entries {
let e = entry?;
if !e.file_type()?.is_file() {
continue;
}
let post: Post = serde_json::from_reader(BufReader::new(File::open(e.path())?))?;
posts.push(post)
}
Ok(posts)
}
}
fn init(storage: &PathBuf, name: &str, target: &str) -> Result<PathBuf> {
let mut p = PathBuf::from(&storage);
p.push("user");
p.push(name);
p.push(target);
if !p.exists() || !p.is_dir() {
bail!("User data location `{}` not found!", p.to_string_lossy());
}
Ok(p)
}

43
src/snac/user/public.rs Normal file
View file

@ -0,0 +1,43 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, de::Error};
use std::str::FromStr;
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Attachment {
pub media_type: String,
pub url: String,
pub name: String,
}
#[derive(Deserialize, Debug)]
pub struct Tag {
pub name: String,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Post {
pub attachment: Option<Vec<Attachment>>,
pub id: String,
#[serde(default, deserialize_with = "time")]
pub published: DateTime<Utc>,
pub source_content: Option<String>,
pub tag: Option<Vec<Tag>>,
#[serde(default, deserialize_with = "time_option")]
pub updated: Option<DateTime<Utc>>,
pub url: String,
}
fn time<'de, D: serde::Deserializer<'de>>(d: D) -> Result<DateTime<Utc>, D::Error> {
let s = String::deserialize(d)?;
DateTime::from_str(&s).map_err(Error::custom)
}
fn time_option<'de, D: serde::Deserializer<'de>>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> {
let s: Option<String> = Option::deserialize(d)?;
match s {
Some(ref t) => DateTime::from_str(t).map(Some).map_err(Error::custom),
None => Ok(None),
}
}