Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serverside hidden activities #112

Merged
merged 11 commits into from
May 28, 2024
Prev Previous commit
Next Next commit
remove LazyLock and remove clones
DrVilepis committed May 28, 2024

Verified

This commit was signed with the committer’s verified signature.
DrVilepis Ville Järvinen
commit 3d2e127a503e50080f61095051de5639be669f4f
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -42,5 +42,5 @@ url = "2.2"

itertools = "0.10.3"
governor = "0.6.0"
diesel = { version = "2.1.0", features = ["chrono", "serde_json"] }
diesel = { version = "2.1.0", features = ["chrono", "serde_json", "postgres_backend"] }
diesel-async = { version = "0.4.1", features = ["postgres", "deadpool"] }
6 changes: 2 additions & 4 deletions src/api/activity.rs
Original file line number Diff line number Diff line change
@@ -173,9 +173,7 @@ pub async fn rename_project(
db: DatabaseWrapper,
body: Json<RenameRequest>,
) -> Result<impl Responder, TimeError> {
let renamed = db
.rename_project(user.id, body.from.clone(), body.to.clone())
.await?;
let renamed = db.rename_project(user.id, &body.from, &body.to).await?;

Ok(web::Json(json!({ "affected_activities": renamed })))
}
@@ -187,7 +185,7 @@ pub async fn hide_project(
body: Json<HideRequest>,
) -> Result<impl Responder, TimeError> {
let renamed = db
.set_project_hidden(user.id, body.target_project.clone(), body.hidden.clone())
.set_project_hidden(user.id, &body.target_project, body.hidden)
.await?;

Ok(web::Json(json!({ "affected_activities": renamed })))
12 changes: 5 additions & 7 deletions src/api/auth.rs
Original file line number Diff line number Diff line change
@@ -158,12 +158,11 @@ pub async fn register(
"Password has to be between 8 and 128 characters long".to_string(),
));
}
if !super::VALID_NAME_REGEX.is_match(&data.username) {
if !super::REGEX.with(|r| r.is_match(&data.username)) {
return Err(TimeError::BadUsername);
}

let username = data.username.clone();
if db.get_user_by_name(username).await.is_ok() {
if db.get_user_by_name(&data.username).await.is_ok() {
return Err(TimeError::UserExists);
}

@@ -206,17 +205,16 @@ pub async fn changeusername(
"Username is not between 2 and 32 chars".to_string(),
));
}
if !super::VALID_NAME_REGEX.is_match(&data.new) {
if !super::REGEX.with(|r| r.is_match(&data.new)) {
return Err(TimeError::BadUsername);
}

let username = data.new.clone();
if db.get_user_by_name(username).await.is_ok() {
if db.get_user_by_name(&data.new).await.is_ok() {
return Err(TimeError::UserExists);
}

let user = db.get_user_by_id(user.identity.id).await?;
db.change_username(user.id, data.new.clone()).await?;
db.change_username(user.id, &data.new).await?;
Ok(HttpResponse::Ok().finish())
}

2 changes: 1 addition & 1 deletion src/api/friends.rs
Original file line number Diff line number Diff line change
@@ -106,7 +106,7 @@ pub async fn remove(
db: DatabaseWrapper,
body: String,
) -> Result<impl Responder, TimeError> {
let friend = db.get_user_by_name(body.clone()).await?;
let friend = db.get_user_by_name(&body).await?;
let deleted = db.remove_friend(user.identity.id, friend.id).await?;

if deleted {
34 changes: 15 additions & 19 deletions src/api/leaderboards.rs
Original file line number Diff line number Diff line change
@@ -31,12 +31,11 @@ pub async fn create_leaderboard(
body: Json<LeaderboardName>,
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
if !super::VALID_NAME_REGEX.is_match(&body.name) {
if !super::REGEX.with(|r| r.is_match(&body.name)) {
return Err(TimeError::BadLeaderboardName);
}
let lname = body.name.clone();

if db.get_leaderboard_id_by_name(lname).await.is_ok() {
if db.get_leaderboard_id_by_name(&body.name).await.is_ok() {
return Err(TimeError::LeaderboardExists);
}

@@ -62,12 +61,12 @@ pub async fn get_leaderboard(
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.get_leaderboard_id_by_name(&path.0)
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_member(user.id, lid).await? {
let board = db.get_leaderboard(path.0.clone()).await?;
let board = db.get_leaderboard(&path.0).await?;
Ok(web::Json(board))
} else {
Err(TimeError::Unauthorized)
@@ -81,12 +80,12 @@ pub async fn delete_leaderboard(
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.get_leaderboard_id_by_name(&path.0)
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_admin(user.identity.id, lid).await? {
db.delete_leaderboard(path.0.clone()).await?;
db.delete_leaderboard(&path.0).await?;
Ok(HttpResponse::Ok().finish())
} else {
Err(TimeError::Unauthorized)
@@ -100,10 +99,7 @@ pub async fn join_leaderboard(
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
match db
.add_user_to_leaderboard(
user.id,
body.invite.trim().trim_start_matches("ttlic_").to_string(),
)
.add_user_to_leaderboard(user.id, body.invite.trim().trim_start_matches("ttlic_"))
.await
{
Err(e) => {
@@ -130,7 +126,7 @@ pub async fn leave_leaderboard(
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.get_leaderboard_id_by_name(&path.0)
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

@@ -158,13 +154,13 @@ pub async fn promote_member(
promotion: Json<LeaderboardUser>,
) -> Result<impl Responder, TimeError> {
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.get_leaderboard_id_by_name(&path.0)
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_admin(user.identity.id, lid).await? {
let newadmin = db
.get_user_by_name(promotion.user.clone())
.get_user_by_name(&promotion.user)
.await
.map_err(|_| TimeError::UserNotFound)?;

@@ -190,13 +186,13 @@ pub async fn demote_member(
demotion: Json<LeaderboardUser>,
) -> Result<impl Responder, TimeError> {
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.get_leaderboard_id_by_name(&path.0)
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_admin(user.identity.id, lid).await? {
let oldadmin = db
.get_user_by_name(demotion.user.clone())
.get_user_by_name(&demotion.user)
.await
.map_err(|_| TimeError::UserNotFound)?;

@@ -222,13 +218,13 @@ pub async fn kick_member(
kick: Json<LeaderboardUser>,
) -> Result<impl Responder, TimeError> {
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.get_leaderboard_id_by_name(&path.0)
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

if db.is_leaderboard_admin(user.identity.id, lid).await? {
let kmember = db
.get_user_by_name(kick.user.clone())
.get_user_by_name(&kick.user)
.await
.map_err(|_| TimeError::UserNotFound)?;

@@ -248,7 +244,7 @@ pub async fn regenerate_invite(
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
let lid = db
.get_leaderboard_id_by_name(path.0.clone())
.get_leaderboard_id_by_name(&path.0)
.await
.map_err(|_| TimeError::LeaderboardNotFound)?;

7 changes: 3 additions & 4 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::sync::LazyLock;

use actix_web::{HttpResponse, Responder};
use regex::Regex;

@@ -14,8 +12,9 @@ pub mod search;
pub mod stats;
pub mod users;

static VALID_NAME_REGEX: LazyLock<Regex> =
LazyLock::new(|| Regex::new("^[[:word:]]{2,32}$").unwrap());
thread_local! {
pub static REGEX: Regex = Regex::new("^[[:word:]]{2,32}$").unwrap();
}

#[get("/health")]
async fn health() -> impl Responder {
25 changes: 11 additions & 14 deletions src/api/oauth.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, sync::LazyLock};
use std::collections::HashMap;

use actix_web::{
cookie::Cookie,
@@ -21,13 +21,14 @@ struct TokenResponse {
token: String,
}

#[derive(Deserialize)]
struct ClientInfo {
#[cfg(feature = "testausid")]
#[derive(Debug, Deserialize, Clone)]
pub struct ClientInfo {
#[serde(rename = "client_id")]
id: String,
pub id: String,
#[serde(rename = "client_secret")]
secret: String,
redirect_uri: String,
pub secret: String,
pub redirect_uri: String,
}

#[derive(Deserialize, Debug)]
@@ -42,15 +43,11 @@ struct TestausIdPlatformInfo {
id: String,
}

static CLIENT_INFO: LazyLock<ClientInfo> = LazyLock::new(|| {
toml::from_str(&std::fs::read_to_string("settings.toml").expect("Missing settings.toml"))
.expect("Invalid Toml in settings.toml")
});

#[get("/auth/callback")]
async fn callback(
request: Query<TokenExchangeRequest>,
client: Data<Client>,
oauth_client: Data<ClientInfo>,
db: DatabaseWrapper,
) -> Result<impl Responder, TimeError> {
if request.code.chars().any(|c| !c.is_alphanumeric()) {
@@ -62,9 +59,9 @@ async fn callback(
.insert_header(("content-type", "application/x-www-form-urlencoded"))
.send_form(&HashMap::from([
("code", &request.code),
("redirect_uri", &CLIENT_INFO.redirect_uri),
("client_id", &CLIENT_INFO.id),
("client_secret", &CLIENT_INFO.secret),
("redirect_uri", &oauth_client.redirect_uri),
("client_id", &oauth_client.id),
("client_secret", &oauth_client.secret),
]))
.await
.unwrap()
12 changes: 6 additions & 6 deletions src/api/users.rs
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ pub async fn get_current_activity(
user.id
} else {
let target_user = db
.get_user_by_name(path.0.clone())
.get_user_by_name(&path.0)
.await
.map_err(|_| TimeError::UserNotFound)?;

@@ -95,7 +95,7 @@ pub async fn get_current_activity(
}
} else {
let target_user = db
.get_user_by_name(path.0.clone())
.get_user_by_name(&path.0)
.await
.map_err(|_| TimeError::UserNotFound)?;

@@ -145,7 +145,7 @@ pub async fn get_activities(
) -> Result<impl Responder, TimeError> {
let Some(user) = opt_user.identity else {
let target_user = db
.get_user_by_name(path.0.clone())
.get_user_by_name(&path.0)
.await
.map_err(|_| TimeError::UserNotFound)?;

@@ -164,7 +164,7 @@ pub async fn get_activities(
//FIXME: This is technically not required when the username equals the username of the
//authenticated user
let target_user = db
.get_user_by_name(path.0.clone())
.get_user_by_name(&path.0)
.await
.map_err(|_| TimeError::UserNotFound)?;

@@ -193,7 +193,7 @@ pub async fn get_activity_summary(
db.get_all_activity(user.id).await?
} else {
let target_user = db
.get_user_by_name(path.0.clone())
.get_user_by_name(&path.0)
.await
.map_err(|_| TimeError::UserNotFound)?;

@@ -208,7 +208,7 @@ pub async fn get_activity_summary(
}
} else {
let target_user = db
.get_user_by_name(path.0.clone())
.get_user_by_name(&path.0)
.await
.map_err(|_| TimeError::UserNotFound)?;

25 changes: 8 additions & 17 deletions src/database/activity.rs
Original file line number Diff line number Diff line change
@@ -98,14 +98,14 @@ impl super::DatabaseWrapper {
pub async fn get_user_coding_time_since(
&self,
uid: i32,
since: chrono::NaiveDateTime,
since: chrono::DateTime<Local>,
) -> Result<i32, TimeError> {
let mut conn = self.db.get().await?;

use crate::schema::coding_activities::dsl::*;

Ok(coding_activities
.filter(user_id.eq(uid).and(start_time.ge(since)))
.filter(user_id.eq(uid).and(start_time.ge(since.naive_local())))
.select(diesel::dsl::sum(duration))
.first::<Option<i64>>(&mut conn)
.await?
@@ -115,24 +115,15 @@ impl super::DatabaseWrapper {
pub async fn get_coding_time_steps(&self, uid: i32) -> CodingTimeSteps {
CodingTimeSteps {
all_time: self
.get_user_coding_time_since(
uid,
chrono::NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
)
.get_user_coding_time_since(uid, chrono::DateTime::default())
.await
.unwrap_or(0),
past_month: self
.get_user_coding_time_since(
uid,
chrono::Local::now().naive_local() - chrono::Duration::days(30),
)
.get_user_coding_time_since(uid, chrono::Local::now() - chrono::Duration::days(30))
.await
.unwrap_or(0),
past_week: self
.get_user_coding_time_since(
uid,
chrono::Local::now().naive_local() - chrono::Duration::days(7),
)
.get_user_coding_time_since(uid, chrono::Local::now() - chrono::Duration::days(7))
.await
.unwrap_or(0),
}
@@ -141,8 +132,8 @@ impl super::DatabaseWrapper {
pub async fn rename_project(
&self,
target_user_id: i32,
from: String,
to: String,
from: &str,
to: &str,
) -> Result<usize, TimeError> {
let mut conn = self.db.get().await?;

@@ -158,7 +149,7 @@ impl super::DatabaseWrapper {
pub async fn set_project_hidden(
&self,
target_user_id: i32,
target_project: String,
target_project: &str,
to: bool,
) -> Result<usize, TimeError> {
let mut conn = self.db.get().await?;
Loading