Skip to content

Commit

Permalink
✨ Spring cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
JieningYu committed Apr 16, 2024
1 parent f7ec307 commit 9a96da3
Show file tree
Hide file tree
Showing 13 changed files with 377 additions and 222 deletions.
451 changes: 256 additions & 195 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions src/account.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Account system.

use std::{
collections::HashMap,
ops::{Deref, DerefMut},
Expand Down Expand Up @@ -53,6 +55,7 @@ pub enum Permission {
///
/// - [`Self::ViewSimpleAccount`]
ViewFullAccount,
/// Gets simple information of an account.
ViewSimpleAccount,

/// Manage notifications.
Expand Down Expand Up @@ -107,20 +110,30 @@ impl libaccount::Permission for Permission {
}
}

/// A tag of an account.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
#[serde(tag = "entry", content = "tag")]
pub enum Tag {
/// A permission group.
Permission(Permission),
/// A department.
Department(String),
/// A house.
House(House),
/// An academy.
Academy(Academy),
}

/// The entry of a [`Tag`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TagEntry {
/// A permission group.
Permission,
/// A department.
Department,
/// A house.
House,
/// An academy.
Academy,
}

Expand Down Expand Up @@ -173,6 +186,7 @@ impl libaccount::tag::UserDefinableEntry for TagEntry {
/// Containing verify sessions.
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Ext {
/// Verify sessions.
verifies: HashMap<VerifyVariant, VerifyCx>,
}

Expand All @@ -187,6 +201,7 @@ pub struct Ext {
/// Currently, the only verify session is reset password.
#[derive(Debug)]
pub struct Account {
/// The inner account.
inner: libaccount::Account<Tag, Ext>,
}

Expand Down Expand Up @@ -338,6 +353,7 @@ impl DerefMut for Account {
/// An unverified account.
#[derive(Debug)]
pub struct Unverified {
/// The inner unverified account.
inner: libaccount::Unverified<VerifyCx>,
}

Expand Down
18 changes: 15 additions & 3 deletions src/account/verify.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Account verification.

use std::{collections::HashMap, fmt::Display};

use lettre::{transport::smtp, AsyncSmtpTransport};
Expand Down Expand Up @@ -53,7 +55,9 @@ impl VerifyCx {
/// - Errors if the difference between the last request time
/// and the current time is no more than 10 minuts.
pub(super) fn update(&mut self) -> Result<Captcha, Error> {
/// The least duration between two requests.
const LEAST_DURATION: time::Duration = time::Duration::minutes(10);

let now = OffsetDateTime::now_utc();
let delta = now - self.last_req;
if delta >= LEAST_DURATION {
Expand Down Expand Up @@ -84,6 +88,7 @@ impl VerifyCx {
E: lettre::Executor,
AsyncSmtpTransport<E>: lettre::AsyncTransport<Error = smtp::Error>,
{
/// The sender name.
const SENDER: &str = "SubIT";
let captcha = self.update()?;

Expand Down Expand Up @@ -113,6 +118,7 @@ impl VerifyCx {
Ok(())
}

/// Gets the captcha.
#[inline]
pub(crate) fn captcha(&self) -> Captcha {
self.captcha
Expand All @@ -131,14 +137,16 @@ impl Default for VerifyCx {
pub struct Captcha(u32);

impl Captcha {
const DIGITS: usize = 6;
/// The number of digits of a captcha.
const DIGITS: u32 = 6;

/// Creates a new captcha randomly.
fn new() -> Self {
let mut rng = rand::thread_rng();
Self(rng.gen_range(0..1000000))
Self(rng.gen_range(0..10u32.pow(Self::DIGITS)))
}

/// Converts this captcha into the inner value.
#[inline]
pub fn into_inner(self) -> u32 {
self.0
Expand All @@ -155,7 +163,7 @@ impl Default for Captcha {
impl Display for Captcha {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let num = self.0.to_string();
for _ in num.len()..Self::DIGITS {
for _ in num.len()..Self::DIGITS as usize {
'0'.fmt(f)?;
}
num.fmt(f)
Expand All @@ -176,8 +184,12 @@ impl From<Captcha> for u32 {
}
}

/// Extra arguments for verifying an account.
///
/// See [`libaccount::ExtVerify`].
#[derive(Serialize, Deserialize)]
pub struct DescArgs {
/// The captcha.
captcha: Captcha,
}

Expand Down
8 changes: 8 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//! The configuration of the server.

use std::path::PathBuf;

use lettre::{transport::smtp, AsyncSmtpTransport};
use serde::{Deserialize, Serialize};

/// The configuration of the server.
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
/// SMTP configuration.
Expand All @@ -25,13 +28,16 @@ pub struct SMTP {
/// The SMTP Server port.
#[serde(default)]
pub port: Option<u16>,
/// The encryption type of target SMTP server.
#[serde(default)]
pub encrypt: SmtpEncryption,

/// The email address.
pub address: lettre::Address,

/// The username.
pub username: String,
/// The password.
pub password: String,

/// The auth mechanism.
Expand All @@ -43,8 +49,10 @@ pub struct SMTP {
/// The encryption type of target SMTP server.
#[derive(Debug, Serialize, Deserialize, Default)]
pub enum SmtpEncryption {
/// Use TLS.
#[default]
Tls,
/// Use STARTTLS.
StartTls,
}

Expand Down
2 changes: 1 addition & 1 deletion src/handle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ macro_rules! gd {
#[macro_export]
macro_rules! va {
($a:expr, $s:expr => $($p:ident),*$(,)?) => {{
let lazy = gd!($s, $a.account).ok_or(crate::Error::PermissionDenied)?;
let lazy = gd!($s, $a.account).ok_or($crate::Error::PermissionDenied)?;
let a = lazy.get().await?;
if a.is_token_valid(&$a.token) {
let _tags = a.tags();
Expand Down
2 changes: 1 addition & 1 deletion src/handle/notification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ pub async fn bulk_get_info<Io: IoHandle>(
.tags()
.contains_permission(&Tag::Permission(Permission::ManageNotifications));

let Some(first) = notifications.get(0).copied() else {
let Some(first) = notifications.first().copied() else {
return Ok(Json(HashMap::new()));
};
let mut select = worlds
Expand Down
16 changes: 6 additions & 10 deletions src/handle/post.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,12 +387,12 @@ pub async fn get_info<Io: IoHandle>(
let val = lazy.get().await?;

if val.creator() == Id(auth.account) || permitted_review {
return Ok(Json(Info::from_full(&val)));
Ok(Json(Info::from_full(val)))
} else if permitted_get_pub
&& matches!(val.state().status(), sms4_backend::post::Status::Approved)
&& val.time().contains(&now)
{
return Ok(Json(Info::from_simple(val)));
Ok(Json(Info::from_simple(val)))
} else {
Err(Error::PostNotFound(id))
}
Expand Down Expand Up @@ -426,7 +426,7 @@ pub async fn bulk_get_info<Io: IoHandle>(
.tags()
.contains_permission(&Tag::Permission(Permission::GetPubPost));

let Some(first) = posts.get(0).copied() else {
let Some(first) = posts.first().copied() else {
return Ok(Json(HashMap::new()));
};
let mut select = worlds
Expand Down Expand Up @@ -505,13 +505,9 @@ pub async fn modify<Io: IoHandle>(
if let Some(new_res) = req
.resources
.take()
.map(|s| s.into_iter().copied().collect::<HashSet<_>>())
.map(|s| s.iter().copied().collect::<HashSet<_>>())
{
let old_res = post
.resources()
.into_iter()
.copied()
.collect::<HashSet<_>>();
let old_res = post.resources().iter().copied().collect::<HashSet<_>>();
let new_diff = new_res
.difference(&old_res)
.copied()
Expand Down Expand Up @@ -659,7 +655,7 @@ pub async fn bulk_remove<Io: IoHandle>(

match req {
BulkRemoveReq::Posts { posts } => {
let Some(first) = posts.get(0).copied() else {
let Some(first) = posts.first().copied() else {
return Ok(());
};
let mut select = worlds
Expand Down
4 changes: 2 additions & 2 deletions src/handle/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ pub async fn get_info<Io: IoHandle>(
return Err(Error::PermissionDenied);
}
Ok(Json(Info {
variant: resource.variant(),
variant: resource.variant().clone(),
}))
}

Expand Down Expand Up @@ -272,7 +272,7 @@ pub async fn bulk_get_info<Io: IoHandle>(
infos.insert(
resource.id(),
Info {
variant: resource.variant(),
variant: resource.variant().clone(),
},
);
}
Expand Down
17 changes: 17 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! The 4th generation of SubIT Screen Management System Backend written in Rust.

#![warn(missing_docs, clippy::missing_docs_in_private_items)]

use std::sync::atomic::AtomicBool;

use account::verify::VerifyVariant;
Expand All @@ -14,15 +18,20 @@ pub mod post;

pub mod resource;

/// Global test flag.
pub static IS_TEST: AtomicBool = AtomicBool::new(false);

/// The test context for testing.
#[derive(Debug, Default)]
pub struct TestCx {
/// The captcha for testing.
pub captcha: tokio::sync::Mutex<Option<account::verify::Captcha>>,
}

/// Error type.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
#[allow(missing_docs)]
pub enum Error {
#[error("account error: {0}")]
LibAccount(libaccount::Error),
Expand Down Expand Up @@ -93,6 +102,7 @@ pub enum Error {
}

impl Error {
/// Converts the error to a status code.
pub fn to_status_code(&self) -> StatusCode {
match self {
Error::VerifySessionNotFound(_)
Expand All @@ -118,8 +128,10 @@ impl Error {
impl IntoResponse for Error {
#[inline]
fn into_response(self) -> axum::response::Response {
/// Error info struct.
#[derive(Serialize)]
struct ErrorInfo {
/// Error message.
error: String,
}
(
Expand Down Expand Up @@ -155,7 +167,9 @@ impl_from! {
dmds::Error => Database,
}

/// Id type.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[repr(transparent)]
pub struct Id(pub u64);

impl Serialize for Id {
Expand All @@ -174,10 +188,13 @@ impl<'de> Deserialize<'de> for Id {
where
D: serde::Deserializer<'de>,
{
/// Deserialization representation.
#[derive(Deserialize)]
#[serde(untagged)]
enum Repr<'a> {
/// Number representation.
Num(u64),
/// String slice representation.
Str(&'a str),
}

Expand Down
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{sync::Arc, time::Duration};
use std::sync::Arc;

use axum::Router;
use dmds::{world, IoHandle, World};
Expand All @@ -16,7 +16,7 @@ macro_rules! ipc {
#[tokio::main]
async fn main() {
let config: Config = {
const CFG_PATH: &'static str = "config.json";
const CFG_PATH: &str = "config.json";
let mut config_file = std::fs::File::open(CFG_PATH).expect("failed to open config file");
serde_json::from_reader(&mut config_file).expect("failed to parse config file")
};
Expand Down Expand Up @@ -51,7 +51,7 @@ async fn main() {

macro_rules! daemon {
($($i:ident => $s:expr),*$(,)?) => {
$(tokio::spawn(dmds_tokio_fs::daemon(state.worlds.$i.clone(), Duration::from_secs($s)));)*
$(tokio::spawn(dmds_tokio_fs::daemon(state.worlds.$i.clone(), std::time::Duration::from_secs($s)));)*
};
}

Expand Down
5 changes: 3 additions & 2 deletions src/notification.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Notification sent by admins, and displayed by the screens.

use std::{
hash::{Hash, Hasher},
time::SystemTime,
Expand All @@ -6,8 +8,7 @@ use std::{
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;

/// Notification sent by admins, and displayed
/// by the screens.
/// Notification sent by admins, and displayed by the screens.
///
/// # dmds Dimensions
///
Expand Down
Loading

0 comments on commit 9a96da3

Please sign in to comment.