Skip to content

Commit

Permalink
update rewards response with total rewards count
Browse files Browse the repository at this point in the history
  • Loading branch information
Kirill-K-1 committed Nov 13, 2024
1 parent 01ff33b commit 3a2a023
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 151 deletions.
16 changes: 15 additions & 1 deletion gov-portal-db/src/mongo_client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use async_trait::async_trait;
use mongodb::{
bson::Document,
options::{ClientOptions, FindOptions, InsertOneOptions, UpdateModifications, UpdateOptions},
options::{
ClientOptions, CountOptions, FindOptions, InsertOneOptions, UpdateModifications,
UpdateOptions,
},
results::{InsertOneResult, UpdateResult},
Client, Collection, Cursor, Database,
};
Expand Down Expand Up @@ -46,6 +49,17 @@ impl MongoCollection {
.with_options(find_options)
.await
}
/// Query count request from collection by filter
pub async fn count(
&self,
filter: impl Into<Document>,
count_options: impl Into<Option<CountOptions>>,
) -> Result<u64, mongodb::error::Error> {
self.inner
.count_documents(filter.into())
.with_options(count_options)
.await
}

/// Insert single document to collection
#[allow(unused)]
Expand Down
305 changes: 163 additions & 142 deletions gov-portal-db/src/rewards_manager/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
pub mod client;
pub mod error;

use bson::doc;
use bson::{doc, Document};
use ethereum_types::Address;
use futures_util::TryStreamExt;
use mongodb::options::{FindOptions, UpdateOptions};
use mongodb::options::{CountOptions, FindOptions, UpdateOptions};
use serde::Deserialize;

use shared::common::{
Expand Down Expand Up @@ -104,15 +104,51 @@ impl RewardsManager {
}
}

/// Searches for multiple user profiles within MongoDB by provided EVM-like address [`Address`] list and returns [`Vec<UserProfile>`]
/// Counts all rewards allocated by requestor within MongoDB by provided wallet EVM-like address [`Address`]
pub async fn count_rewards(
&self,
requestor: &Address,
from: Option<u64>,
to: Option<u64>,
community: Option<&str>,
) -> Result<u64, error::Error> {
if !self
.config
.moderators
.iter()
.any(|wallet| wallet == requestor)
{
return Err(error::Error::Unauthorized);
}

let expr = self.build_rewards_filter_expr(from, to, community)?;
let filter = doc! {
"$expr": bson::to_bson(&expr)?,
};

let res = tokio::time::timeout(
self.db_client.req_timeout,
self.db_client
.collection()
.count(filter, CountOptions::default()),
)
.await?
.map_err(error::Error::from);

tracing::debug!("Count total rewards result: {res:?}");

res
}

/// Searches all rewards allocated by requestor within MongoDB by provided wallet EVM-like address [`Address`] and returns [`Vec<Rewards>`]
pub async fn get_rewards(
&self,
requestor: &Address,
start: Option<u64>,
limit: Option<u64>,
from: Option<u64>,
to: Option<u64>,
community: Option<String>,
community: Option<&str>,
) -> Result<Vec<Rewards>, error::Error> {
let start = start.unwrap_or_default();
let limit = limit
Expand All @@ -128,75 +164,9 @@ impl RewardsManager {
return Err(error::Error::Unauthorized);
}

let mut in_and_cond_doc = doc! {
"$and": []
};

let mut cond = doc! {};

if let Some(community) = community {
cond.insert("$eq", bson::to_bson(&["$$wallet.v.community", &community])?);

in_and_cond_doc.get_array_mut("$and")?.push(
doc! {
"$gt": [{ "$size": "$$entries" }, 0]
}
.into(),
);
}

if from.is_some() || to.is_some() {
if let Some(from) = from {
in_and_cond_doc.get_array_mut("$and")?.push(
doc! {
"$gte": ["$$timestamp", bson::to_bson(&from)?]
}
.into(),
);
}

if let Some(to) = to {
in_and_cond_doc.get_array_mut("$and")?.push(
doc! {
"$lte": ["$$timestamp", bson::to_bson(&to)?]
}
.into(),
);
}
}

let expr = self.build_rewards_filter_expr(from, to, community)?;
let filter = doc! {
"$expr":{
"$let":{
"vars":{
"entries":{
"$filter":{
"input":{
"$objectToArray":"$wallets"
},
"as":"wallet",
"cond": cond
}
}
},
"in":{
"$let": {
"vars": {
"timestamp":{
"$arrayElemAt":[{
"$map":{
"input":"$$entries",
"as":"entry",
"in":"$$entry.v.timestamp"
}
},0]
}
},
"in": in_and_cond_doc
}
}
}
}
"$expr": expr
};

let find_options = FindOptions::builder()
Expand Down Expand Up @@ -250,7 +220,48 @@ impl RewardsManager {
})
}

/// Searches for multiple user profiles within MongoDB by provided EVM-like address [`Address`] list and returns [`Vec<UserProfile>`]
/// Counts rewards allocated for user within MongoDB by provided wallet EVM-like address [`Address`]
pub async fn count_rewards_by_wallet(
&self,
requestor: &Address,
wallet: &Address,
from: Option<u64>,
to: Option<u64>,
community: Option<&str>,
) -> Result<u64, error::Error> {
let requires_moderator_access_rights = wallet != requestor;

if requires_moderator_access_rights
&& !self
.config
.moderators
.iter()
.any(|wallet| wallet == requestor)
{
return Err(error::Error::Unauthorized);
}

let expr = self.build_rewards_filter_expr(from, to, community)?;
let filter = doc! {
format!("wallets.0x{}", hex::encode(wallet)): { "$exists": true },
"$expr": bson::to_bson(&expr)?,
};

let res = tokio::time::timeout(
self.db_client.req_timeout,
self.db_client
.collection()
.count(filter, CountOptions::default()),
)
.await?
.map_err(error::Error::from);

tracing::debug!("Count total rewards by wallet ({wallet:?}) result: {res:?}");

res
}

/// Searches rewards allocated for user within MongoDB by provided wallet EVM-like address [`Address`] and returns [`Vec<Rewards>`]
#[allow(clippy::too_many_arguments)]
pub async fn get_rewards_by_wallet(
&self,
Expand All @@ -260,7 +271,7 @@ impl RewardsManager {
limit: Option<u64>,
from: Option<u64>,
to: Option<u64>,
community: Option<String>,
community: Option<&str>,
) -> Result<Vec<Rewards>, error::Error> {
let start = start.unwrap_or_default();
let limit = limit
Expand All @@ -279,76 +290,10 @@ impl RewardsManager {
return Err(error::Error::Unauthorized);
}

let mut in_and_cond_doc = doc! {
"$and": []
};

let mut cond = doc! {};

if let Some(community) = community {
cond.insert("$eq", bson::to_bson(&["$$wallet.v.community", &community])?);

in_and_cond_doc.get_array_mut("$and")?.push(
doc! {
"$gt": [{ "$size": "$$entries" }, 0]
}
.into(),
);
}

if from.is_some() || to.is_some() {
if let Some(from) = from {
in_and_cond_doc.get_array_mut("$and")?.push(
doc! {
"$gte": ["$$timestamp", bson::to_bson(&from)?]
}
.into(),
);
}

if let Some(to) = to {
in_and_cond_doc.get_array_mut("$and")?.push(
doc! {
"$lt": ["$$timestamp", bson::to_bson(&to)?]
}
.into(),
);
}
}

let expr = self.build_rewards_filter_expr(from, to, community)?;
let filter = doc! {
format!("wallets.0x{}", hex::encode(wallet)): { "$exists": true },
"$expr":{
"$let":{
"vars":{
"entries":{
"$filter":{
"input":{
"$objectToArray":"$wallets"
},
"as":"wallet",
"cond": cond
}
}
},
"in":{
"$let": {
"vars": {
"timestamp":{
"$arrayElemAt":[{
"$map":{
"input":"$$entries",
"as":"entry",
"in":"$$entry.v.timestamp"
}
},0]
}
},
"in": in_and_cond_doc
}
}
}
}
"$expr": bson::to_bson(&expr)?,
};

let find_options = FindOptions::builder()
Expand Down Expand Up @@ -406,4 +351,80 @@ impl RewardsManager {
.collect()
})
}

fn build_rewards_filter_expr(
&self,
from: Option<u64>,
to: Option<u64>,
community: Option<&str>,
) -> Result<Document, error::Error> {
let mut in_and_cond_doc = doc! {
"$and": []
};

let mut cond = doc! {};

if let Some(community) = community {
cond.insert("$eq", bson::to_bson(&["$$wallet.v.community", community])?);

in_and_cond_doc.get_array_mut("$and")?.push(
doc! {
"$gt": [{ "$size": "$$entries" }, 0]
}
.into(),
);
}

if from.is_some() || to.is_some() {
if let Some(from) = from {
in_and_cond_doc.get_array_mut("$and")?.push(
doc! {
"$gte": ["$$timestamp", bson::to_bson(&from)?]
}
.into(),
);
}

if let Some(to) = to {
in_and_cond_doc.get_array_mut("$and")?.push(
doc! {
"$lt": ["$$timestamp", bson::to_bson(&to)?]
}
.into(),
);
}
}

Ok(doc! {
"$let":{
"vars":{
"entries":{
"$filter":{
"input":{
"$objectToArray":"$wallets"
},
"as":"wallet",
"cond": cond
}
}
},
"in":{
"$let": {
"vars": {
"timestamp":{
"$arrayElemAt":[{
"$map":{
"input":"$$entries",
"as":"entry",
"in":"$$entry.v.timestamp"
}
},0]
}
},
"in": in_and_cond_doc
}
}
}
})
}
}
Loading

0 comments on commit 3a2a023

Please sign in to comment.