mirror of
https://github.com/perfect-panel/ppanel-web.git
synced 2026-08-29 14:02:08 -04:00
Initial
This commit is contained in:
@@ -0,0 +1,512 @@
|
||||
//! Adapter module — ports Go `server/adapter` package to Rust.
|
||||
//!
|
||||
//! Provides:
|
||||
//! - [`Proxy`] – per-proxy configuration struct (mirrors Go `Proxy`)
|
||||
//! - [`User`] – subscriber info (mirrors Go `User`)
|
||||
//! - [`ClientConfig`] – template-rendering config
|
||||
//! - [`Client`] – renders a Go-template with a sprig subset
|
||||
//! - [`Adapter`] – converts `Node`+`Server` entities into `Vec<Proxy>`
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Context as _;
|
||||
use base64::{engine::general_purpose::STANDARD as B64, Engine as _};
|
||||
use chrono::TimeZone as _;
|
||||
|
||||
use crate::model::entity::node::{Node, Protocol as NodeProtocol, Server};
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Proxy
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Full proxy configuration, mirroring the Go `Proxy` struct in `adapter/client.go`.
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
pub struct Proxy {
|
||||
pub sort: i32,
|
||||
pub name: String,
|
||||
pub server: String,
|
||||
pub port: i32,
|
||||
#[serde(rename = "Type")]
|
||||
pub type_: String,
|
||||
pub tags: Vec<String>,
|
||||
|
||||
// Security
|
||||
pub security: Option<String>,
|
||||
pub sni: Option<String>,
|
||||
pub allow_insecure: bool,
|
||||
pub fingerprint: Option<String>,
|
||||
pub reality_server_addr: Option<String>,
|
||||
pub reality_server_port: i32,
|
||||
pub reality_private_key: Option<String>,
|
||||
pub reality_public_key: Option<String>,
|
||||
pub reality_short_id: Option<String>,
|
||||
|
||||
// Transport
|
||||
pub transport: Option<String>,
|
||||
pub host: Option<String>,
|
||||
pub path: Option<String>,
|
||||
pub service_name: Option<String>,
|
||||
|
||||
// Shadowsocks
|
||||
pub method: Option<String>,
|
||||
pub server_key: Option<String>,
|
||||
pub uot: bool,
|
||||
pub uot_version: i32,
|
||||
|
||||
// Vmess/Vless/Trojan
|
||||
pub flow: Option<String>,
|
||||
|
||||
// Hysteria2
|
||||
pub hop_ports: Option<String>,
|
||||
pub hop_interval: i32,
|
||||
pub obfs_password: Option<String>,
|
||||
pub up_mbps: i32,
|
||||
pub down_mbps: i32,
|
||||
|
||||
// TUIC
|
||||
pub disable_sni: bool,
|
||||
pub reduce_rtt: bool,
|
||||
pub udp_relay_mode: Option<String>,
|
||||
pub congestion_controller: Option<String>,
|
||||
|
||||
// AnyTLS
|
||||
pub padding_scheme: Option<String>,
|
||||
|
||||
// Mieru
|
||||
pub multiplex: Option<String>,
|
||||
|
||||
// Vless xhttp
|
||||
pub xhttp_mode: Option<String>,
|
||||
pub xhttp_extra: Option<String>,
|
||||
|
||||
// Encryption
|
||||
pub encryption: Option<String>,
|
||||
pub encryption_mode: Option<String>,
|
||||
pub encryption_rtt: Option<String>,
|
||||
pub encryption_ticket: Option<String>,
|
||||
pub encryption_server_padding: Option<String>,
|
||||
pub encryption_private_key: Option<String>,
|
||||
pub encryption_client_padding: Option<String>,
|
||||
pub encryption_password: Option<String>,
|
||||
|
||||
// ECH
|
||||
pub ech_enable: bool,
|
||||
pub ech_server_name: Option<String>,
|
||||
|
||||
// Misc
|
||||
pub ratio: f64,
|
||||
pub cert_mode: Option<String>,
|
||||
pub cert_dns_provider: Option<String>,
|
||||
pub cert_dns_env: Option<String>,
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// User
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Subscriber / user info passed to templates (mirrors Go `User`).
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
||||
pub struct User {
|
||||
pub password: String,
|
||||
/// Unix timestamp (seconds).
|
||||
pub expired_at: i64,
|
||||
pub download: i64,
|
||||
pub upload: i64,
|
||||
pub traffic: i64,
|
||||
pub subscribe_url: String,
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// ClientConfig
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Configuration for a [`Client`] instance.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ClientConfig {
|
||||
pub site_name: String,
|
||||
pub subscribe_name: String,
|
||||
/// Output format, e.g. `"base64"`, `"yaml"`, `"json"`.
|
||||
pub output_format: String,
|
||||
pub params: HashMap<String, String>,
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Client
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Renders a Go-compatible template with a sprig-subset function map.
|
||||
pub struct Client {
|
||||
pub config: ClientConfig,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Render `template` against `proxies` and `user`.
|
||||
///
|
||||
/// Mirrors Go `(*Client).Build()`.
|
||||
pub fn build(&self, template: &str, proxies: &[Proxy], user: &User) -> anyhow::Result<String> {
|
||||
let mut tmpl = gtmpl::Template::default();
|
||||
|
||||
// Register sprig-subset functions.
|
||||
tmpl.add_func("toJson", sprig_to_json);
|
||||
tmpl.add_func("b64enc", sprig_b64enc);
|
||||
tmpl.add_func("date", sprig_date);
|
||||
|
||||
tmpl.parse(template)
|
||||
.map_err(|e| anyhow::anyhow!("template parse error: {e}"))?;
|
||||
|
||||
// Serialize each proxy to a serde_json::Value, then lift to gtmpl::Value.
|
||||
let proxy_values: Vec<gtmpl::Value> = proxies
|
||||
.iter()
|
||||
.map(|p| {
|
||||
let json = serde_json::to_value(p)
|
||||
.context("serialize Proxy to JSON")?;
|
||||
Ok(json_to_gtmpl(json))
|
||||
})
|
||||
.collect::<anyhow::Result<_>>()?;
|
||||
|
||||
let user_value = json_to_gtmpl(
|
||||
serde_json::to_value(user).context("serialize User to JSON")?,
|
||||
);
|
||||
|
||||
let params_value = {
|
||||
let map: HashMap<String, gtmpl::Value> = self
|
||||
.config
|
||||
.params
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), gtmpl::Value::String(v.clone())))
|
||||
.collect();
|
||||
gtmpl::Value::Map(map)
|
||||
};
|
||||
|
||||
let mut ctx: HashMap<String, gtmpl::Value> = HashMap::new();
|
||||
ctx.insert(
|
||||
"SiteName".into(),
|
||||
gtmpl::Value::String(self.config.site_name.clone()),
|
||||
);
|
||||
ctx.insert(
|
||||
"SubscribeName".into(),
|
||||
gtmpl::Value::String(self.config.subscribe_name.clone()),
|
||||
);
|
||||
ctx.insert(
|
||||
"OutputFormat".into(),
|
||||
gtmpl::Value::String(self.config.output_format.clone()),
|
||||
);
|
||||
ctx.insert("Proxies".into(), gtmpl::Value::Array(proxy_values));
|
||||
ctx.insert("UserInfo".into(), user_value);
|
||||
ctx.insert("Params".into(), params_value);
|
||||
|
||||
let rendered = tmpl
|
||||
.render(>mpl::Context::from(gtmpl::Value::Map(ctx)))
|
||||
.map_err(|e| anyhow::anyhow!("template render error: {e}"))?;
|
||||
|
||||
if self.config.output_format == "base64" {
|
||||
return Ok(B64.encode(rendered.as_bytes()));
|
||||
}
|
||||
|
||||
Ok(rendered)
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// JSON ↔ gtmpl::Value conversion
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
fn json_to_gtmpl(v: serde_json::Value) -> gtmpl::Value {
|
||||
match v {
|
||||
serde_json::Value::Null => gtmpl::Value::Nil,
|
||||
serde_json::Value::Bool(b) => gtmpl::Value::Bool(b),
|
||||
serde_json::Value::Number(n) => {
|
||||
if let Some(i) = n.as_i64() {
|
||||
gtmpl::Value::Number(gtmpl_value::Number::from(i))
|
||||
} else if let Some(f) = n.as_f64() {
|
||||
gtmpl::Value::Number(gtmpl_value::Number::from(f))
|
||||
} else {
|
||||
gtmpl::Value::Number(gtmpl_value::Number::from(0_i64))
|
||||
}
|
||||
}
|
||||
serde_json::Value::String(s) => gtmpl::Value::String(s),
|
||||
serde_json::Value::Array(arr) => {
|
||||
gtmpl::Value::Array(arr.into_iter().map(json_to_gtmpl).collect())
|
||||
}
|
||||
serde_json::Value::Object(map) => {
|
||||
let m: HashMap<String, gtmpl::Value> =
|
||||
map.into_iter().map(|(k, v)| (k, json_to_gtmpl(v))).collect();
|
||||
gtmpl::Value::Map(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Sprig-subset template functions
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// `toJson` — serialises first argument to a JSON string.
|
||||
fn sprig_to_json(args: &[gtmpl::Value]) -> Result<gtmpl::Value, gtmpl_value::FuncError> {
|
||||
let v = args
|
||||
.first()
|
||||
.ok_or_else(|| gtmpl_value::FuncError::AtLeastXArgs("toJson".into(), 1))?;
|
||||
|
||||
// Convert gtmpl::Value back through serde to produce JSON.
|
||||
let json_val = gtmpl_value_to_json(v.clone());
|
||||
let s = serde_json::to_string(&json_val).unwrap_or_else(|_| "null".into());
|
||||
Ok(gtmpl::Value::String(s))
|
||||
}
|
||||
|
||||
/// `b64enc` — base64-encodes first argument as a UTF-8 string.
|
||||
fn sprig_b64enc(args: &[gtmpl::Value]) -> Result<gtmpl::Value, gtmpl_value::FuncError> {
|
||||
let v = args
|
||||
.first()
|
||||
.ok_or_else(|| gtmpl_value::FuncError::AtLeastXArgs("b64enc".into(), 1))?;
|
||||
let s = match v {
|
||||
gtmpl::Value::String(s) => s.clone(),
|
||||
other => format!("{other:?}"),
|
||||
};
|
||||
Ok(gtmpl::Value::String(B64.encode(s.as_bytes())))
|
||||
}
|
||||
|
||||
/// `date` — formats a Unix timestamp using a Go-style layout string.
|
||||
///
|
||||
/// Signature: `date <layout-string> <unix-timestamp>`
|
||||
fn sprig_date(args: &[gtmpl::Value]) -> Result<gtmpl::Value, gtmpl_value::FuncError> {
|
||||
if args.len() < 2 {
|
||||
return Err(gtmpl_value::FuncError::AtLeastXArgs("date".into(), 2));
|
||||
}
|
||||
let layout = match &args[0] {
|
||||
gtmpl::Value::String(s) => s.as_str(),
|
||||
_ => {
|
||||
return Err(gtmpl_value::FuncError::Generic(
|
||||
"date: first arg must be a string layout".into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
let ts: i64 = match &args[1] {
|
||||
gtmpl::Value::Number(n) => n
|
||||
.as_i64()
|
||||
.unwrap_or_else(|| n.as_f64().map(|f| f as i64).unwrap_or(0)),
|
||||
_ => {
|
||||
return Err(gtmpl_value::FuncError::Generic(
|
||||
"date: second arg must be a number (Unix timestamp)".into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let dt = chrono::Utc
|
||||
.timestamp_opt(ts, 0)
|
||||
.single()
|
||||
.unwrap_or_else(chrono::Utc::now);
|
||||
|
||||
// Map common Go reference-time tokens to chrono format specifiers.
|
||||
let chrono_fmt = go_layout_to_chrono(layout);
|
||||
Ok(gtmpl::Value::String(dt.format(&chrono_fmt).to_string()))
|
||||
}
|
||||
|
||||
/// Translate a Go time-layout string to a chrono format string.
|
||||
///
|
||||
/// Only the most common reference-time tokens are mapped.
|
||||
fn go_layout_to_chrono(layout: &str) -> String {
|
||||
layout
|
||||
.replace("2006", "%Y")
|
||||
.replace("01", "%m")
|
||||
.replace("02", "%d")
|
||||
.replace("15", "%H")
|
||||
.replace("04", "%M")
|
||||
.replace("05", "%S")
|
||||
.replace("Jan", "%b")
|
||||
.replace("Monday", "%A")
|
||||
.replace("Mon", "%a")
|
||||
}
|
||||
|
||||
/// Convert a `gtmpl::Value` to a `serde_json::Value` (best-effort).
|
||||
fn gtmpl_value_to_json(v: gtmpl::Value) -> serde_json::Value {
|
||||
match v {
|
||||
gtmpl::Value::Nil | gtmpl::Value::NoValue => serde_json::Value::Null,
|
||||
gtmpl::Value::Bool(b) => serde_json::Value::Bool(b),
|
||||
gtmpl::Value::String(s) => serde_json::Value::String(s),
|
||||
gtmpl::Value::Number(n) => {
|
||||
if let Some(i) = n.as_i64() {
|
||||
serde_json::Value::Number(i.into())
|
||||
} else if let Some(f) = n.as_f64() {
|
||||
serde_json::Number::from_f64(f)
|
||||
.map(serde_json::Value::Number)
|
||||
.unwrap_or(serde_json::Value::Null)
|
||||
} else {
|
||||
serde_json::Value::Null
|
||||
}
|
||||
}
|
||||
gtmpl::Value::Array(arr) => {
|
||||
serde_json::Value::Array(arr.into_iter().map(gtmpl_value_to_json).collect())
|
||||
}
|
||||
gtmpl::Value::Map(map) | gtmpl::Value::Object(map) => {
|
||||
let obj: serde_json::Map<String, serde_json::Value> = map
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, gtmpl_value_to_json(v)))
|
||||
.collect();
|
||||
serde_json::Value::Object(obj)
|
||||
}
|
||||
// Functions have no meaningful JSON representation.
|
||||
gtmpl::Value::Function(_) => serde_json::Value::Null,
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Adapter
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Converts node+server entities into a sorted list of [`Proxy`] values.
|
||||
pub struct Adapter;
|
||||
|
||||
impl Adapter {
|
||||
/// Build a `Vec<Proxy>` from `(Node, Server)` pairs.
|
||||
///
|
||||
/// Mirrors Go `(*Adapter).Proxies()`.
|
||||
pub fn proxies(pairs: &[(Node, Server)]) -> Vec<Proxy> {
|
||||
let mut out: Vec<Proxy> = Vec::new();
|
||||
|
||||
for (node, server) in pairs {
|
||||
// Deserialise the JSON protocols array stored in `server.protocols`.
|
||||
let protocols: Vec<NodeProtocol> = match serde_json::from_str(&server.protocols) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
server_id = server.id,
|
||||
error = %e,
|
||||
"failed to parse server protocols JSON"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Find the protocol entry whose `type_` matches `node.protocol`.
|
||||
let proto = match protocols.iter().find(|p| p.type_ == node.protocol) {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
tracing::warn!(
|
||||
node_id = node.id,
|
||||
protocol = %node.protocol,
|
||||
"no matching protocol entry in server.protocols"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let tags: Vec<String> = if node.tags.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
node.tags.split(',').map(str::trim).map(String::from).collect()
|
||||
};
|
||||
|
||||
out.push(Proxy {
|
||||
sort: node.sort,
|
||||
name: node.name.clone(),
|
||||
server: node.address.clone(),
|
||||
port: node.port,
|
||||
type_: node.protocol.clone(),
|
||||
tags,
|
||||
security: proto.security.clone(),
|
||||
sni: proto.sni.clone(),
|
||||
allow_insecure: proto.allow_insecure,
|
||||
fingerprint: proto.fingerprint.clone(),
|
||||
reality_server_addr: proto.reality_server_addr.clone(),
|
||||
reality_server_port: proto.reality_server_port,
|
||||
reality_private_key: proto.reality_private_key.clone(),
|
||||
reality_public_key: proto.reality_public_key.clone(),
|
||||
reality_short_id: proto.reality_short_id.clone(),
|
||||
transport: proto.transport.clone(),
|
||||
host: proto.host.clone(),
|
||||
path: proto.path.clone(),
|
||||
service_name: proto.service_name.clone(),
|
||||
method: proto.cipher.clone(),
|
||||
server_key: proto.server_key.clone(),
|
||||
uot: proto.uot,
|
||||
uot_version: proto.uot_version,
|
||||
flow: proto.flow.clone(),
|
||||
hop_ports: proto.hop_ports.clone(),
|
||||
hop_interval: proto.hop_interval,
|
||||
obfs_password: proto.obfs_password.clone(),
|
||||
up_mbps: proto.up_mbps,
|
||||
down_mbps: proto.down_mbps,
|
||||
disable_sni: proto.disable_sni,
|
||||
reduce_rtt: proto.reduce_rtt,
|
||||
udp_relay_mode: proto.udp_relay_mode.clone(),
|
||||
congestion_controller: proto.congestion_controller.clone(),
|
||||
padding_scheme: proto.padding_scheme.clone(),
|
||||
multiplex: proto.multiplex.clone(),
|
||||
xhttp_mode: proto.xhttp_mode.clone(),
|
||||
xhttp_extra: proto.xhttp_extra.clone(),
|
||||
encryption: proto.encryption.clone(),
|
||||
encryption_mode: proto.encryption_mode.clone(),
|
||||
encryption_rtt: proto.encryption_rtt.clone(),
|
||||
encryption_ticket: proto.encryption_ticket.clone(),
|
||||
encryption_server_padding: proto.encryption_server_padding.clone(),
|
||||
encryption_private_key: proto.encryption_private_key.clone(),
|
||||
encryption_client_padding: proto.encryption_client_padding.clone(),
|
||||
encryption_password: proto.encryption_password.clone(),
|
||||
ech_enable: proto.ech_enable,
|
||||
ech_server_name: proto.ech_server_name.clone(),
|
||||
ratio: proto.ratio,
|
||||
cert_mode: proto.cert_mode.clone(),
|
||||
cert_dns_provider: proto.cert_dns_provider.clone(),
|
||||
cert_dns_env: proto.cert_dns_env.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
// Sort by `node.sort` ascending (mirrors Go slice sort in original code).
|
||||
out.sort_by_key(|p| p.sort);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Tests
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_proxy_default() {
|
||||
let _ = Proxy::default();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_b64enc() {
|
||||
let args = vec![gtmpl::Value::String("hello".into())];
|
||||
let result = sprig_b64enc(&args).expect("b64enc should succeed");
|
||||
assert_eq!(result, gtmpl::Value::String("aGVsbG8=".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_build_simple() {
|
||||
let config = ClientConfig {
|
||||
site_name: "TestSite".into(),
|
||||
subscribe_name: "TestSub".into(),
|
||||
output_format: "text".into(),
|
||||
params: HashMap::new(),
|
||||
};
|
||||
let client = Client { config };
|
||||
|
||||
let proxies = vec![Proxy::default(), Proxy::default()];
|
||||
let user = User::default();
|
||||
|
||||
// Go template: render the count of proxies.
|
||||
let out = client
|
||||
.build("{{ len .Proxies }}", &proxies, &user)
|
||||
.expect("build should succeed");
|
||||
assert_eq!(out.trim(), "2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_build_base64() {
|
||||
let config = ClientConfig {
|
||||
output_format: "base64".into(),
|
||||
..Default::default()
|
||||
};
|
||||
let client = Client { config };
|
||||
let out = client
|
||||
.build("hello", &[], &User::default())
|
||||
.expect("build should succeed");
|
||||
// base64("hello") == "aGVsbG8="
|
||||
assert_eq!(out, "aGVsbG8=");
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
use redis::aio::ConnectionManager;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::config::RedisConfig;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Cache {
|
||||
con: std::sync::Arc<Mutex<ConnectionManager>>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Cache {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Cache").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
pub async fn new(cfg: &RedisConfig) -> Result<Self, redis::RedisError> {
|
||||
let dsn = format!("redis://:{}@{}", cfg.pass, cfg.host);
|
||||
let client = redis::Client::open(dsn)?;
|
||||
let mut con = client.get_connection_manager().await?;
|
||||
|
||||
if cfg.db != 0 {
|
||||
redis::cmd("SELECT")
|
||||
.arg(cfg.db)
|
||||
.query_async::<()>(&mut con)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
con: std::sync::Arc::new(Mutex::new(con)),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get(&self, key: &str) -> Result<Option<String>, redis::RedisError> {
|
||||
let mut con = self.con.lock().await;
|
||||
redis::cmd("GET")
|
||||
.arg(key)
|
||||
.query_async(&mut *con)
|
||||
.await
|
||||
.map(|v: Option<String>| v)
|
||||
}
|
||||
|
||||
pub async fn set_ex(
|
||||
&self,
|
||||
key: &str,
|
||||
value: &str,
|
||||
seconds: i64,
|
||||
) -> Result<(), redis::RedisError> {
|
||||
let mut con = self.con.lock().await;
|
||||
redis::cmd("SET")
|
||||
.arg(key)
|
||||
.arg(value)
|
||||
.arg("EX")
|
||||
.arg(seconds)
|
||||
.query_async(&mut *con)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn del(&self, key: &str) -> Result<(), redis::RedisError> {
|
||||
let mut con = self.con.lock().await;
|
||||
redis::cmd("DEL")
|
||||
.arg(key)
|
||||
.query_async(&mut *con)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn exists(&self, key: &str) -> Result<bool, redis::RedisError> {
|
||||
let mut con = self.con.lock().await;
|
||||
redis::cmd("EXISTS")
|
||||
.arg(key)
|
||||
.query_async(&mut *con)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn incr(&self, key: &str) -> Result<i64, redis::RedisError> {
|
||||
let mut con = self.con.lock().await;
|
||||
redis::cmd("INCR")
|
||||
.arg(key)
|
||||
.query_async(&mut *con)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn expire(&self, key: &str, seconds: i64) -> Result<(), redis::RedisError> {
|
||||
let mut con = self.con.lock().await;
|
||||
redis::cmd("EXPIRE")
|
||||
.arg(key)
|
||||
.arg(seconds)
|
||||
.query_async(&mut *con)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_int(&self, key: &str) -> Result<Option<i64>, redis::RedisError> {
|
||||
let mut con = self.con.lock().await;
|
||||
redis::cmd("GET")
|
||||
.arg(key)
|
||||
.query_async(&mut *con)
|
||||
.await
|
||||
.map(|v: Option<String>| v.and_then(|s| s.parse().ok()))
|
||||
}
|
||||
|
||||
pub async fn ttl(&self, key: &str) -> Result<i64, redis::RedisError> {
|
||||
let mut con = self.con.lock().await;
|
||||
redis::cmd("TTL")
|
||||
.arg(key)
|
||||
.query_async(&mut *con)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//! Redis / cache key constants, ported from `server/internal/config/cacheKey.go`.
|
||||
//!
|
||||
//! TODO: these constants are defined ahead of the cache layer. The root
|
||||
//! `Cargo.toml` does not yet pull a Redis client (e.g. `redis` / `deadpool-redis`)
|
||||
//! and `config::RedisConfig` is a dead leaf until the cache service is wired
|
||||
//! up. When introducing the cache layer, add the dependency and a `cache`
|
||||
//! module that consumes these keys.
|
||||
|
||||
pub const CURRENCY_CONFIG_KEY: &str = "system:currency_config";
|
||||
pub const SMS_CONFIG_KEY: &str = "system:sms_config";
|
||||
pub const SITE_CONFIG_KEY: &str = "system:site_config";
|
||||
pub const SUBSCRIBE_CONFIG_KEY: &str = "system:subscribe_config";
|
||||
pub const REGISTER_CONFIG_KEY: &str = "system:register_config";
|
||||
pub const VERIFY_CONFIG_KEY: &str = "system:verify_config";
|
||||
pub const EMAIL_SMTP_CONFIG_KEY: &str = "system:email_smtp_config";
|
||||
pub const NODE_CONFIG_KEY: &str = "system:node_config";
|
||||
pub const INVITE_CONFIG_KEY: &str = "system:invite_config";
|
||||
pub const TELEGRAM_CONFIG_KEY: &str = "system:telegram_config";
|
||||
pub const ADMIN_TELEGRAM_CHAT_IDS_KEY: &str = "system:telegram_admin_chat_ids";
|
||||
pub const TOS_CONFIG_KEY: &str = "system:tos_config";
|
||||
pub const VERIFY_CODE_CONFIG_KEY: &str = "system:verify_code_config";
|
||||
pub const SESSION_ID_KEY: &str = "auth:session_id";
|
||||
pub const GLOBAL_CONFIG_KEY: &str = "system:global_config";
|
||||
pub const AUTH_CODE_CACHE_KEY: &str = "auth:verify:email";
|
||||
pub const AUTH_CODE_TELEPHONE_CACHE_KEY: &str = "auth:verify:telephone";
|
||||
pub const COMMON_STAT_CACHE_KEY: &str = "common:stat";
|
||||
pub const SERVER_COUNT_CACHE_KEY: &str = "server:count";
|
||||
pub const SEND_INTERVAL_KEY_PREFIX: &str = "send:interval:";
|
||||
pub const SEND_COUNT_LIMIT_KEY_PREFIX: &str = "send:limit:";
|
||||
@@ -0,0 +1,715 @@
|
||||
pub mod cache_key;
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::path::Path;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Top-level Config
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Config {
|
||||
#[serde(default = "default_model")]
|
||||
pub model: String,
|
||||
|
||||
#[serde(default = "default_host")]
|
||||
pub host: String,
|
||||
|
||||
#[serde(default = "default_port")]
|
||||
pub port: u16,
|
||||
|
||||
#[serde(default)]
|
||||
pub debug: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub transport: TransportConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub tls: Tls,
|
||||
|
||||
#[serde(rename = "JwtAuth")]
|
||||
pub jwt_auth: JwtAuth,
|
||||
|
||||
#[serde(default)]
|
||||
pub logger: LogConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub database: DatabaseConfig,
|
||||
|
||||
pub mysql: Option<DatabaseConfig>,
|
||||
|
||||
#[serde(default)]
|
||||
pub redis: RedisConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub site: SiteConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub node: NodeConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub mobile: MobileConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub email: EmailConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub device: DeviceConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub verify: Verify,
|
||||
|
||||
#[serde(rename = "VerifyCode")]
|
||||
pub verify_code: VerifyCode,
|
||||
|
||||
#[serde(default)]
|
||||
pub register: RegisterConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub subscribe: SubscribeConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub invite: InviteConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub telegram: Telegram,
|
||||
|
||||
#[serde(default)]
|
||||
pub log: Log,
|
||||
|
||||
#[serde(default)]
|
||||
pub currency: Currency,
|
||||
|
||||
#[serde(default)]
|
||||
pub plugin: PluginConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub trace: TraceConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub administrator: Administrator,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load() -> Self {
|
||||
let path = std::env::var("PPANEL_CONFIG").unwrap_or_else(|_| "config.yaml".to_string());
|
||||
Self::from_file(&path)
|
||||
}
|
||||
|
||||
pub fn from_file(path: impl AsRef<Path>) -> Self {
|
||||
let path = path.as_ref();
|
||||
let content = std::fs::read_to_string(path).unwrap_or_else(|e| {
|
||||
panic!("failed to read config file {}: {e}", path.display())
|
||||
});
|
||||
serde_yaml::from_str(&content).unwrap_or_else(|e| {
|
||||
panic!("failed to parse config file {}: {e}", path.display())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn database_config(&self) -> &DatabaseConfig {
|
||||
if self.database.addr.is_some() || !self.database.dbname.is_empty() {
|
||||
&self.database
|
||||
} else if let Some(ref mysql) = self.mysql {
|
||||
mysql
|
||||
} else {
|
||||
&self.database
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Default helpers
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
fn default_model() -> String { "prod".into() }
|
||||
fn default_host() -> String { "0.0.0.0".into() }
|
||||
fn default_port() -> u16 { 8080 }
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Sub-config structs
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct RedisConfig {
|
||||
#[serde(default = "default_redis_host")]
|
||||
pub host: String,
|
||||
#[serde(default)]
|
||||
pub pass: String,
|
||||
#[serde(default)]
|
||||
pub db: i32,
|
||||
}
|
||||
|
||||
fn default_redis_host() -> String { "localhost:6379".into() }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct TransportConfig {
|
||||
#[serde(default = "default_transport_driver")]
|
||||
pub driver: String,
|
||||
}
|
||||
|
||||
fn default_transport_driver() -> String { "hertz".into() }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct JwtAuth {
|
||||
#[serde(default)]
|
||||
pub access_secret: String,
|
||||
#[serde(default = "default_access_expire")]
|
||||
pub access_expire: i64,
|
||||
}
|
||||
|
||||
fn default_access_expire() -> i64 { 604800 }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Verify {
|
||||
#[serde(default)]
|
||||
pub turnstile_site_key: String,
|
||||
#[serde(default)]
|
||||
pub turnstile_secret: String,
|
||||
#[serde(default)]
|
||||
pub login_verify: bool,
|
||||
#[serde(default)]
|
||||
pub register_verify: bool,
|
||||
#[serde(default)]
|
||||
pub reset_password_verify: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct SubscribeConfig {
|
||||
#[serde(default)]
|
||||
pub single_model: bool,
|
||||
#[serde(default = "default_subscribe_path")]
|
||||
pub subscribe_path: String,
|
||||
#[serde(default)]
|
||||
pub subscribe_domain: String,
|
||||
#[serde(default)]
|
||||
pub pan_domain: bool,
|
||||
#[serde(default)]
|
||||
pub user_agent_limit: bool,
|
||||
#[serde(default)]
|
||||
pub user_agent_list: String,
|
||||
#[serde(default = "default_show_tutorial")]
|
||||
pub show_tutorial: bool,
|
||||
}
|
||||
|
||||
fn default_subscribe_path() -> String { "/v1/subscribe/config".into() }
|
||||
fn default_show_tutorial() -> bool { true }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct RegisterConfig {
|
||||
#[serde(default)]
|
||||
pub stop_register: bool,
|
||||
#[serde(default)]
|
||||
pub enable_trial: bool,
|
||||
#[serde(default)]
|
||||
pub trial_subscribe: i64,
|
||||
#[serde(default)]
|
||||
pub trial_time: i64,
|
||||
#[serde(default)]
|
||||
pub trial_time_unit: String,
|
||||
#[serde(default)]
|
||||
pub ip_register_limit: i64,
|
||||
#[serde(default)]
|
||||
pub ip_register_limit_duration: i64,
|
||||
#[serde(default)]
|
||||
pub enable_ip_register_limit: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct EmailConfig {
|
||||
#[serde(rename = "Enable", default = "default_email_enable")]
|
||||
pub enable: bool,
|
||||
#[serde(default)]
|
||||
pub platform: String,
|
||||
#[serde(default)]
|
||||
pub platform_config: String,
|
||||
#[serde(default)]
|
||||
pub enable_verify: bool,
|
||||
#[serde(default)]
|
||||
pub enable_notify: bool,
|
||||
#[serde(default)]
|
||||
pub enable_domain_suffix: bool,
|
||||
#[serde(default)]
|
||||
pub domain_suffix_list: String,
|
||||
#[serde(default)]
|
||||
pub verify_email_template: String,
|
||||
#[serde(default)]
|
||||
pub expiration_email_template: String,
|
||||
#[serde(default)]
|
||||
pub maintenance_email_template: String,
|
||||
#[serde(default)]
|
||||
pub traffic_exceed_email_template: String,
|
||||
}
|
||||
|
||||
fn default_email_enable() -> bool { true }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct MobileConfig {
|
||||
#[serde(rename = "Enable", default = "default_mobile_enable")]
|
||||
pub enable: bool,
|
||||
#[serde(default)]
|
||||
pub platform: String,
|
||||
#[serde(default)]
|
||||
pub platform_config: String,
|
||||
#[serde(default)]
|
||||
pub enable_verify: bool,
|
||||
#[serde(default)]
|
||||
pub enable_whitelist: bool,
|
||||
#[serde(default)]
|
||||
pub whitelist: Vec<String>,
|
||||
}
|
||||
|
||||
fn default_mobile_enable() -> bool { true }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct DeviceConfig {
|
||||
#[serde(default = "default_device_enable")]
|
||||
pub enable: bool,
|
||||
#[serde(default)]
|
||||
pub show_ads: bool,
|
||||
#[serde(default)]
|
||||
pub enable_security: bool,
|
||||
#[serde(default)]
|
||||
pub only_real_device: bool,
|
||||
#[serde(default)]
|
||||
pub security_secret: String,
|
||||
}
|
||||
|
||||
fn default_device_enable() -> bool { true }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct SiteConfig {
|
||||
#[serde(default)]
|
||||
pub host: String,
|
||||
#[serde(default)]
|
||||
pub site_name: String,
|
||||
#[serde(default)]
|
||||
pub site_desc: String,
|
||||
#[serde(default)]
|
||||
pub site_logo: String,
|
||||
#[serde(default)]
|
||||
pub keywords: String,
|
||||
#[serde(default)]
|
||||
pub custom_html: String,
|
||||
#[serde(default)]
|
||||
pub custom_data: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct NodeConfig {
|
||||
#[serde(default)]
|
||||
pub node_secret: String,
|
||||
#[serde(default = "default_node_pull_interval")]
|
||||
pub node_pull_interval: i64,
|
||||
#[serde(default = "default_node_push_interval")]
|
||||
pub node_push_interval: i64,
|
||||
#[serde(default)]
|
||||
pub traffic_report_threshold: i64,
|
||||
#[serde(default)]
|
||||
pub ip_strategy: String,
|
||||
#[serde(default)]
|
||||
pub dns: Vec<NodeDns>,
|
||||
#[serde(default)]
|
||||
pub block: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub outbound: Vec<NodeOutbound>,
|
||||
}
|
||||
|
||||
fn default_node_pull_interval() -> i64 { 60 }
|
||||
fn default_node_push_interval() -> i64 { 60 }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct NodeDns {
|
||||
pub proto: String,
|
||||
pub address: String,
|
||||
#[serde(default)]
|
||||
pub domains: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct NodeOutbound {
|
||||
pub name: String,
|
||||
pub protocol: String,
|
||||
pub address: String,
|
||||
pub port: i64,
|
||||
#[serde(default)]
|
||||
pub user: String,
|
||||
#[serde(default)]
|
||||
pub password: String,
|
||||
#[serde(default)]
|
||||
pub uuid: String,
|
||||
#[serde(default)]
|
||||
pub cipher: String,
|
||||
#[serde(default)]
|
||||
pub security: String,
|
||||
#[serde(default)]
|
||||
pub sni: String,
|
||||
#[serde(default)]
|
||||
pub allow_insecure: bool,
|
||||
#[serde(default)]
|
||||
pub fingerprint: String,
|
||||
#[serde(default)]
|
||||
pub transport: String,
|
||||
#[serde(default)]
|
||||
pub host: String,
|
||||
#[serde(default)]
|
||||
pub path: String,
|
||||
#[serde(default)]
|
||||
pub service_name: String,
|
||||
#[serde(default)]
|
||||
pub flow: String,
|
||||
#[serde(default)]
|
||||
pub uot: bool,
|
||||
#[serde(default)]
|
||||
pub uot_version: i32,
|
||||
#[serde(default)]
|
||||
pub congestion_controller: String,
|
||||
#[serde(default)]
|
||||
pub udp_stream: bool,
|
||||
#[serde(default)]
|
||||
pub reduce_rtt: bool,
|
||||
#[serde(default)]
|
||||
pub heartbeat: i32,
|
||||
#[serde(default)]
|
||||
pub reality_public_key: String,
|
||||
#[serde(default)]
|
||||
pub reality_short_id: String,
|
||||
#[serde(default)]
|
||||
pub spider_x: String,
|
||||
#[serde(default)]
|
||||
pub settings: String,
|
||||
#[serde(default)]
|
||||
pub stream_settings: String,
|
||||
#[serde(default)]
|
||||
pub rules: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct InviteConfig {
|
||||
#[serde(default)]
|
||||
pub forced_invite: bool,
|
||||
#[serde(default)]
|
||||
pub referral_percentage: i64,
|
||||
#[serde(default)]
|
||||
pub only_first_purchase: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Telegram {
|
||||
#[serde(default)]
|
||||
pub enable: bool,
|
||||
#[serde(default)]
|
||||
pub bot_id: i64,
|
||||
#[serde(default)]
|
||||
pub bot_name: String,
|
||||
#[serde(default)]
|
||||
pub bot_token: String,
|
||||
#[serde(default)]
|
||||
pub enable_notify: bool,
|
||||
#[serde(default)]
|
||||
pub web_hook_domain: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Tls {
|
||||
#[serde(default)]
|
||||
pub enable: bool,
|
||||
#[serde(default)]
|
||||
pub cert_file: String,
|
||||
#[serde(default)]
|
||||
pub key_file: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct VerifyCode {
|
||||
#[serde(default = "default_verify_code_expire")]
|
||||
pub expire_time: i64,
|
||||
#[serde(default = "default_verify_code_limit")]
|
||||
pub limit: i64,
|
||||
#[serde(default = "default_verify_code_interval")]
|
||||
pub interval: i64,
|
||||
}
|
||||
|
||||
fn default_verify_code_expire() -> i64 { 300 }
|
||||
fn default_verify_code_limit() -> i64 { 15 }
|
||||
fn default_verify_code_interval() -> i64 { 60 }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Log {
|
||||
#[serde(default = "default_log_auto_clear")]
|
||||
pub auto_clear: bool,
|
||||
#[serde(default = "default_log_clear_days")]
|
||||
pub clear_days: i64,
|
||||
}
|
||||
|
||||
fn default_log_auto_clear() -> bool { true }
|
||||
fn default_log_clear_days() -> i64 { 7 }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Currency {
|
||||
#[serde(default = "default_currency_unit")]
|
||||
pub unit: String,
|
||||
#[serde(default = "default_currency_symbol")]
|
||||
pub symbol: String,
|
||||
#[serde(default)]
|
||||
pub access_key: String,
|
||||
}
|
||||
|
||||
fn default_currency_unit() -> String { "CNY".into() }
|
||||
fn default_currency_symbol() -> String { "¥".into() }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct PluginConfig {
|
||||
#[serde(default = "default_plugin_enabled")]
|
||||
pub enabled: bool,
|
||||
#[serde(default = "default_plugin_directory")]
|
||||
pub directory: String,
|
||||
#[serde(default = "default_plugin_max_memory")]
|
||||
pub max_memory_mb: i64,
|
||||
#[serde(default = "default_plugin_timeout")]
|
||||
pub timeout_sec: i64,
|
||||
#[serde(default)]
|
||||
pub allow_list: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub block_list: Vec<String>,
|
||||
}
|
||||
|
||||
fn default_plugin_enabled() -> bool { true }
|
||||
fn default_plugin_directory() -> String { "plugins".into() }
|
||||
fn default_plugin_max_memory() -> i64 { 64 }
|
||||
fn default_plugin_timeout() -> i64 { 30 }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Administrator {
|
||||
#[serde(default = "default_admin_email")]
|
||||
pub email: String,
|
||||
#[serde(default = "default_admin_password")]
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
fn default_admin_email() -> String { "admin@ppanel.dev".into() }
|
||||
fn default_admin_password() -> String { "password".into() }
|
||||
|
||||
// ─── Trace / OpenTelemetry ───────────────────────────────────────────────────
|
||||
|
||||
/// Mirrors `pkg/trace/config.go → Config`.
|
||||
///
|
||||
/// Supported batcher values: `"jaeger"` | `"zipkin"` | `"otlpgrpc"` | `"otlphttp"` | `"stdout"`
|
||||
/// Leave `endpoint` empty (or set `disabled = true`) to disable tracing.
|
||||
#[derive(Debug, Clone, Deserialize, Default)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct TraceConfig {
|
||||
/// Service name reported to the tracing backend (default "ppanel").
|
||||
#[serde(default = "default_trace_name")]
|
||||
pub name: String,
|
||||
|
||||
/// Exporter endpoint URL (e.g. `http://localhost:14268/api/traces` for Jaeger HTTP).
|
||||
#[serde(default)]
|
||||
pub endpoint: String,
|
||||
|
||||
/// Fraction of traces to sample, 0.0–1.0 (default 1.0 = 100 %).
|
||||
#[serde(default = "default_trace_sampler")]
|
||||
pub sampler: f64,
|
||||
|
||||
/// Exporter backend: `jaeger` | `otlpgrpc` | `otlphttp` | `stdout`.
|
||||
#[serde(default = "default_trace_batcher")]
|
||||
pub batcher: String,
|
||||
|
||||
/// Extra headers forwarded to the OTLP exporter.
|
||||
#[serde(default)]
|
||||
pub otlp_headers: std::collections::HashMap<String, String>,
|
||||
|
||||
/// URL path override for OTLP HTTP (e.g. `"/v1/traces"`).
|
||||
#[serde(default)]
|
||||
pub otlp_http_path: String,
|
||||
|
||||
/// Use TLS for OTLP HTTP transport.
|
||||
#[serde(default)]
|
||||
pub otlp_http_secure: bool,
|
||||
|
||||
/// Disable tracing entirely (shortcut to skip initialisation).
|
||||
#[serde(default)]
|
||||
pub disabled: bool,
|
||||
}
|
||||
|
||||
fn default_trace_name() -> String { "ppanel".into() }
|
||||
fn default_trace_sampler() -> f64 { 1.0 }
|
||||
fn default_trace_batcher() -> String { "stdout".into() }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct LogConfig {
|
||||
#[serde(default = "default_log_service_name")]
|
||||
pub service_name: String,
|
||||
#[serde(default = "default_log_mode")]
|
||||
pub mode: String,
|
||||
#[serde(default = "default_log_encoding")]
|
||||
pub encoding: String,
|
||||
#[serde(default = "default_log_time_format")]
|
||||
pub time_format: String,
|
||||
#[serde(default = "default_log_path")]
|
||||
pub path: String,
|
||||
#[serde(default = "default_log_level")]
|
||||
pub level: String,
|
||||
#[serde(default)]
|
||||
pub max_content_length: u32,
|
||||
#[serde(default)]
|
||||
pub compress: bool,
|
||||
#[serde(default = "default_log_stat")]
|
||||
pub stat: bool,
|
||||
#[serde(default)]
|
||||
pub keep_days: i32,
|
||||
#[serde(default = "default_log_stack_cooldown")]
|
||||
pub stack_cooldown_millis: i32,
|
||||
#[serde(default)]
|
||||
pub max_backups: i32,
|
||||
#[serde(default)]
|
||||
pub max_size: i32,
|
||||
#[serde(default = "default_log_rotation")]
|
||||
pub rotation: String,
|
||||
#[serde(default = "default_log_file_time_format")]
|
||||
pub file_time_format: String,
|
||||
}
|
||||
|
||||
fn default_log_service_name() -> String { "PPanel".into() }
|
||||
fn default_log_mode() -> String { "file".into() }
|
||||
fn default_log_encoding() -> String { "json".into() }
|
||||
fn default_log_time_format() -> String { "2006-01-02 15:04:05.000".into() }
|
||||
fn default_log_path() -> String { "logs".into() }
|
||||
fn default_log_level() -> String { "info".into() }
|
||||
fn default_log_stat() -> bool { true }
|
||||
fn default_log_stack_cooldown() -> i32 { 100 }
|
||||
fn default_log_rotation() -> String { "daily".into() }
|
||||
fn default_log_file_time_format() -> String { "2006-01-02T15:04:05.000Z07:00".into() }
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct DatabaseConfig {
|
||||
#[serde(default = "default_db_driver")]
|
||||
pub driver: String,
|
||||
#[serde(default)]
|
||||
pub addr: Option<String>,
|
||||
#[serde(default)]
|
||||
pub username: String,
|
||||
#[serde(default)]
|
||||
pub password: String,
|
||||
#[serde(default)]
|
||||
pub dbname: String,
|
||||
#[serde(default = "default_db_config")]
|
||||
pub config: String,
|
||||
#[serde(default = "default_db_max_idle")]
|
||||
pub max_idle_conns: i32,
|
||||
#[serde(default = "default_db_max_open")]
|
||||
pub max_open_conns: i32,
|
||||
#[serde(default = "default_db_slow_threshold")]
|
||||
pub slow_threshold: i64,
|
||||
}
|
||||
|
||||
fn default_db_driver() -> String { "mysql".into() }
|
||||
fn default_db_config() -> String { "charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai".into() }
|
||||
fn default_db_max_idle() -> i32 { 10 }
|
||||
fn default_db_max_open() -> i32 { 10 }
|
||||
fn default_db_slow_threshold() -> i64 { 1000 }
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Default trait — enables #[serde(default)] on all optional fields
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
macro_rules! impl_default {
|
||||
($ty:ty { $($field:ident: $val:expr),* $(,)? }) => {
|
||||
impl Default for $ty {
|
||||
fn default() -> Self {
|
||||
Self { $($field: $val),* }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_default!(Config {
|
||||
model: default_model(),
|
||||
host: default_host(),
|
||||
port: default_port(),
|
||||
debug: false,
|
||||
transport: TransportConfig::default(),
|
||||
tls: Tls::default(),
|
||||
jwt_auth: JwtAuth::default(),
|
||||
logger: LogConfig::default(),
|
||||
database: DatabaseConfig::default(),
|
||||
mysql: None,
|
||||
redis: RedisConfig::default(),
|
||||
site: SiteConfig::default(),
|
||||
node: NodeConfig::default(),
|
||||
mobile: MobileConfig::default(),
|
||||
email: EmailConfig::default(),
|
||||
device: DeviceConfig::default(),
|
||||
verify: Verify::default(),
|
||||
verify_code: VerifyCode::default(),
|
||||
register: RegisterConfig::default(),
|
||||
subscribe: SubscribeConfig::default(),
|
||||
invite: InviteConfig::default(),
|
||||
telegram: Telegram::default(),
|
||||
log: Log::default(),
|
||||
currency: Currency::default(),
|
||||
plugin: PluginConfig::default(),
|
||||
trace: TraceConfig::default(),
|
||||
administrator: Administrator::default(),
|
||||
});
|
||||
|
||||
impl_default!(RedisConfig { host: default_redis_host(), pass: String::new(), db: 0 });
|
||||
impl_default!(TransportConfig { driver: default_transport_driver() });
|
||||
impl_default!(JwtAuth { access_secret: String::new(), access_expire: default_access_expire() });
|
||||
impl_default!(Verify { turnstile_site_key: String::new(), turnstile_secret: String::new(), login_verify: false, register_verify: false, reset_password_verify: false });
|
||||
impl_default!(SubscribeConfig { single_model: false, subscribe_path: default_subscribe_path(), subscribe_domain: String::new(), pan_domain: false, user_agent_limit: false, user_agent_list: String::new(), show_tutorial: default_show_tutorial() });
|
||||
impl_default!(RegisterConfig { stop_register: false, enable_trial: false, trial_subscribe: 0, trial_time: 0, trial_time_unit: String::new(), ip_register_limit: 0, ip_register_limit_duration: 0, enable_ip_register_limit: false });
|
||||
impl_default!(EmailConfig { enable: default_email_enable(), platform: String::new(), platform_config: String::new(), enable_verify: false, enable_notify: false, enable_domain_suffix: false, domain_suffix_list: String::new(), verify_email_template: String::new(), expiration_email_template: String::new(), maintenance_email_template: String::new(), traffic_exceed_email_template: String::new() });
|
||||
impl_default!(MobileConfig { enable: default_mobile_enable(), platform: String::new(), platform_config: String::new(), enable_verify: false, enable_whitelist: false, whitelist: Vec::new() });
|
||||
impl_default!(DeviceConfig { enable: default_device_enable(), show_ads: false, enable_security: false, only_real_device: false, security_secret: String::new() });
|
||||
impl_default!(SiteConfig { host: String::new(), site_name: String::new(), site_desc: String::new(), site_logo: String::new(), keywords: String::new(), custom_html: String::new(), custom_data: String::new() });
|
||||
impl_default!(NodeConfig { node_secret: String::new(), node_pull_interval: default_node_pull_interval(), node_push_interval: default_node_push_interval(), traffic_report_threshold: 0, ip_strategy: String::new(), dns: Vec::new(), block: Vec::new(), outbound: Vec::new() });
|
||||
impl_default!(NodeDns { proto: String::new(), address: String::new(), domains: Vec::new() });
|
||||
impl_default!(NodeOutbound { name: String::new(), protocol: String::new(), address: String::new(), port: 0, user: String::new(), password: String::new(), uuid: String::new(), cipher: String::new(), security: String::new(), sni: String::new(), allow_insecure: false, fingerprint: String::new(), transport: String::new(), host: String::new(), path: String::new(), service_name: String::new(), flow: String::new(), uot: false, uot_version: 0, congestion_controller: String::new(), udp_stream: false, reduce_rtt: false, heartbeat: 0, reality_public_key: String::new(), reality_short_id: String::new(), spider_x: String::new(), settings: String::new(), stream_settings: String::new(), rules: Vec::new() });
|
||||
impl_default!(InviteConfig { forced_invite: false, referral_percentage: 0, only_first_purchase: false });
|
||||
impl_default!(Telegram { enable: false, bot_id: 0, bot_name: String::new(), bot_token: String::new(), enable_notify: false, web_hook_domain: String::new() });
|
||||
impl_default!(Tls { enable: false, cert_file: String::new(), key_file: String::new() });
|
||||
impl_default!(VerifyCode { expire_time: default_verify_code_expire(), limit: default_verify_code_limit(), interval: default_verify_code_interval() });
|
||||
impl_default!(Log { auto_clear: default_log_auto_clear(), clear_days: default_log_clear_days() });
|
||||
impl_default!(Currency { unit: default_currency_unit(), symbol: default_currency_symbol(), access_key: String::new() });
|
||||
impl_default!(PluginConfig { enabled: default_plugin_enabled(), directory: default_plugin_directory(), max_memory_mb: default_plugin_max_memory(), timeout_sec: default_plugin_timeout(), allow_list: Vec::new(), block_list: Vec::new() });
|
||||
impl_default!(Administrator { email: default_admin_email(), password: default_admin_password() });
|
||||
impl_default!(LogConfig {
|
||||
service_name: default_log_service_name(),
|
||||
mode: default_log_mode(),
|
||||
encoding: default_log_encoding(),
|
||||
time_format: default_log_time_format(),
|
||||
path: default_log_path(),
|
||||
level: default_log_level(),
|
||||
max_content_length: 0,
|
||||
compress: false,
|
||||
stat: default_log_stat(),
|
||||
keep_days: 0,
|
||||
stack_cooldown_millis: default_log_stack_cooldown(),
|
||||
max_backups: 0,
|
||||
max_size: 0,
|
||||
rotation: default_log_rotation(),
|
||||
file_time_format: default_log_file_time_format(),
|
||||
});
|
||||
impl_default!(DatabaseConfig { driver: default_db_driver(), addr: None, username: String::new(), password: String::new(), dbname: String::new(), config: default_db_config(), max_idle_conns: default_db_max_idle(), max_open_conns: default_db_max_open(), slow_threshold: default_db_slow_threshold() });
|
||||
@@ -0,0 +1,34 @@
|
||||
/// Supported proxy protocols, ported from `server/internal/config/protocol.go`.
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Protocol {
|
||||
Shadowsocks,
|
||||
Trojan,
|
||||
Vmess,
|
||||
Vless,
|
||||
}
|
||||
|
||||
impl Protocol {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Protocol::Shadowsocks => "shadowsocks",
|
||||
Protocol::Trojan => "trojan",
|
||||
Protocol::Vmess => "vmess",
|
||||
Protocol::Vless => "vless",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Protocol {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
match s {
|
||||
"shadowsocks" => Ok(Protocol::Shadowsocks),
|
||||
"trojan" => Ok(Protocol::Trojan),
|
||||
"vmess" => Ok(Protocol::Vmess),
|
||||
"vless" => Ok(Protocol::Vless),
|
||||
other => Err(format!("unknown protocol: {other}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//! Database connection initialisation.
|
||||
//!
|
||||
//! Reads the [`DatabaseConfig`] and creates a native `Pool<Postgres>` or
|
||||
//! `Pool<MySql>` wrapped in [`Db`]. Using concrete pool types (instead of
|
||||
//! `AnyPool`) lets each repository impl write native SQL with `$N` / `?`
|
||||
//! placeholders and use `FromRow` against the correct row type.
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::config::DatabaseConfig;
|
||||
use crate::repository::{Db, Dialect};
|
||||
|
||||
/// Build a pool + dialect wrapper from the config subsection.
|
||||
pub async fn init_pool(cfg: &DatabaseConfig) -> Result<Db, sqlx::Error> {
|
||||
let dsn = build_dsn(cfg);
|
||||
let dialect = detect_dialect(cfg);
|
||||
|
||||
let max_conn = cfg.max_open_conns.max(1) as u32;
|
||||
|
||||
match dialect {
|
||||
Dialect::Postgres => {
|
||||
let pool = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(max_conn)
|
||||
.acquire_timeout(Duration::from_secs(10))
|
||||
.connect(&dsn)
|
||||
.await?;
|
||||
Ok(Db::new_pg(pool))
|
||||
}
|
||||
Dialect::Mysql => {
|
||||
let pool = sqlx::mysql::MySqlPoolOptions::new()
|
||||
.max_connections(max_conn)
|
||||
.acquire_timeout(Duration::from_secs(10))
|
||||
.connect(&dsn)
|
||||
.await?;
|
||||
Ok(Db::new_mysql(pool))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── DSN builder ─────────────────────────────────────────────────────────
|
||||
|
||||
fn build_dsn(cfg: &DatabaseConfig) -> String {
|
||||
let addr = cfg
|
||||
.addr
|
||||
.as_deref()
|
||||
.filter(|a| !a.is_empty())
|
||||
.unwrap_or(match detect_dialect(cfg) {
|
||||
Dialect::Postgres => "localhost:5432",
|
||||
Dialect::Mysql => "localhost:3306",
|
||||
});
|
||||
let password = url_encode_password(&cfg.password);
|
||||
let query = if cfg.config.is_empty() {
|
||||
default_query(cfg)
|
||||
} else {
|
||||
&cfg.config
|
||||
};
|
||||
|
||||
match detect_dialect(cfg) {
|
||||
Dialect::Postgres => format!(
|
||||
"postgres://{}:{}@{}/{}?{}",
|
||||
cfg.username, password, addr, cfg.dbname, query,
|
||||
),
|
||||
Dialect::Mysql => format!(
|
||||
"mysql://{}:{}@{}/{}?{}",
|
||||
cfg.username, password, addr, cfg.dbname, query,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_dialect(cfg: &DatabaseConfig) -> Dialect {
|
||||
Dialect::from_driver(&cfg.driver)
|
||||
}
|
||||
|
||||
fn default_query(cfg: &DatabaseConfig) -> &'static str {
|
||||
match detect_dialect(cfg) {
|
||||
Dialect::Postgres => "sslmode=disable&TimeZone=Asia/Shanghai",
|
||||
Dialect::Mysql => "charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai",
|
||||
}
|
||||
}
|
||||
|
||||
fn url_encode_password(s: &str) -> String {
|
||||
s.chars()
|
||||
.map(|c| match c {
|
||||
'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' | '~' => c.to_string(),
|
||||
' ' => "%20".into(),
|
||||
other => format!("%{:02X}", other as u8),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::ads::create_ads_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_ads(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateAdsRequest>,
|
||||
) -> HttpResult {
|
||||
match create_ads_service::create_ads(state.repos.ads.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::ads::delete_ads_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn delete_ads(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<DeleteAdsRequest>,
|
||||
) -> HttpResult {
|
||||
match delete_ads_service::delete_ads(state.repos.ads.as_ref(), req.id).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::ads::get_ads_detail_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_ads_detail(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetAdsDetailRequest>,
|
||||
) -> HttpResult {
|
||||
match get_ads_detail_service::get_ads_detail(state.repos.ads.as_ref(), req.id).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::ads::get_ads_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_ads_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetAdsListRequest>,
|
||||
) -> HttpResult {
|
||||
match get_ads_list_service::get_ads_list(state.repos.ads.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
mod create_ads_handler;
|
||||
pub use create_ads_handler::create_ads;
|
||||
mod update_ads_handler;
|
||||
pub use update_ads_handler::update_ads;
|
||||
mod delete_ads_handler;
|
||||
pub use delete_ads_handler::delete_ads;
|
||||
mod get_ads_detail_handler;
|
||||
pub use get_ads_detail_handler::get_ads_detail;
|
||||
mod get_ads_list_handler;
|
||||
pub use get_ads_list_handler::get_ads_list;
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::ads::update_ads_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn update_ads(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<UpdateAdsRequest>,
|
||||
) -> HttpResult {
|
||||
match update_ads_service::update_ads(state.repos.ads.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::announcement::create_announcement_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_announcement(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateAnnouncementRequest>,
|
||||
) -> HttpResult {
|
||||
match create_announcement_service::create_announcement(state.repos.announcement.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::announcement::delete_announcement_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn delete_announcement(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<DeleteAnnouncementRequest>,
|
||||
) -> HttpResult {
|
||||
match delete_announcement_service::delete_announcement(state.repos.announcement.as_ref(), req.id).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::announcement::get_announcement_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_announcement(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetAnnouncementRequest>,
|
||||
) -> HttpResult {
|
||||
match get_announcement_service::get_announcement(state.repos.announcement.as_ref(), req.id).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::announcement::get_announcement_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_announcement_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetAnnouncementListRequest>,
|
||||
) -> HttpResult {
|
||||
match get_announcement_list_service::get_announcement_list(state.repos.announcement.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
mod create_announcement_handler;
|
||||
pub use create_announcement_handler::create_announcement;
|
||||
mod update_announcement_handler;
|
||||
pub use update_announcement_handler::update_announcement;
|
||||
mod delete_announcement_handler;
|
||||
pub use delete_announcement_handler::delete_announcement;
|
||||
mod get_announcement_handler;
|
||||
pub use get_announcement_handler::get_announcement;
|
||||
mod get_announcement_list_handler;
|
||||
pub use get_announcement_list_handler::get_announcement_list;
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::announcement::update_announcement_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn update_announcement(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<UpdateAnnouncementRequest>,
|
||||
) -> HttpResult {
|
||||
match update_announcement_service::update_announcement(state.repos.announcement.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::application::create_subscribe_application_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_subscribe_application(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateSubscribeApplicationRequest>,
|
||||
) -> HttpResult {
|
||||
match create_subscribe_application_service::create_subscribe_application(
|
||||
state.repos.client.as_ref(),
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::application::delete_subscribe_application_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn delete_subscribe_application(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<DeleteSubscribeApplicationRequest>,
|
||||
) -> HttpResult {
|
||||
match delete_subscribe_application_service::delete_subscribe_application(
|
||||
state.repos.client.as_ref(),
|
||||
req.id,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::application::get_subscribe_application_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_subscribe_application_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetSubscribeApplicationListRequest>,
|
||||
) -> HttpResult {
|
||||
match get_subscribe_application_list_service::get_subscribe_application_list(
|
||||
state.repos.client.as_ref(),
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
mod create_subscribe_application_handler;
|
||||
pub use create_subscribe_application_handler::create_subscribe_application;
|
||||
mod update_subscribe_application_handler;
|
||||
pub use update_subscribe_application_handler::update_subscribe_application;
|
||||
mod delete_subscribe_application_handler;
|
||||
pub use delete_subscribe_application_handler::delete_subscribe_application;
|
||||
mod get_subscribe_application_list_handler;
|
||||
pub use get_subscribe_application_list_handler::get_subscribe_application_list;
|
||||
mod preview_subscribe_template_handler;
|
||||
pub use preview_subscribe_template_handler::preview_subscribe_template;
|
||||
@@ -0,0 +1,21 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::application::preview_subscribe_template_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn preview_subscribe_template(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<PreviewSubscribeTemplateRequest>,
|
||||
) -> HttpResult {
|
||||
match preview_subscribe_template_service::preview_subscribe_template(
|
||||
state.repos.client.as_ref(),
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::application::update_subscribe_application_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn update_subscribe_application(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<UpdateSubscribeApplicationRequest>,
|
||||
) -> HttpResult {
|
||||
match update_subscribe_application_service::update_subscribe_application(
|
||||
state.repos.client.as_ref(),
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
use axum::extract::{Query, State};
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::auth::GetAuthMethodConfigRequest;
|
||||
use crate::service::admin::auth_method::get_auth_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_auth_method_config(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetAuthMethodConfigRequest>,
|
||||
) -> HttpResult {
|
||||
match get_auth_method_list_service::get_auth_method_config(state.repos.auth.as_ref(), req).await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use axum::extract::State;
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::auth_method::get_auth_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_auth_method_list(
|
||||
State(state): State<AppState>,
|
||||
) -> HttpResult {
|
||||
match get_auth_method_list_service::get_auth_method_list(state.repos.auth.as_ref()).await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use axum::extract::State;
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::auth_method::get_auth_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_email_platform(
|
||||
State(_state): State<AppState>,
|
||||
) -> HttpResult {
|
||||
match get_auth_method_list_service::get_email_platform().await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use axum::extract::State;
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::auth_method::get_auth_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_sms_platform(
|
||||
State(_state): State<AppState>,
|
||||
) -> HttpResult {
|
||||
match get_auth_method_list_service::get_sms_platform().await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
mod get_auth_method_config_handler;
|
||||
pub use get_auth_method_config_handler::get_auth_method_config;
|
||||
mod update_auth_method_config_handler;
|
||||
pub use update_auth_method_config_handler::update_auth_method_config;
|
||||
mod get_auth_method_list_handler;
|
||||
pub use get_auth_method_list_handler::get_auth_method_list;
|
||||
mod get_email_platform_handler;
|
||||
pub use get_email_platform_handler::get_email_platform;
|
||||
mod get_sms_platform_handler;
|
||||
pub use get_sms_platform_handler::get_sms_platform;
|
||||
mod test_email_send_handler;
|
||||
pub use test_email_send_handler::test_email_send;
|
||||
mod test_sms_send_handler;
|
||||
pub use test_sms_send_handler::test_sms_send;
|
||||
@@ -0,0 +1,21 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::auth_method::get_auth_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TestEmailSendRequest {
|
||||
pub to: String,
|
||||
}
|
||||
|
||||
pub async fn test_email_send(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<TestEmailSendRequest>,
|
||||
) -> HttpResult {
|
||||
match get_auth_method_list_service::test_email_send(&state.config, req.to).await {
|
||||
Ok(_) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::auth_method::get_auth_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TestSmsSendRequest {
|
||||
pub to: String,
|
||||
}
|
||||
|
||||
pub async fn test_sms_send(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<TestSmsSendRequest>,
|
||||
) -> HttpResult {
|
||||
match get_auth_method_list_service::test_sms_send(&state.config, req.to).await {
|
||||
Ok(_) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::auth::UpdateAuthMethodConfigRequest;
|
||||
use crate::service::admin::auth_method::get_auth_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn update_auth_method_config(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<UpdateAuthMethodConfigRequest>,
|
||||
) -> HttpResult {
|
||||
match get_auth_method_list_service::update_auth_method_config(state.repos.auth.as_ref(), req).await {
|
||||
Ok(_) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
mod query_revenue_statistics_handler;
|
||||
pub use query_revenue_statistics_handler::query_revenue_statistics;
|
||||
mod query_server_total_data_handler;
|
||||
pub use query_server_total_data_handler::query_server_total_data;
|
||||
mod query_ticket_wait_reply_handler;
|
||||
pub use query_ticket_wait_reply_handler::query_ticket_wait_reply;
|
||||
mod query_user_statistics_handler;
|
||||
pub use query_user_statistics_handler::query_user_statistics;
|
||||
@@ -0,0 +1,14 @@
|
||||
use axum::extract::State;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::console::query_revenue_statistics_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn query_revenue_statistics(State(state): State<AppState>) -> HttpResult {
|
||||
match query_revenue_statistics_service::query_revenue_statistics(state.repos.order.as_ref())
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
use axum::extract::State;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::console::query_server_total_data_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn query_server_total_data(State(state): State<AppState>) -> HttpResult {
|
||||
match query_server_total_data_service::query_server_total_data(&state.repos).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use axum::extract::State;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::console::query_ticket_wait_reply_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn query_ticket_wait_reply(State(state): State<AppState>) -> HttpResult {
|
||||
match query_ticket_wait_reply_service::query_ticket_wait_reply(state.repos.ticket.as_ref())
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::console::query_user_statistics_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn query_user_statistics(State(state): State<AppState>) -> HttpResult {
|
||||
match query_user_statistics_service::query_user_statistics(
|
||||
state.repos.user.as_ref(),
|
||||
state.repos.order.as_ref(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::coupon::batch_delete_coupon_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn batch_delete_coupon(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<BatchDeleteCouponRequest>,
|
||||
) -> HttpResult {
|
||||
match batch_delete_coupon_service::batch_delete_coupon(state.repos.coupon.as_ref(), req).await {
|
||||
Ok(()) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::coupon::create_coupon_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_coupon(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateCouponRequest>,
|
||||
) -> HttpResult {
|
||||
match create_coupon_service::create_coupon(state.repos.coupon.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::coupon::delete_coupon_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn delete_coupon(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<DeleteCouponRequest>,
|
||||
) -> HttpResult {
|
||||
match delete_coupon_service::delete_coupon(state.repos.coupon.as_ref(), req.id).await {
|
||||
Ok(()) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::coupon::get_coupon_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_coupon_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetCouponListRequest>,
|
||||
) -> HttpResult {
|
||||
match get_coupon_list_service::get_coupon_list(state.repos.coupon.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
mod create_coupon_handler;
|
||||
pub use create_coupon_handler::create_coupon;
|
||||
mod update_coupon_handler;
|
||||
pub use update_coupon_handler::update_coupon;
|
||||
mod delete_coupon_handler;
|
||||
pub use delete_coupon_handler::delete_coupon;
|
||||
mod batch_delete_coupon_handler;
|
||||
pub use batch_delete_coupon_handler::batch_delete_coupon;
|
||||
mod get_coupon_list_handler;
|
||||
pub use get_coupon_list_handler::get_coupon_list;
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::coupon::update_coupon_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn update_coupon(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<UpdateCouponRequest>,
|
||||
) -> HttpResult {
|
||||
match update_coupon_service::update_coupon(state.repos.coupon.as_ref(), req).await {
|
||||
Ok(()) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::document::batch_delete_document_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn batch_delete_document(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<BatchDeleteDocumentRequest>,
|
||||
) -> HttpResult {
|
||||
match batch_delete_document_service::batch_delete_document(state.repos.document.as_ref(), req)
|
||||
.await
|
||||
{
|
||||
Ok(()) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::document::create_document_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_document(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateDocumentRequest>,
|
||||
) -> HttpResult {
|
||||
match create_document_service::create_document(state.repos.document.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::document::delete_document_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn delete_document(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<DeleteDocumentRequest>,
|
||||
) -> HttpResult {
|
||||
match delete_document_service::delete_document(state.repos.document.as_ref(), req.id).await {
|
||||
Ok(()) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::document::get_document_detail_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_document_detail(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetDocumentDetailRequest>,
|
||||
) -> HttpResult {
|
||||
match get_document_detail_service::get_document_detail(state.repos.document.as_ref(), req.id)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::document::get_document_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_document_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetDocumentListRequest>,
|
||||
) -> HttpResult {
|
||||
match get_document_list_service::get_document_list(state.repos.document.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
mod create_document_handler;
|
||||
pub use create_document_handler::create_document;
|
||||
mod update_document_handler;
|
||||
pub use update_document_handler::update_document;
|
||||
mod delete_document_handler;
|
||||
pub use delete_document_handler::delete_document;
|
||||
mod batch_delete_document_handler;
|
||||
pub use batch_delete_document_handler::batch_delete_document;
|
||||
mod get_document_detail_handler;
|
||||
pub use get_document_detail_handler::get_document_detail;
|
||||
mod get_document_list_handler;
|
||||
pub use get_document_list_handler::get_document_list;
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::document::update_document_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn update_document(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<UpdateDocumentRequest>,
|
||||
) -> HttpResult {
|
||||
match update_document_service::update_document(state.repos.document.as_ref(), req).await {
|
||||
Ok(()) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::log::filter_balance_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_balance_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterBalanceLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_balance_log_service::filter_balance_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::log::filter_commission_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_commission_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterCommissionLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_commission_log_service::filter_commission_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use axum::extract::{Query, State};
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::log::filter_balance_log_service::{self, FilterEmailMobileLogRequest};
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_email_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterEmailMobileLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_balance_log_service::filter_email_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::log::filter_gift_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_gift_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterGiftLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_gift_log_service::filter_gift_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::log::filter_login_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_login_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterLoginLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_login_log_service::filter_login_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use axum::extract::{Query, State};
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::log::filter_balance_log_service::{self, FilterEmailMobileLogRequest};
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_mobile_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterEmailMobileLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_balance_log_service::filter_mobile_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::log::filter_register_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_register_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterRegisterLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_register_log_service::filter_register_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::log::filter_reset_subscribe_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_reset_subscribe_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterResetSubscribeLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_reset_subscribe_log_service::filter_reset_subscribe_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::log::filter_server_traffic_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_server_traffic_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterServerTrafficLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_server_traffic_log_service::filter_server_traffic_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::log::filter_subscribe_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_subscribe_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterSubscribeLogRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_subscribe_log_service::filter_subscribe_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
use axum::extract::{Query, State};
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::log::FilterTrafficLogDetailsRequest;
|
||||
use crate::service::admin::log::filter_balance_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_traffic_log_details(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterTrafficLogDetailsRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_balance_log_service::filter_traffic_log_details(state.repos.log.as_ref(), req).await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
use axum::extract::{Query, State};
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::log::filter_balance_log_service;
|
||||
use crate::model::dto::log::FilterSubscribeTrafficRequest;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_user_subscribe_traffic_log(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterSubscribeTrafficRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_balance_log_service::filter_user_subscribe_traffic_log(state.repos.log.as_ref(), req).await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use axum::extract::State;
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::log::filter_balance_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_log_setting(
|
||||
State(state): State<AppState>,
|
||||
) -> HttpResult {
|
||||
match filter_balance_log_service::get_log_setting(&state.config).await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
use axum::extract::{Query, State};
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::log::GetMessageLogListRequest;
|
||||
use crate::service::admin::log::filter_balance_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_message_log_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetMessageLogListRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_balance_log_service::get_message_log_list(state.repos.log.as_ref(), req).await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
mod filter_balance_log_handler;
|
||||
pub use filter_balance_log_handler::filter_balance_log;
|
||||
mod filter_commission_log_handler;
|
||||
pub use filter_commission_log_handler::filter_commission_log;
|
||||
mod filter_email_log_handler;
|
||||
pub use filter_email_log_handler::filter_email_log;
|
||||
mod filter_gift_log_handler;
|
||||
pub use filter_gift_log_handler::filter_gift_log;
|
||||
mod filter_login_log_handler;
|
||||
pub use filter_login_log_handler::filter_login_log;
|
||||
mod filter_mobile_log_handler;
|
||||
pub use filter_mobile_log_handler::filter_mobile_log;
|
||||
mod filter_register_log_handler;
|
||||
pub use filter_register_log_handler::filter_register_log;
|
||||
mod filter_reset_subscribe_log_handler;
|
||||
pub use filter_reset_subscribe_log_handler::filter_reset_subscribe_log;
|
||||
mod filter_server_traffic_log_handler;
|
||||
pub use filter_server_traffic_log_handler::filter_server_traffic_log;
|
||||
mod filter_subscribe_log_handler;
|
||||
pub use filter_subscribe_log_handler::filter_subscribe_log;
|
||||
mod filter_traffic_log_details_handler;
|
||||
pub use filter_traffic_log_details_handler::filter_traffic_log_details;
|
||||
mod filter_user_subscribe_traffic_log_handler;
|
||||
pub use filter_user_subscribe_traffic_log_handler::filter_user_subscribe_traffic_log;
|
||||
mod get_log_setting_handler;
|
||||
pub use get_log_setting_handler::get_log_setting;
|
||||
mod get_message_log_list_handler;
|
||||
pub use get_message_log_list_handler::get_message_log_list;
|
||||
mod update_log_setting_handler;
|
||||
pub use update_log_setting_handler::update_log_setting;
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::log::LogSetting;
|
||||
use crate::service::admin::log::filter_balance_log_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn update_log_setting(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<LogSetting>,
|
||||
) -> HttpResult {
|
||||
match filter_balance_log_service::update_log_setting(&state.config, req).await {
|
||||
Ok(_) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::marketing::create_batch_send_email_task_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_batch_send_email_task(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateBatchSendEmailTaskRequest>,
|
||||
) -> HttpResult {
|
||||
match create_batch_send_email_task_service::create_batch_send_email_task(
|
||||
state.repos.task.as_ref(),
|
||||
&state.config,
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::marketing::create_quota_task_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_quota_task(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateQuotaTaskRequest>,
|
||||
) -> HttpResult {
|
||||
match create_quota_task_service::create_quota_task(state.repos.task.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::marketing::get_batch_send_email_task_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_batch_send_email_task_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetBatchSendEmailTaskListRequest>,
|
||||
) -> HttpResult {
|
||||
match get_batch_send_email_task_list_service::get_batch_send_email_task_list(
|
||||
state.repos.task.as_ref(),
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::marketing::get_batch_send_email_task_status_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_batch_send_email_task_status(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<GetBatchSendEmailTaskStatusRequest>,
|
||||
) -> HttpResult {
|
||||
match get_batch_send_email_task_status_service::get_batch_send_email_task_status(
|
||||
state.repos.task.as_ref(),
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::marketing::get_pre_send_email_count_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_pre_send_email_count(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<GetPreSendEmailCountRequest>,
|
||||
) -> HttpResult {
|
||||
match get_pre_send_email_count_service::get_pre_send_email_count(
|
||||
state.repos.user.as_ref(),
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
mod create_batch_send_email_task_handler;
|
||||
pub use create_batch_send_email_task_handler::create_batch_send_email_task;
|
||||
mod create_quota_task_handler;
|
||||
pub use create_quota_task_handler::create_quota_task;
|
||||
mod get_batch_send_email_task_list_handler;
|
||||
pub use get_batch_send_email_task_list_handler::get_batch_send_email_task_list;
|
||||
mod get_batch_send_email_task_status_handler;
|
||||
pub use get_batch_send_email_task_status_handler::get_batch_send_email_task_status;
|
||||
mod get_pre_send_email_count_handler;
|
||||
pub use get_pre_send_email_count_handler::get_pre_send_email_count;
|
||||
mod query_quota_task_list_handler;
|
||||
pub use query_quota_task_list_handler::query_quota_task_list;
|
||||
mod query_quota_task_pre_count_handler;
|
||||
pub use query_quota_task_pre_count_handler::query_quota_task_pre_count;
|
||||
mod query_quota_task_status_handler;
|
||||
pub use query_quota_task_status_handler::query_quota_task_status;
|
||||
mod stop_batch_send_email_task_handler;
|
||||
pub use stop_batch_send_email_task_handler::stop_batch_send_email_task;
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::marketing::query_quota_task_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn query_quota_task_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<QueryQuotaTaskListRequest>,
|
||||
) -> HttpResult {
|
||||
match query_quota_task_list_service::query_quota_task_list(state.repos.task.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::marketing::query_quota_task_pre_count_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn query_quota_task_pre_count(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<QueryQuotaTaskPreCountRequest>,
|
||||
) -> HttpResult {
|
||||
match query_quota_task_pre_count_service::query_quota_task_pre_count(
|
||||
state.repos.user.as_ref(),
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::marketing::query_quota_task_status_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn query_quota_task_status(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<QueryQuotaTaskStatusRequest>,
|
||||
) -> HttpResult {
|
||||
match query_quota_task_status_service::query_quota_task_status(state.repos.task.as_ref(), req)
|
||||
.await
|
||||
{
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::marketing::stop_batch_send_email_task_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn stop_batch_send_email_task(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<StopBatchSendEmailTaskRequest>,
|
||||
) -> HttpResult {
|
||||
match stop_batch_send_email_task_service::stop_batch_send_email_task(
|
||||
state.repos.task.as_ref(),
|
||||
req,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
pub mod ads;
|
||||
pub mod announcement;
|
||||
pub mod application;
|
||||
pub mod auth_method;
|
||||
pub mod console;
|
||||
pub mod coupon;
|
||||
pub mod document;
|
||||
pub mod log;
|
||||
pub mod marketing;
|
||||
pub mod order;
|
||||
pub mod payment;
|
||||
pub mod plugin;
|
||||
pub mod server;
|
||||
pub mod subscribe;
|
||||
pub mod system;
|
||||
pub mod ticket;
|
||||
pub mod tool;
|
||||
pub mod user;
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::order::create_order_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_order(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateOrderRequest>,
|
||||
) -> HttpResult {
|
||||
match create_order_service::create_order(state.repos.order.as_ref(), req).await {
|
||||
Ok(()) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::order::get_order_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_order_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetOrderListRequest>,
|
||||
) -> HttpResult {
|
||||
match get_order_list_service::get_order_list(state.repos.order.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
mod create_order_handler;
|
||||
pub use create_order_handler::create_order;
|
||||
mod get_order_list_handler;
|
||||
pub use get_order_list_handler::get_order_list;
|
||||
mod update_order_status_handler;
|
||||
pub use update_order_status_handler::update_order_status;
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::order::update_order_status_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn update_order_status(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<UpdateOrderStatusRequest>,
|
||||
) -> HttpResult {
|
||||
match update_order_status_service::update_order_status(state.repos.order.as_ref(), req).await {
|
||||
Ok(()) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::payment::CreatePaymentMethodRequest;
|
||||
use crate::service::admin::payment::get_payment_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_payment_method(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreatePaymentMethodRequest>,
|
||||
) -> HttpResult {
|
||||
match get_payment_method_list_service::create_payment_method(state.repos.payment.as_ref(), req).await {
|
||||
Ok(_) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::payment::DeletePaymentMethodRequest;
|
||||
use crate::service::admin::payment::get_payment_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn delete_payment_method(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<DeletePaymentMethodRequest>,
|
||||
) -> HttpResult {
|
||||
match get_payment_method_list_service::delete_payment_method(state.repos.payment.as_ref(), req).await {
|
||||
Ok(_) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
use axum::extract::{Query, State};
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::payment::GetPaymentMethodListRequest;
|
||||
use crate::service::admin::payment::get_payment_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_payment_method_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<GetPaymentMethodListRequest>,
|
||||
) -> HttpResult {
|
||||
match get_payment_method_list_service::get_payment_method_list(state.repos.payment.as_ref(), req).await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use axum::extract::State;
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::payment::get_payment_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn get_payment_platform(
|
||||
State(_state): State<AppState>,
|
||||
) -> HttpResult {
|
||||
match get_payment_method_list_service::get_payment_platform().await {
|
||||
Ok(d) => build_http_result(Some(d), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
mod create_payment_method_handler;
|
||||
pub use create_payment_method_handler::create_payment_method;
|
||||
mod update_payment_method_handler;
|
||||
pub use update_payment_method_handler::update_payment_method;
|
||||
mod delete_payment_method_handler;
|
||||
pub use delete_payment_method_handler::delete_payment_method;
|
||||
mod get_payment_method_list_handler;
|
||||
pub use get_payment_method_list_handler::get_payment_method_list;
|
||||
mod get_payment_platform_handler;
|
||||
pub use get_payment_platform_handler::get_payment_platform;
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::payment::UpdatePaymentMethodRequest;
|
||||
use crate::service::admin::payment::get_payment_method_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn update_payment_method(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<UpdatePaymentMethodRequest>,
|
||||
) -> HttpResult {
|
||||
match get_payment_method_list_service::update_payment_method(state.repos.payment.as_ref(), req).await {
|
||||
Ok(_) => build_http_result(Some(()), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
// Plugin API types and helpers
|
||||
@@ -0,0 +1,7 @@
|
||||
use result::http_result::HttpResult;
|
||||
|
||||
pub async fn detail(
|
||||
|
||||
) -> HttpResult {
|
||||
todo!()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
use result::http_result::HttpResult;
|
||||
|
||||
pub async fn disable_handler(
|
||||
|
||||
) -> HttpResult {
|
||||
todo!()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
use result::http_result::HttpResult;
|
||||
|
||||
pub async fn enable_handler(
|
||||
|
||||
) -> HttpResult {
|
||||
todo!()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
use result::http_result::HttpResult;
|
||||
|
||||
pub async fn list(
|
||||
|
||||
) -> HttpResult {
|
||||
todo!()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
mod api;
|
||||
mod detail;
|
||||
pub use detail::detail;
|
||||
mod disable;
|
||||
pub use disable::disable_handler;
|
||||
mod enable;
|
||||
pub use enable::enable_handler;
|
||||
mod list;
|
||||
pub use list::list;
|
||||
mod reload;
|
||||
pub use reload::reload_handler;
|
||||
@@ -0,0 +1,7 @@
|
||||
use result::http_result::HttpResult;
|
||||
|
||||
pub async fn reload_handler(
|
||||
|
||||
) -> HttpResult {
|
||||
todo!()
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::server::create_node_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_node(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateNodeRequest>,
|
||||
) -> HttpResult {
|
||||
match create_node_service::create_node(state.repos.node.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::server::create_server_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn create_server(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateServerRequest>,
|
||||
) -> HttpResult {
|
||||
match create_server_service::create_server(state.repos.node.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::server::delete_node_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn delete_node(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<DeleteNodeRequest>,
|
||||
) -> HttpResult {
|
||||
match delete_node_service::delete_node(state.repos.node.as_ref(), req.id).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::server::delete_server_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn delete_server(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<DeleteServerRequest>,
|
||||
) -> HttpResult {
|
||||
match delete_server_service::delete_server(state.repos.node.as_ref(), req.id).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::service::admin::server::filter_node_list_service::{self, FilterNodeListRequest};
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_node_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterNodeListRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_node_list_service::filter_node_list(state.repos.node.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use axum::extract::{Query, State};
|
||||
|
||||
use crate::handler::AppState;
|
||||
use crate::model::dto::*;
|
||||
use crate::service::admin::server::filter_server_list_service;
|
||||
use result::http_result::{build_http_result, HttpResult};
|
||||
|
||||
pub async fn filter_server_list(
|
||||
State(state): State<AppState>,
|
||||
Query(req): Query<FilterServerListRequest>,
|
||||
) -> HttpResult {
|
||||
match filter_server_list_service::filter_server_list(state.repos.node.as_ref(), req).await {
|
||||
Ok(data) => build_http_result(Some(data), None),
|
||||
Err(e) => build_http_result::<()>(None, Some(e)),
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user