apply rebase
This commit is contained in:
parent
9e3c3fcbe0
commit
310df0c86d
@ -1,13 +1,13 @@
|
|||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||||
#[sea_orm(table_name = "credits")]
|
#[sea_orm(table_name = "admin")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: u64,
|
||||||
pub credits: u64,
|
|
||||||
#[sea_orm(unique)]
|
#[sea_orm(unique)]
|
||||||
pub user_id: u64,
|
pub user_id: u64,
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.5
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
use crate::serialization;
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -10,8 +9,7 @@ pub struct Model {
|
|||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
#[sea_orm(unique)]
|
#[sea_orm(unique)]
|
||||||
#[serde(serialize_with = "serialization::uuid_as_ulid")]
|
pub bearer_token: Vec<u8>,
|
||||||
pub bearer_token: Uuid,
|
|
||||||
pub user_id: u64,
|
pub user_id: u64,
|
||||||
pub expires_at: DateTimeUtc,
|
pub expires_at: DateTimeUtc,
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.5
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
pub mod credits;
|
pub mod credits;
|
||||||
|
pub mod admin;
|
||||||
pub mod login;
|
pub mod login;
|
||||||
pub mod pending_login;
|
pub mod pending_login;
|
||||||
pub mod referral;
|
pub mod referral;
|
||||||
@ -12,6 +13,5 @@ pub mod rpc_key;
|
|||||||
pub mod rpc_request;
|
pub mod rpc_request;
|
||||||
pub mod sea_orm_active_enums;
|
pub mod sea_orm_active_enums;
|
||||||
pub mod secondary_user;
|
pub mod secondary_user;
|
||||||
pub mod serialization;
|
|
||||||
pub mod user;
|
pub mod user;
|
||||||
pub mod user_tier;
|
pub mod user_tier;
|
||||||
|
@ -13,9 +13,7 @@ mod m20221108_200345_save_anon_stats;
|
|||||||
mod m20221211_124002_request_method_privacy;
|
mod m20221211_124002_request_method_privacy;
|
||||||
mod m20221213_134158_move_login_into_database;
|
mod m20221213_134158_move_login_into_database;
|
||||||
mod m20230119_204135_better_free_tier;
|
mod m20230119_204135_better_free_tier;
|
||||||
mod m20230205_130035_create_credits;
|
mod m20230117_191358_admin_table;
|
||||||
mod m20230205_133204_create_requests;
|
|
||||||
mod m20230205_133755_create_referrals;
|
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
@ -35,10 +33,7 @@ impl MigratorTrait for Migrator {
|
|||||||
Box::new(m20221108_200345_save_anon_stats::Migration),
|
Box::new(m20221108_200345_save_anon_stats::Migration),
|
||||||
Box::new(m20221211_124002_request_method_privacy::Migration),
|
Box::new(m20221211_124002_request_method_privacy::Migration),
|
||||||
Box::new(m20221213_134158_move_login_into_database::Migration),
|
Box::new(m20221213_134158_move_login_into_database::Migration),
|
||||||
Box::new(m20230119_204135_better_free_tier::Migration),
|
Box::new(m20230117_191358_admin_table::Migration),
|
||||||
Box::new(m20230205_130035_create_credits::Migration),
|
|
||||||
Box::new(m20230205_133204_create_requests::Migration),
|
|
||||||
Box::new(m20230205_133755_create_referrals::Migration),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
58
migration/src/m20230117_191358_admin_table.rs
Normal file
58
migration/src/m20230117_191358_admin_table.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
// Replace the sample below with your own migration scripts
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(Admin::Table)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Admin::Id)
|
||||||
|
.big_unsigned()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Admin::UserId)
|
||||||
|
.big_unsigned()
|
||||||
|
.unique_key()
|
||||||
|
.not_null()
|
||||||
|
)
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("fk-admin-user_id")
|
||||||
|
.from(Admin::Table, Admin::UserId)
|
||||||
|
.to(User::Table, User::Id),
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
// Replace the sample below with your own migration scripts
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(Admin::Table).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Learn more at https://docs.rs/sea-query#iden
|
||||||
|
#[derive(Iden)]
|
||||||
|
enum User {
|
||||||
|
Table,
|
||||||
|
Id
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Iden)]
|
||||||
|
enum Admin {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
UserId,
|
||||||
|
}
|
124
web3_proxy/src/admin_queries.rs
Normal file
124
web3_proxy/src/admin_queries.rs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
use crate::app::Web3ProxyApp;
|
||||||
|
use crate::frontend::errors::FrontendErrorResponse;
|
||||||
|
use crate::user_queries::get_user_id_from_params;
|
||||||
|
use anyhow::Context;
|
||||||
|
use axum::{
|
||||||
|
Json,
|
||||||
|
headers::{authorization::Bearer, Authorization},
|
||||||
|
TypedHeader,
|
||||||
|
};
|
||||||
|
use axum::response::{IntoResponse, Response};
|
||||||
|
use entities::{admin, user, user_tier};
|
||||||
|
use ethers::prelude::Address;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use http::StatusCode;
|
||||||
|
use migration::sea_orm::{self, IntoActiveModel};
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn query_admin_modify_usertier<'a>(
|
||||||
|
app: &'a Web3ProxyApp,
|
||||||
|
bearer: Option<TypedHeader<Authorization<Bearer>>>,
|
||||||
|
params: &'a HashMap<String, String>
|
||||||
|
) -> Result<Response, FrontendErrorResponse> {
|
||||||
|
|
||||||
|
// Quickly return if any of the input tokens are bad
|
||||||
|
let user_address: Vec<u8> = params
|
||||||
|
.get("user_address")
|
||||||
|
.ok_or_else(||
|
||||||
|
FrontendErrorResponse::StatusCode(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
"Unable to find user_address key in request".to_string(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
)?
|
||||||
|
.parse::<Address>()
|
||||||
|
.map_err(|err| {
|
||||||
|
FrontendErrorResponse::StatusCode(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
"Unable to parse user_address as an Address".to_string(),
|
||||||
|
Some(err.into()),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.to_fixed_bytes().into();
|
||||||
|
let user_tier_title = params
|
||||||
|
.get("user_tier_title")
|
||||||
|
.ok_or_else(|| FrontendErrorResponse::StatusCode(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
"Unable to get the user_tier_title key from the request".to_string(),
|
||||||
|
None,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
// Prepare output body
|
||||||
|
let mut response_body = HashMap::new();
|
||||||
|
response_body.insert(
|
||||||
|
"user_address",
|
||||||
|
serde_json::Value::String(user_address.into()),
|
||||||
|
);
|
||||||
|
response_body.insert(
|
||||||
|
"user_tier_title",
|
||||||
|
serde_json::Value::String(user_tier_title.into()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Establish connections
|
||||||
|
let db_conn = app.db_conn().context("query_admin_modify_user needs a db")?;
|
||||||
|
let db_replica = app
|
||||||
|
.db_replica()
|
||||||
|
.context("query_user_stats needs a db replica")?;
|
||||||
|
let mut redis_conn = app
|
||||||
|
.redis_conn()
|
||||||
|
.await
|
||||||
|
.context("query_admin_modify_user had a redis connection error")?
|
||||||
|
.context("query_admin_modify_user needs a redis")?;
|
||||||
|
|
||||||
|
// Try to get the user who is calling from redis (if existent) / else from the database
|
||||||
|
// TODO: Make a single query, where you retrieve the user, and directly from it the secondary user (otherwise we do two jumpy, which is unnecessary)
|
||||||
|
// get the user id first. if it is 0, we should use a cache on the app
|
||||||
|
let caller_id = get_user_id_from_params(&mut redis_conn, &db_conn, &db_replica, bearer, ¶ms).await?;
|
||||||
|
|
||||||
|
// Check if the caller is an admin (i.e. if he is in an admin table)
|
||||||
|
let admin: admin::Model = admin::Entity::find()
|
||||||
|
.filter(admin::Entity::UserId.eq(caller_id))
|
||||||
|
.one(&db_replica)
|
||||||
|
.await?
|
||||||
|
.context("This user is not registered as an admin")?;
|
||||||
|
|
||||||
|
// If we are here, that means an admin was found, and we can safely proceed
|
||||||
|
|
||||||
|
// Fetch the admin, and the user
|
||||||
|
let user: user::Model = user::Entity::find()
|
||||||
|
.filter(user::Column::Address.eq(user_address))
|
||||||
|
.one(&db_replica)
|
||||||
|
.await?
|
||||||
|
.context("No user with this id found as the change")?;
|
||||||
|
// Return early if the target user_tier_id is the same as the original user_tier_id
|
||||||
|
response_body.insert(
|
||||||
|
"user_tier_title",
|
||||||
|
serde_json::Value::String(user.user_tier_id.into()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now we can modify the user's tier
|
||||||
|
let new_user_tier: user_tier::Model = user_tier::Entity::find()
|
||||||
|
.filter(user_tier::Column::Title.eq(user_tier_title.clone()))
|
||||||
|
.one(&db_replica)
|
||||||
|
.await?
|
||||||
|
.context("No user tier found with that name")?;
|
||||||
|
|
||||||
|
if user.user_tier_id == new_user_tier.id {
|
||||||
|
info!("user already has that tier");
|
||||||
|
} else {
|
||||||
|
let mut user = user.into_active_model();
|
||||||
|
|
||||||
|
user.user_tier_id = sea_orm::Set(new_user_tier.id);
|
||||||
|
|
||||||
|
user.save(&db_conn).await?;
|
||||||
|
|
||||||
|
info!("user's tier changed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, remove the user from redis
|
||||||
|
// TODO: Also remove the user from the redis
|
||||||
|
|
||||||
|
Ok(Json(&response_body).into_response())
|
||||||
|
|
||||||
|
}
|
@ -167,7 +167,7 @@ pub async fn serve(port: u16, proxy_app: Arc<Web3ProxyApp>) -> anyhow::Result<()
|
|||||||
get(users::user_stats_aggregated_get),
|
get(users::user_stats_aggregated_get),
|
||||||
)
|
)
|
||||||
.route("/user/stats/detailed", get(users::user_stats_detailed_get))
|
.route("/user/stats/detailed", get(users::user_stats_detailed_get))
|
||||||
.route("/user/modify_role", get(users::admin_change_user_roles))
|
.route("/admin/modify_role", get(users::admin_change_user_roles))
|
||||||
.route("/user/logout", post(users::user_logout_post))
|
.route("/user/logout", post(users::user_logout_post))
|
||||||
//
|
//
|
||||||
// Axum layers
|
// Axum layers
|
||||||
|
@ -44,6 +44,7 @@ use ulid::Ulid;
|
|||||||
use entities::user::Relation::UserTier;
|
use entities::user::Relation::UserTier;
|
||||||
use migration::extension::postgres::Type;
|
use migration::extension::postgres::Type;
|
||||||
use thread_fast_rng::rand;
|
use thread_fast_rng::rand;
|
||||||
|
use crate::admin_queries::query_admin_modify_usertier;
|
||||||
use crate::frontend::errors::FrontendErrorResponse;
|
use crate::frontend::errors::FrontendErrorResponse;
|
||||||
|
|
||||||
/// `GET /user/login/:user_address` or `GET /user/login/:user_address/:message_eip` -- Start the "Sign In with Ethereum" (siwe) login flow.
|
/// `GET /user/login/:user_address` or `GET /user/login/:user_address/:message_eip` -- Start the "Sign In with Ethereum" (siwe) login flow.
|
||||||
@ -954,119 +955,7 @@ pub async fn admin_change_user_roles(
|
|||||||
bearer: Option<TypedHeader<Authorization<Bearer>>>,
|
bearer: Option<TypedHeader<Authorization<Bearer>>>,
|
||||||
Query(params): Query<HashMap<String, String>>,
|
Query(params): Query<HashMap<String, String>>,
|
||||||
) -> FrontendResult {
|
) -> FrontendResult {
|
||||||
|
let response = query_admin_modify_usertier(&app, bearer, ¶ms).await?;
|
||||||
|
|
||||||
// Make sure that the bearer exists, and has admin rights ...
|
response
|
||||||
let user_address: Vec<u8> = params
|
|
||||||
.get("user_address")
|
|
||||||
.ok_or_else(||
|
|
||||||
FrontendErrorResponse::StatusCode(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"Unable to find user_address key in request".to_string(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
)?
|
|
||||||
.parse::<Address>()
|
|
||||||
.map_err(|err| {
|
|
||||||
FrontendErrorResponse::StatusCode(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"Unable to parse user_address as an Address".to_string(),
|
|
||||||
Some(err.into()),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.to_fixed_bytes().into();
|
|
||||||
let user_tier_title = params
|
|
||||||
.get("user_tier_title")
|
|
||||||
.ok_or_else(|| FrontendErrorResponse::StatusCode(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"Unable to get the user_tier_title key from the request".to_string(),
|
|
||||||
None,
|
|
||||||
))?;
|
|
||||||
|
|
||||||
// Create database connections and all that
|
|
||||||
let db_conn = app.db_conn().context("admin_change_user_roles needs a db")?;
|
|
||||||
let db_replica = app
|
|
||||||
.db_replica()
|
|
||||||
.context("admin_change_user_roles needs a db replica")?;
|
|
||||||
let mut redis_conn = app
|
|
||||||
.redis_conn()
|
|
||||||
.await
|
|
||||||
.context("admin_change_user_roles had a redis connection error")?
|
|
||||||
.context("admin_change_user_roles needs a redis")?;
|
|
||||||
|
|
||||||
// TODO: Make a single query, where you retrieve the user, and directly from it the secondary user (otherwise we do two jumpy, which is unnecessary)
|
|
||||||
// get the user id first. if it is 0, we should use a cache on the app
|
|
||||||
let user_id = get_user_id_from_params(&mut redis_conn, &db_conn, &db_replica, bearer, ¶ms).await?;
|
|
||||||
|
|
||||||
let mut response_body = HashMap::new();
|
|
||||||
response_body.insert(
|
|
||||||
"user_id",
|
|
||||||
serde_json::Value::Number(user_id.into()),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get both the user and user role
|
|
||||||
let user: user::Model = user::Entity::find_by_id(user_id)
|
|
||||||
.one(&db_conn)
|
|
||||||
.await?
|
|
||||||
.context("No user with this id found!")?;
|
|
||||||
// TODO: Let's connect the string, and find the previous string of the user id ... (this might be ok for now too thought)
|
|
||||||
response_body.insert(
|
|
||||||
"previous_tier",
|
|
||||||
serde_json::Value::Number(user.user_tier_id.into()),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Modify the user-role ...
|
|
||||||
// Check if this use has admin privileges ...
|
|
||||||
let user_role: secondary_user::Model = secondary_user::Entity::find()
|
|
||||||
.filter(secondary_user::Column::UserId.eq(user_id))
|
|
||||||
.one(&db_conn)
|
|
||||||
.await?
|
|
||||||
.context("No user tier found with that name")?;
|
|
||||||
println!("User role is: {:?}", user_role);
|
|
||||||
|
|
||||||
// Return error if the user is not an admin or a user
|
|
||||||
match user_role.role {
|
|
||||||
Role::Owner | Role::Admin => {
|
|
||||||
// Change the user tier, we can copy a bunch of the functionality from the user-tier address
|
|
||||||
|
|
||||||
// Check if all the required parameters are included in the request, if not, return an error
|
|
||||||
let user = user::Entity::find()
|
|
||||||
.filter(user::Column::Address.eq(user_address))
|
|
||||||
.one(&db_conn)
|
|
||||||
.await?
|
|
||||||
.context("No user found with that key")?;
|
|
||||||
|
|
||||||
// TODO: don't serialize the rpc key
|
|
||||||
debug!("user: {:#?}", user);
|
|
||||||
|
|
||||||
let user_tier = user_tier::Entity::find()
|
|
||||||
.filter(user_tier::Column::Title.eq(user_tier_title.clone()))
|
|
||||||
.one(&db_conn)
|
|
||||||
.await?
|
|
||||||
.context("No user tier found with that name")?;
|
|
||||||
debug!("user_tier: {:#?}", user_tier);
|
|
||||||
|
|
||||||
if user.user_tier_id == user_tier.id {
|
|
||||||
info!("user already has that tier");
|
|
||||||
} else {
|
|
||||||
let mut user = user.into_active_model();
|
|
||||||
|
|
||||||
user.user_tier_id = sea_orm::Set(user_tier.id);
|
|
||||||
|
|
||||||
user.save(&db_conn).await?;
|
|
||||||
|
|
||||||
info!("user's tier changed");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Role::Collaborator => {
|
|
||||||
return Err(anyhow::anyhow!("you do not have admin rights!").into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
response_body.insert(
|
|
||||||
"user_id",
|
|
||||||
serde_json::Value::Number(user_id.into()),
|
|
||||||
);
|
|
||||||
let mut response = Json(&response_body).into_response();
|
|
||||||
Ok(response)
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod app_stats;
|
pub mod app_stats;
|
||||||
|
pub mod admin_queries;
|
||||||
pub mod block_number;
|
pub mod block_number;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod frontend;
|
pub mod frontend;
|
||||||
|
@ -9,6 +9,7 @@ use axum::{
|
|||||||
TypedHeader,
|
TypedHeader,
|
||||||
};
|
};
|
||||||
use chrono::{NaiveDateTime, Utc};
|
use chrono::{NaiveDateTime, Utc};
|
||||||
|
use ethers::prelude::Address;
|
||||||
use entities::{login, rpc_accounting, rpc_key};
|
use entities::{login, rpc_accounting, rpc_key};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
|
Loading…
Reference in New Issue
Block a user