mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-16 14:47:25 +08:00
feat/web: Patchset 3 (#455)
https://apifox.com/apidoc/shared-ceda7a60-e817-4ea8-827b-de4e874dc45e implement all backend API
This commit is contained in:
35
easytier-web/src/db/entity/groups.rs
Normal file
35
easytier-web/src/db/entity/groups.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "groups")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(unique)]
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::groups_permissions::Entity")]
|
||||
GroupsPermissions,
|
||||
#[sea_orm(has_many = "super::users_groups::Entity")]
|
||||
UsersGroups,
|
||||
}
|
||||
|
||||
impl Related<super::groups_permissions::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::GroupsPermissions.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::users_groups::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::UsersGroups.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
47
easytier-web/src/db/entity/groups_permissions.rs
Normal file
47
easytier-web/src/db/entity/groups_permissions.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "groups_permissions")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub group_id: i32,
|
||||
pub permission_id: i32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::groups::Entity",
|
||||
from = "Column::GroupId",
|
||||
to = "super::groups::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Groups,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::permissions::Entity",
|
||||
from = "Column::PermissionId",
|
||||
to = "super::permissions::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Permissions,
|
||||
}
|
||||
|
||||
impl Related<super::groups::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Groups.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::permissions::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Permissions.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
11
easytier-web/src/db/entity/mod.rs
Normal file
11
easytier-web/src/db/entity/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
||||
|
||||
pub mod prelude;
|
||||
|
||||
pub mod groups;
|
||||
pub mod groups_permissions;
|
||||
pub mod permissions;
|
||||
pub mod tower_sessions;
|
||||
pub mod user_running_network_configs;
|
||||
pub mod users;
|
||||
pub mod users_groups;
|
||||
27
easytier-web/src/db/entity/permissions.rs
Normal file
27
easytier-web/src/db/entity/permissions.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "permissions")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(unique)]
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::groups_permissions::Entity")]
|
||||
GroupsPermissions,
|
||||
}
|
||||
|
||||
impl Related<super::groups_permissions::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::GroupsPermissions.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
9
easytier-web/src/db/entity/prelude.rs
Normal file
9
easytier-web/src/db/entity/prelude.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
||||
|
||||
pub use super::groups::Entity as Groups;
|
||||
pub use super::groups_permissions::Entity as GroupsPermissions;
|
||||
pub use super::permissions::Entity as Permissions;
|
||||
pub use super::tower_sessions::Entity as TowerSessions;
|
||||
pub use super::user_running_network_configs::Entity as UserRunningNetworkConfigs;
|
||||
pub use super::users::Entity as Users;
|
||||
pub use super::users_groups::Entity as UsersGroups;
|
||||
19
easytier-web/src/db/entity/tower_sessions.rs
Normal file
19
easytier-web/src/db/entity/tower_sessions.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "tower_sessions")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false, column_type = "Text")]
|
||||
pub id: String,
|
||||
#[sea_orm(column_type = "Blob")]
|
||||
pub data: Vec<u8>,
|
||||
pub expiry_date: i32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
39
easytier-web/src/db/entity/user_running_network_configs.rs
Normal file
39
easytier-web/src/db/entity/user_running_network_configs.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "user_running_network_configs")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
#[sea_orm(column_type = "Text", unique)]
|
||||
pub network_instance_id: String,
|
||||
#[sea_orm(column_type = "Text")]
|
||||
pub network_config: String,
|
||||
pub disabled: bool,
|
||||
pub create_time: DateTimeWithTimeZone,
|
||||
pub update_time: DateTimeWithTimeZone,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::users::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Users,
|
||||
}
|
||||
|
||||
impl Related<super::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Users.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
36
easytier-web/src/db/entity/users.rs
Normal file
36
easytier-web/src/db/entity/users.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "users")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(unique)]
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::user_running_network_configs::Entity")]
|
||||
UserRunningNetworkConfigs,
|
||||
#[sea_orm(has_many = "super::users_groups::Entity")]
|
||||
UsersGroups,
|
||||
}
|
||||
|
||||
impl Related<super::user_running_network_configs::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::UserRunningNetworkConfigs.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::users_groups::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::UsersGroups.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
47
easytier-web/src/db/entity/users_groups.rs
Normal file
47
easytier-web/src/db/entity/users_groups.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "users_groups")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
pub group_id: i32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::groups::Entity",
|
||||
from = "Column::GroupId",
|
||||
to = "super::groups::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Groups,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::users::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Users,
|
||||
}
|
||||
|
||||
impl Related<super::groups::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Groups.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Users.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
215
easytier-web/src/db/mod.rs
Normal file
215
easytier-web/src/db/mod.rs
Normal file
@@ -0,0 +1,215 @@
|
||||
// sea-orm-cli generate entity -u sqlite:./et.db -o easytier-web/src/db/entity/ --with-serde both --with-copy-enums
|
||||
#[allow(unused_imports)]
|
||||
pub mod entity;
|
||||
|
||||
use entity::user_running_network_configs;
|
||||
use sea_orm::{
|
||||
sea_query::OnConflict, ColumnTrait as _, DatabaseConnection, DbErr, EntityTrait as _,
|
||||
QueryFilter as _, SqlxSqliteConnector, TransactionTrait as _,
|
||||
};
|
||||
use sea_orm_migration::MigratorTrait as _;
|
||||
use sqlx::{migrate::MigrateDatabase as _, types::chrono, Sqlite, SqlitePool};
|
||||
|
||||
use crate::migrator;
|
||||
|
||||
type UserIdInDb = i32;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Db {
|
||||
db_path: String,
|
||||
db: SqlitePool,
|
||||
orm_db: DatabaseConnection,
|
||||
}
|
||||
|
||||
impl Db {
|
||||
pub async fn new<T: ToString>(db_path: T) -> anyhow::Result<Self> {
|
||||
let db = Self::prepare_db(db_path.to_string().as_str()).await?;
|
||||
let orm_db = SqlxSqliteConnector::from_sqlx_sqlite_pool(db.clone());
|
||||
migrator::Migrator::up(&orm_db, None).await?;
|
||||
|
||||
Ok(Self {
|
||||
db_path: db_path.to_string(),
|
||||
db,
|
||||
orm_db,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn memory_db() -> Self {
|
||||
Self::new(":memory:").await.unwrap()
|
||||
}
|
||||
|
||||
#[tracing::instrument(ret)]
|
||||
async fn prepare_db(db_path: &str) -> anyhow::Result<SqlitePool> {
|
||||
if !Sqlite::database_exists(db_path).await.unwrap_or(false) {
|
||||
tracing::info!("Database not found, creating a new one");
|
||||
Sqlite::create_database(db_path).await?;
|
||||
}
|
||||
|
||||
let db = sqlx::pool::PoolOptions::new()
|
||||
.max_lifetime(None)
|
||||
.idle_timeout(None)
|
||||
.connect(db_path)
|
||||
.await?;
|
||||
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> SqlitePool {
|
||||
self.db.clone()
|
||||
}
|
||||
|
||||
pub fn orm_db(&self) -> &DatabaseConnection {
|
||||
&self.orm_db
|
||||
}
|
||||
|
||||
pub async fn insert_or_update_user_network_config<T: ToString>(
|
||||
&self,
|
||||
user_id: UserIdInDb,
|
||||
network_inst_id: uuid::Uuid,
|
||||
network_config: T,
|
||||
) -> Result<(), DbErr> {
|
||||
let txn = self.orm_db().begin().await?;
|
||||
|
||||
use entity::user_running_network_configs as urnc;
|
||||
|
||||
let on_conflict = OnConflict::column(urnc::Column::NetworkInstanceId)
|
||||
.update_columns([
|
||||
urnc::Column::NetworkConfig,
|
||||
urnc::Column::Disabled,
|
||||
urnc::Column::UpdateTime,
|
||||
])
|
||||
.to_owned();
|
||||
let insert_m = urnc::ActiveModel {
|
||||
user_id: sea_orm::Set(user_id),
|
||||
network_instance_id: sea_orm::Set(network_inst_id.to_string()),
|
||||
network_config: sea_orm::Set(network_config.to_string()),
|
||||
disabled: sea_orm::Set(false),
|
||||
create_time: sea_orm::Set(chrono::Local::now().fixed_offset()),
|
||||
update_time: sea_orm::Set(chrono::Local::now().fixed_offset()),
|
||||
..Default::default()
|
||||
};
|
||||
urnc::Entity::insert(insert_m)
|
||||
.on_conflict(on_conflict)
|
||||
.do_nothing()
|
||||
.exec(&txn)
|
||||
.await?;
|
||||
|
||||
txn.commit().await
|
||||
}
|
||||
|
||||
pub async fn delete_network_config(
|
||||
&self,
|
||||
user_id: UserIdInDb,
|
||||
network_inst_id: uuid::Uuid,
|
||||
) -> Result<(), DbErr> {
|
||||
use entity::user_running_network_configs as urnc;
|
||||
|
||||
urnc::Entity::delete_many()
|
||||
.filter(urnc::Column::UserId.eq(user_id))
|
||||
.filter(urnc::Column::NetworkInstanceId.eq(network_inst_id.to_string()))
|
||||
.exec(self.orm_db())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn list_network_configs(
|
||||
&self,
|
||||
user_id: UserIdInDb,
|
||||
only_enabled: bool,
|
||||
) -> Result<Vec<user_running_network_configs::Model>, DbErr> {
|
||||
use entity::user_running_network_configs as urnc;
|
||||
|
||||
let configs = urnc::Entity::find().filter(urnc::Column::UserId.eq(user_id));
|
||||
let configs = if only_enabled {
|
||||
configs.filter(urnc::Column::Disabled.eq(false))
|
||||
} else {
|
||||
configs
|
||||
};
|
||||
|
||||
let configs = configs.all(self.orm_db()).await?;
|
||||
|
||||
Ok(configs)
|
||||
}
|
||||
|
||||
pub async fn get_user_id<T: ToString>(
|
||||
&self,
|
||||
user_name: T,
|
||||
) -> Result<Option<UserIdInDb>, DbErr> {
|
||||
use entity::users as u;
|
||||
|
||||
let user = u::Entity::find()
|
||||
.filter(u::Column::Username.eq(user_name.to_string()))
|
||||
.one(self.orm_db())
|
||||
.await?;
|
||||
|
||||
Ok(user.map(|u| u.id))
|
||||
}
|
||||
|
||||
// TODO: currently we don't have a token system, so we just use the user name as token
|
||||
pub async fn get_user_id_by_token<T: ToString>(
|
||||
&self,
|
||||
token: T,
|
||||
) -> Result<Option<UserIdInDb>, DbErr> {
|
||||
self.get_user_id(token).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter as _};
|
||||
|
||||
use crate::db::{entity::user_running_network_configs, Db};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_user_network_config_management() {
|
||||
let db = Db::memory_db().await;
|
||||
let user_id = 1;
|
||||
let network_config = "test_config";
|
||||
let inst_id = uuid::Uuid::new_v4();
|
||||
|
||||
db.insert_or_update_user_network_config(user_id, inst_id, network_config)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let result = user_running_network_configs::Entity::find()
|
||||
.filter(user_running_network_configs::Column::UserId.eq(user_id))
|
||||
.one(db.orm_db())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
println!("{:?}", result);
|
||||
assert_eq!(result.network_config, network_config);
|
||||
|
||||
// overwrite the config
|
||||
let network_config = "test_config2";
|
||||
db.insert_or_update_user_network_config(user_id, inst_id, network_config)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let result2 = user_running_network_configs::Entity::find()
|
||||
.filter(user_running_network_configs::Column::UserId.eq(user_id))
|
||||
.one(db.orm_db())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
println!("{:?}", result2);
|
||||
assert_eq!(result2.network_config, network_config);
|
||||
|
||||
assert_eq!(result.create_time, result2.create_time);
|
||||
assert_ne!(result.update_time, result2.update_time);
|
||||
|
||||
assert_eq!(
|
||||
db.list_network_configs(user_id, true).await.unwrap().len(),
|
||||
1
|
||||
);
|
||||
|
||||
db.delete_network_config(user_id, inst_id).await.unwrap();
|
||||
let result3 = user_running_network_configs::Entity::find()
|
||||
.filter(user_running_network_configs::Column::UserId.eq(user_id))
|
||||
.one(db.orm_db())
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(result3.is_none());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user