Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/labrinth/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
- Use `ApiError` as the error type for API routes
- Always use `cargo clippy` instead of `cargo check`
- The return type of an HTTP route should not be `HttpResponse` if possible; always prefer more specific types
- Use `web::Json<T>` for JSON-encoded response
- Use `()` for no content
Expand Down
4 changes: 2 additions & 2 deletions apps/labrinth/src/auth/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ pub async fn filter_visible_version_ids(
let visible_project_ids = filter_visible_project_ids(
DBProject::get_many_ids(&project_ids, pool, redis)
.await
.wrap_api_err("fetching projects for visibility filtering")?
.wrap_internal_err("fetching projects for visibility filtering")?
.iter()
.map(|x| &x.inner)
.collect(),
Expand Down Expand Up @@ -355,7 +355,7 @@ pub async fn filter_enlisted_version_ids(
let authorized_project_ids = filter_enlisted_projects_ids(
DBProject::get_many_ids(&project_ids, pool, redis)
.await
.wrap_api_err("fetching projects for membership filtering")?
.wrap_internal_err("fetching projects for membership filtering")?
.iter()
.map(|x| &x.inner)
.collect(),
Expand Down
6 changes: 0 additions & 6 deletions apps/labrinth/src/auth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ pub enum AuthenticationError {
Internal(#[from] eyre::Report),
#[error("An unknown database error occurred: {0}")]
Sqlx(#[from] sqlx::Error),
#[error("Database Error: {0}")]
Database(#[from] crate::database::models::DatabaseError),
#[error("Error while parsing JSON: {0}")]
SerDe(#[from] serde_json::Error),
#[error("Error while communicating to external provider")]
Expand Down Expand Up @@ -66,9 +64,6 @@ impl actix_web::ResponseError for AuthenticationError {
StatusCode::INTERNAL_SERVER_ERROR
}
AuthenticationError::Sqlx(..) => StatusCode::INTERNAL_SERVER_ERROR,
AuthenticationError::Database(..) => {
StatusCode::INTERNAL_SERVER_ERROR
}
AuthenticationError::SerDe(..) => StatusCode::BAD_REQUEST,
AuthenticationError::Reqwest(..) => {
StatusCode::INTERNAL_SERVER_ERROR
Expand Down Expand Up @@ -105,7 +100,6 @@ impl AuthenticationError {
match self {
AuthenticationError::Internal(..) => "internal_error",
AuthenticationError::Sqlx(..) => "database_error",
AuthenticationError::Database(..) => "database_error",
AuthenticationError::SerDe(..) => "invalid_input",
AuthenticationError::Reqwest(..) => "network_error",
AuthenticationError::InvalidCredentials => "invalid_credentials",
Expand Down
4 changes: 2 additions & 2 deletions apps/labrinth/src/auth/oauth/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ pub enum OAuthErrorType {
AccessDenied,
}

impl From<crate::database::models::DatabaseError> for OAuthErrorType {
fn from(value: crate::database::models::DatabaseError) -> Self {
impl From<eyre::Report> for OAuthErrorType {
fn from(value: eyre::Report) -> Self {
OAuthErrorType::AuthenticationError(value.into())
}
}
Expand Down
4 changes: 2 additions & 2 deletions apps/labrinth/src/background_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,8 @@ mod version_updater {
pub enum VersionIndexingError {
#[error("Network error while updating game versions list: {0}")]
NetworkError(#[from] reqwest::Error),
#[error("Database error while updating game versions list: {0}")]
DatabaseError(#[from] crate::database::models::DatabaseError),
#[error("internal error while updating game versions list: {0}")]
InternalError(#[from] eyre::Report),
}

pub async fn update_versions(
Expand Down
41 changes: 24 additions & 17 deletions apps/labrinth/src/database/models/affiliate_code_item.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use chrono::{DateTime, Utc};
use eyre::{Result, WrapErr};
use futures::{StreamExt, TryStreamExt};

use crate::database::models::{DBAffiliateCodeId, DBUserId, DatabaseError};
use crate::database::models::{DBAffiliateCodeId, DBUserId};

#[derive(Debug)]
pub struct DBAffiliateCode {
Expand All @@ -16,14 +17,15 @@ impl DBAffiliateCode {
pub async fn get_by_id(
id: DBAffiliateCodeId,
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Option<DBAffiliateCode>, DatabaseError> {
) -> Result<Option<DBAffiliateCode>> {
let record = sqlx::query!(
"SELECT id, created_at, created_by, affiliate, source_name
FROM affiliate_codes WHERE id = $1",
id as DBAffiliateCodeId
)
.fetch_optional(exec)
.await?;
.await
.wrap_err("fetching affiliate code by id")?;

Ok(record.map(|record| DBAffiliateCode {
id: DBAffiliateCodeId(record.id),
Expand All @@ -37,16 +39,16 @@ impl DBAffiliateCode {
pub async fn get_by_affiliate(
affiliate: DBUserId,
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Vec<DBAffiliateCode>, DatabaseError> {
) -> Result<Vec<DBAffiliateCode>> {
let records = sqlx::query!(
"SELECT id, created_at, created_by, affiliate, source_name
FROM affiliate_codes WHERE affiliate = $1",
affiliate as DBUserId
)
.fetch(exec)
.map(|record| {
let record = record?;
Ok::<_, DatabaseError>(DBAffiliateCode {
let record = record.wrap_err("reading affiliate code record")?;
eyre::Ok(DBAffiliateCode {
id: DBAffiliateCodeId(record.id),
created_at: record.created_at,
created_by: DBUserId(record.created_by),
Expand All @@ -55,15 +57,16 @@ impl DBAffiliateCode {
})
})
.try_collect::<Vec<_>>()
.await?;
.await
.wrap_err("fetching affiliate codes by affiliate")?;

Ok(records)
}

pub async fn insert(
&self,
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
) -> Result<(), DatabaseError> {
) -> Result<()> {
sqlx::query!(
"INSERT INTO affiliate_codes (id, created_at, created_by, affiliate, source_name)
VALUES ($1, $2, $3, $4, $5)",
Expand All @@ -74,20 +77,22 @@ impl DBAffiliateCode {
self.source_name
)
.execute(exec)
.await?;
.await
.wrap_err("inserting affiliate code")?;
Ok(())
}

pub async fn remove(
id: DBAffiliateCodeId,
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Option<()>, DatabaseError> {
) -> Result<Option<()>> {
let result = sqlx::query!(
"DELETE FROM affiliate_codes WHERE id = $1",
id as DBAffiliateCodeId
)
.execute(exec)
.await?;
.await
.wrap_err("removing affiliate code")?;

if result.rows_affected() > 0 {
Ok(Some(()))
Expand All @@ -100,29 +105,30 @@ impl DBAffiliateCode {
id: DBAffiliateCodeId,
source_name: &str,
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
) -> Result<bool, DatabaseError> {
) -> Result<bool> {
let result = sqlx::query!(
"UPDATE affiliate_codes SET source_name = $1 WHERE id = $2",
source_name,
id as DBAffiliateCodeId
)
.execute(exec)
.await?;
.await
.wrap_err("updating affiliate code source name")?;

Ok(result.rows_affected() > 0)
}

pub async fn get_all(
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
) -> Result<Vec<DBAffiliateCode>, DatabaseError> {
) -> Result<Vec<DBAffiliateCode>> {
let records = sqlx::query!(
"SELECT id, created_at, created_by, affiliate, source_name
FROM affiliate_codes ORDER BY created_at DESC"
)
.fetch(exec)
.map(|record| {
let record = record?;
Ok::<_, DatabaseError>(DBAffiliateCode {
let record = record.wrap_err("reading affiliate code record")?;
eyre::Ok(DBAffiliateCode {
id: DBAffiliateCodeId(record.id),
created_at: record.created_at,
created_by: DBUserId(record.created_by),
Expand All @@ -131,7 +137,8 @@ impl DBAffiliateCode {
})
})
.try_collect::<Vec<_>>()
.await?;
.await
.wrap_err("fetching all affiliate codes")?;

Ok(records)
}
Expand Down
55 changes: 38 additions & 17 deletions apps/labrinth/src/database/models/analytics_event_item.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use chrono::{DateTime, Utc};
use eyre::{Result, WrapErr};
use futures::{StreamExt, TryStreamExt};
use sqlx::types::Json;
use xredis::RedisPool;

use crate::{
database::models::{DBAnalyticsEventId, DatabaseError},
database::models::DBAnalyticsEventId,
models::v3::analytics_event::AnalyticsEventMeta,
};
use serde::{Deserialize, Serialize};
Expand All @@ -24,7 +25,7 @@ impl DBAnalyticsEvent {
pub async fn insert(
&self,
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
) -> Result<(), DatabaseError> {
) -> Result<()> {
sqlx::query!(
"
INSERT INTO analytics_events (id, meta, starts, ends)
Expand All @@ -36,15 +37,16 @@ impl DBAnalyticsEvent {
self.ends,
)
.execute(exec)
.await?;
.await
.wrap_err("inserting analytics event")?;

Ok(())
}

pub async fn update(
&self,
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
) -> Result<bool, DatabaseError> {
) -> Result<bool> {
let result = sqlx::query!(
"
UPDATE analytics_events
Expand All @@ -57,15 +59,16 @@ impl DBAnalyticsEvent {
self.ends,
)
.execute(exec)
.await?;
.await
.wrap_err("updating analytics event")?;

Ok(result.rows_affected() > 0)
}

pub async fn remove(
id: DBAnalyticsEventId,
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
) -> Result<bool, DatabaseError> {
) -> Result<bool> {
let result = sqlx::query!(
"
DELETE FROM analytics_events
Expand All @@ -74,21 +77,29 @@ impl DBAnalyticsEvent {
id as DBAnalyticsEventId,
)
.execute(exec)
.await?;
.await
.wrap_err("removing analytics event")?;

Ok(result.rows_affected() > 0)
}

pub async fn get_all(
exec: impl crate::database::Executor<'_, Database = sqlx::Postgres>,
redis: &RedisPool,
) -> Result<Vec<DBAnalyticsEvent>, DatabaseError> {
let mut redis = redis.connect().await?;
) -> Result<Vec<DBAnalyticsEvent>> {
let mut redis = redis
.connect()
.await
.wrap_err("connecting to redis for analytics events")?;
let key = redis
.key()
.metadata(ANALYTICS_EVENTS_NAMESPACE, ANALYTICS_EVENTS_ALL_KEY);

if let Some(events) = redis.get_deserialized(&key).await? {
if let Some(events) = redis
.get_deserialized(&key)
.await
.wrap_err("getting cached analytics events")?
{
return Ok(events);
}

Expand All @@ -101,29 +112,39 @@ impl DBAnalyticsEvent {
)
.fetch(exec)
.map(|record| {
let record = record?;
let record = record.wrap_err("reading analytics event record")?;

Ok::<_, DatabaseError>(DBAnalyticsEvent {
eyre::Ok(DBAnalyticsEvent {
id: DBAnalyticsEventId(record.id),
meta: record.meta.0,
starts: record.starts,
ends: record.ends,
})
})
.try_collect::<Vec<_>>()
.await?;
.await
.wrap_err("fetching analytics events from database")?;

redis.set_serialized(&key, &events, None).await?;
redis
.set_serialized(&key, &events, None)
.await
.wrap_err("caching analytics events")?;

Ok(events)
}

pub async fn clear_cache(redis: &RedisPool) -> Result<(), DatabaseError> {
let mut redis = redis.connect().await?;
pub async fn clear_cache(redis: &RedisPool) -> Result<()> {
let mut redis = redis
.connect()
.await
.wrap_err("connecting to redis to clear analytics event cache")?;
let key = redis
.key()
.metadata(ANALYTICS_EVENTS_NAMESPACE, ANALYTICS_EVENTS_ALL_KEY);
redis.delete(&key).await?;
redis
.delete(&key)
.await
.wrap_err("clearing analytics event cache")?;
Ok(())
}
}
Loading
Loading