Skip to content

Commit

Permalink
Cannot add problem to another contest if problem has been in contest …
Browse files Browse the repository at this point in the history
…that deleted (#66)

* Fix bug children's foreign key not deleted

* chore remove idea warning

* Fix typo
  • Loading branch information
Eason0729 authored Aug 22, 2024
1 parent a499cf3 commit c341b6c
Show file tree
Hide file tree
Showing 31 changed files with 177 additions and 158 deletions.
6 changes: 3 additions & 3 deletions backend/src/endpoint/announcement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl Announcement for ArcServer {

let id = *model.id.as_ref();

tracing::info!(count.announcement = 1, id = id);
info!(count.announcement = 1, id = id);

Ok(id.into())
})
Expand All @@ -197,7 +197,7 @@ impl Announcement for ArcServer {
req.bound_check()?;

req.get_or_insert(|req| async move {
tracing::trace!(id = req.id);
trace!(id = req.id);

let mut model = Entity::find_by_id(req.id)
.with_auth(&auth)
Expand Down Expand Up @@ -242,7 +242,7 @@ impl Announcement for ArcServer {
if result.rows_affected == 0 {
Err(Error::NotInDB)
} else {
tracing::info!(counter.announcement = -1, id = req.id);
info!(counter.announcement = -1, id = req.id);
Ok(())
}
})
Expand Down
4 changes: 2 additions & 2 deletions backend/src/endpoint/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Chat for ArcServer {
.map_err(Into::<Error>::into)?;

let id = *model.id.as_ref();
tracing::debug!(id = id, "chat_created");
debug!(id = id, "chat_created");

Ok(id.into())
})
Expand Down Expand Up @@ -80,7 +80,7 @@ impl Chat for ArcServer {
if result.rows_affected == 0 {
Err(Error::NotInDB)
} else {
tracing::info!(counter.chat = -1, id = req.id);
info!(counter.chat = -1, id = req.id);
Ok(())
}
})
Expand Down
114 changes: 62 additions & 52 deletions backend/src/endpoint/contest.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use super::*;

use crate::entity::{
contest::{Paginator, *},
*,
problem, *,
};
use sea_orm::sea_query::Expr;

use grpc::backend::contest_server::*;

Expand Down Expand Up @@ -164,7 +164,7 @@ impl Contest for ArcServer {

let id = *model.id.as_ref();

tracing::info!(count.contest = 1, id = id);
info!(count.contest = 1, id = id);

Ok(id.into())
})
Expand All @@ -185,7 +185,7 @@ impl Contest for ArcServer {
let (_, perm) = auth.assume_login()?;

req.get_or_insert(|req| async move {
tracing::trace!(id = req.id);
trace!(id = req.id);

let mut model = Entity::find_by_id(req.id).with_auth(&auth).write()?
.one(self.db.deref())
Expand Down Expand Up @@ -238,6 +238,8 @@ impl Contest for ArcServer {
let (auth, req) = self.rate_limit(req).in_current_span().await?;

req.get_or_insert(|req| async move {
let txn = self.db.begin().await?;

let result = Entity::delete_by_id(req.id)
.with_auth(&auth)
.write()?
Expand All @@ -246,12 +248,20 @@ impl Contest for ArcServer {
.await
.map_err(Into::<Error>::into)?;

problem::Entity::update_many()
.col_expr(problem::Column::ContestId, Expr::value(Value::Int(None)))
.filter(crate::entity::testcase::Column::ProblemId.eq(req.id))
.exec(&txn)
.instrument(info_span!("remove_child"))
.await?;

txn.commit().await.map_err(|_| Error::Retry)?;

if result.rows_affected == 0 {
Err(Error::NotInDB)
} else {
tracing::info!(counter.contest = -1, id = req.id);
Ok(())
return Err(Error::NotInDB);
}
info!(counter.contest = -1, id = req.id);
Ok(())
})
.await
.with_grpc()
Expand All @@ -260,47 +270,30 @@ impl Contest for ArcServer {
#[instrument(
skip_all,
level = "info",
name = "oj.backend.Contest/join",
name = "oj.backend.Contest/publish",
err(level = "debug", Display)
)]
async fn join(&self, req: Request<JoinContestRequest>) -> Result<Response<()>, Status> {
async fn publish(&self, req: Request<PublishRequest>) -> Result<Response<()>, Status> {
let (auth, req) = self.rate_limit(req).in_current_span().await?;
let (user_id, _) = auth.assume_login()?;

req.get_or_insert(|req| async move {
let model = Entity::find_by_id(req.id)
let mut model = Entity::find_by_id(req.id)
.with_auth(&auth)
.read()?
.write()?
.columns([Column::Id])
.one(self.db.deref())
.instrument(info_span!("fetch").or_current())
.await
.map_err(Into::<Error>::into)?
.ok_or(Error::NotInDB)?;
// FIXME: abstract away password checking logic

if let Some(tar) = model.password {
let password = req
.password
.as_ref()
.ok_or(Error::NotInPayload("password"))?;
if !self.crypto.hash_eq(password, &tar) {
return Err(Error::PermissionDeny("mismatched password"));
}
}

let pivot = user_contest::ActiveModel {
user_id: ActiveValue::Set(user_id),
contest_id: ActiveValue::Set(model.id),
..Default::default()
};
.ok_or(Error::NotInDB)?
.into_active_model();

pivot
.save(self.db.deref())
.instrument(info_span!("insert_pviot").or_current())
.await
.map_err(Into::<Error>::into)?;
model.public = ActiveValue::Set(true);

tracing::debug!(user_id = user_id, contest_id = req.id);
model
.update(self.db.deref())
.instrument(info_span!("update").or_current())
.await?;
Ok(())
})
.await
Expand All @@ -310,10 +303,10 @@ impl Contest for ArcServer {
#[instrument(
skip_all,
level = "info",
name = "oj.backend.Contest/publish",
name = "oj.backend.Contest/unpublish",
err(level = "debug", Display)
)]
async fn publish(&self, req: Request<PublishRequest>) -> Result<Response<()>, Status> {
async fn unpublish(&self, req: Request<PublishRequest>) -> Result<Response<()>, Status> {
let (auth, req) = self.rate_limit(req).in_current_span().await?;

req.get_or_insert(|req| async move {
Expand All @@ -328,7 +321,7 @@ impl Contest for ArcServer {
.ok_or(Error::NotInDB)?
.into_active_model();

model.public = ActiveValue::Set(true);
model.public = ActiveValue::Set(false);

model
.update(self.db.deref())
Expand All @@ -343,30 +336,47 @@ impl Contest for ArcServer {
#[instrument(
skip_all,
level = "info",
name = "oj.backend.Contest/unpublish",
name = "oj.backend.Contest/join",
err(level = "debug", Display)
)]
async fn unpublish(&self, req: Request<PublishRequest>) -> Result<Response<()>, Status> {
async fn join(&self, req: Request<JoinContestRequest>) -> Result<Response<()>, Status> {
let (auth, req) = self.rate_limit(req).in_current_span().await?;
let (user_id, _) = auth.assume_login()?;

req.get_or_insert(|req| async move {
let mut model = Entity::find_by_id(req.id)
let model = Entity::find_by_id(req.id)
.with_auth(&auth)
.write()?
.columns([Column::Id])
.read()?
.one(self.db.deref())
.instrument(info_span!("fetch").or_current())
.await
.map_err(Into::<Error>::into)?
.ok_or(Error::NotInDB)?
.into_active_model();
.ok_or(Error::NotInDB)?;
// FIXME: abstract away password checking logic

model.public = ActiveValue::Set(false);
if let Some(tar) = model.password {
let password = req
.password
.as_ref()
.ok_or(Error::NotInPayload("password"))?;
if !self.crypto.hash_eq(password, &tar) {
return Err(Error::PermissionDeny("mismatched password"));
}
}

model
.update(self.db.deref())
.instrument(info_span!("update").or_current())
.await?;
let pivot = user_contest::ActiveModel {
user_id: ActiveValue::Set(user_id),
contest_id: ActiveValue::Set(model.id),
..Default::default()
};

pivot
.save(self.db.deref())
.instrument(info_span!("insert_pviot").or_current())
.await
.map_err(Into::<Error>::into)?;

debug!(user_id = user_id, contest_id = req.id);
Ok(())
})
.await
Expand Down
6 changes: 3 additions & 3 deletions backend/src/endpoint/education.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl Education for ArcServer {

let id = *model.id.as_ref();

tracing::info!(count.education = 1, id = id);
info!(count.education = 1, id = id);

Ok(id.into())
})
Expand All @@ -123,7 +123,7 @@ impl Education for ArcServer {
req.bound_check()?;

req.get_or_insert(|req| async move {
tracing::trace!(id = req.id);
trace!(id = req.id);
let mut model = Entity::find_by_id(req.id)
.with_auth(&auth)
.write()?
Expand Down Expand Up @@ -167,7 +167,7 @@ impl Education for ArcServer {
if result.rows_affected == 0 {
Err(Error::NotInDB)
} else {
tracing::info!(counter.education = -1, id = req.id);
info!(counter.education = -1, id = req.id);
Ok(())
}
})
Expand Down
2 changes: 1 addition & 1 deletion backend/src/endpoint/imgur.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl Image for ArcServer {
req.get_or_insert(|req| async move {
let url = self.imgur.upload(req.data).await?;

tracing::debug!(counter.image = 1, uri = url);
debug!(counter.image = 1, uri = url);
Ok(UploadResponse { url })
})
.await
Expand Down
24 changes: 18 additions & 6 deletions backend/src/endpoint/problem.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::*;
use grpc::backend::problem_server::*;
use sea_orm::sea_query::Expr;

use crate::entity::{contest, problem::Paginator, problem::*};
use crate::entity::{contest, problem::Paginator, problem::*, testcase};

impl<'a> From<WithAuth<'a, Model>> for ProblemFullInfo {
fn from(value: WithAuth<'a, Model>) -> Self {
Expand Down Expand Up @@ -139,7 +140,7 @@ impl Problem for ArcServer {

let id = *model.id.as_ref();

tracing::info!(count.problem = 1, id = id);
info!(count.problem = 1, id = id);

Ok(id.into())
})
Expand Down Expand Up @@ -191,17 +192,28 @@ impl Problem for ArcServer {
async fn remove(&self, req: Request<RemoveRequest>) -> Result<Response<()>, Status> {
let (auth, req) = self.rate_limit(req).in_current_span().await?;
req.get_or_insert(|req| async move {
let txn = self.db.begin().await?;

let result = Entity::delete_by_id(req.id)
.with_auth(&auth)
.write()?
.exec(self.db.deref())
.exec(&txn)
.instrument(info_span!("remove").or_current())
.await
.map_err(Into::<Error>::into)?;
.await?;

testcase::Entity::update_many()
.col_expr(testcase::Column::ProblemId, Expr::value(Value::Int(None)))
.filter(testcase::Column::ProblemId.eq(req.id))
.exec(&txn)
.instrument(info_span!("remove_child"))
.await?;

txn.commit().await.map_err(|_| Error::Retry)?;

if result.rows_affected == 0 {
return Err(Error::NotInDB);
}
info!(count.problem = -1, id = req.id);
Ok(())
})
.await
Expand Down Expand Up @@ -286,7 +298,7 @@ impl Problem for ArcServer {

let mut model = model.ok_or(Error::NotInDB)?.into_active_model();
if let Some(x) = model.contest_id.into_value() {
tracing::debug!(old_id = x.to_string());
debug!(old_id = x.to_string());
}
model.contest_id = ActiveValue::Set(None);
model
Expand Down
8 changes: 4 additions & 4 deletions backend/src/endpoint/submit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ impl Submit for ArcServer {
async fn info(&self, req: Request<Id>) -> Result<Response<SubmitInfo>, Status> {
let (auth, req) = self.rate_limit(req).in_current_span().await?;

tracing::debug!(id = req.id);
debug!(id = req.id);

let model = Entity::read_filter(Entity::find_by_id(req.id), &auth)?
.one(self.db.deref())
.instrument(tracing::debug_span!("fetch").or_current())
.instrument(debug_span!("fetch").or_current())
.await
.map_err(Into::<Error>::into)?
.ok_or(Error::NotInDB)?;
Expand Down Expand Up @@ -156,7 +156,7 @@ impl Submit for ArcServer {
.instrument(info_span!("construct_submit").or_current())
.await?;

tracing::info!(counter.submit = 1, id = id);
info!(counter.submit = 1, id = id);

Ok(id.into())
})
Expand Down Expand Up @@ -189,7 +189,7 @@ impl Submit for ArcServer {
if result.rows_affected == 0 {
Err(Error::NotInDB)
} else {
tracing::info!(counter.submit = -1, id = req.id);
info!(counter.submit = -1, id = req.id);
Ok(())
}
})
Expand Down
Loading

0 comments on commit c341b6c

Please sign in to comment.