add: channels, messages

This commit is contained in:
trisua 2025-04-27 23:11:37 -04:00
parent 67492cf73f
commit 7774124bd0
40 changed files with 2238 additions and 115 deletions

View file

@ -190,9 +190,12 @@ pub struct UserSettings {
/// If dislikes are hidden for the user.
#[serde(default)]
pub hide_dislikes: bool,
/// The timeline that the "Home" button takes you to
/// The timeline that the "Home" button takes you to.
#[serde(default)]
pub default_timeline: DefaultTimelineChoice,
/// If other users that you aren't following can add you to chats.
#[serde(default)]
pub private_chats: bool,
}
impl Default for User {
@ -352,10 +355,12 @@ pub enum ConnectionService {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum ConnectionType {
/// A connection through a token with an expiration time.
/// A connection through a token which never expires.
Token,
/// <https://www.rfc-editor.org/rfc/rfc7636>
PKCE,
/// A connection with no stored authentication.
None,
}
#[derive(Clone, Debug, Serialize, Deserialize)]

View file

@ -18,11 +18,17 @@ pub struct Channel {
///
/// Top (0) to bottom.
pub position: usize,
/// The members of the chat (ids). Should be empty if `community > 0`.
///
/// The owner should not be a member of the channel since any member can update members.
pub members: Vec<usize>,
/// The title of the channel.
pub title: String,
}
impl Channel {
/// Create a new [`Channel`].
pub fn new(community: usize, owner: usize, position: usize) -> Self {
pub fn new(community: usize, owner: usize, position: usize, title: String) -> Self {
Self {
id: AlmostSnowflake::new(1234567890)
.to_string()
@ -34,8 +40,32 @@ impl Channel {
minimum_role_read: (CommunityPermission::DEFAULT | CommunityPermission::MEMBER).bits(),
minimum_role_write: (CommunityPermission::DEFAULT | CommunityPermission::MEMBER).bits(),
position,
members: Vec::new(),
title,
}
}
/// Check if the given `uid` can post in the channel.
pub fn check_post(&self, uid: usize, membership: Option<CommunityPermission>) -> bool {
let mut is_member = false;
if let Some(membership) = membership {
is_member = membership.bits() >= self.minimum_role_write
}
(uid == self.owner) | is_member | self.members.contains(&uid)
}
/// Check if the given `uid` can post in the channel.
pub fn check_read(&self, uid: usize, membership: Option<CommunityPermission>) -> bool {
let mut is_member = false;
if let Some(membership) = membership {
is_member = membership.bits() >= self.minimum_role_read
}
(uid == self.owner) | is_member | self.members.contains(&uid)
}
}
#[derive(Serialize, Deserialize)]

View file

@ -2,6 +2,7 @@ pub mod auth;
pub mod communities;
pub mod communities_permissions;
pub mod moderation;
pub mod oauth;
pub mod permissions;
pub mod reactions;
pub mod requests;
@ -9,6 +10,9 @@ pub mod requests;
#[cfg(feature = "redis")]
pub mod channels;
#[cfg(feature = "redis")]
pub mod socket;
use std::fmt::Display;
use serde::{Deserialize, Serialize};

View file

@ -0,0 +1,36 @@
use base64::{engine::general_purpose::URL_SAFE as base64url, Engine};
use serde::{Serialize, Deserialize};
use tetratto_shared::hash::hash;
use super::{Result, Error};
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub enum PkceChallengeMethod {
S256,
}
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub enum AppScope {
#[serde(alias = "user-read-profile")]
UserReadProfile,
}
/// Check a verifier against the stored challenge (using the given [`PkceChallengeMethod`]).
pub fn check_verifier(verifier: &str, challenge: &str, method: PkceChallengeMethod) -> Result<()> {
if method != PkceChallengeMethod::S256 {
return Err(Error::MiscError("only S256 is supported".to_string()));
}
let decoded = match base64url.decode(challenge.as_bytes()) {
Ok(hash) => hash,
Err(e) => return Err(Error::MiscError(e.to_string())),
};
let hash = hash(verifier.to_string());
if hash.as_bytes() != decoded {
// the verifier we received does not match the verifier from the stored challenge
return Err(Error::NotAllowed);
}
Ok(())
}

View file

@ -0,0 +1,23 @@
use serde::{Serialize, Deserialize, de::DeserializeOwned};
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub enum SocketMethod {
/// Authentication and channel identification.
Headers,
/// A message was sent in the channel.
Message,
/// A message was deleted in the channel.
Delete,
}
#[derive(Serialize, Deserialize)]
pub struct SocketMessage {
pub method: SocketMethod,
pub data: String,
}
impl SocketMessage {
pub fn data<T: DeserializeOwned>(&self) -> T {
serde_json::from_str(&self.data).unwrap()
}
}