Skip to content

Commit

Permalink
Allow crate version deletion in the first 24 hours from creation
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Napetti committed Feb 6, 2023
1 parent 5231704 commit c4cf991
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/controllers/version.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod delete;
pub mod deprecated;
pub mod downloads;
pub mod metadata;
Expand Down
68 changes: 68 additions & 0 deletions src/controllers/version/delete.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//! Functionality related to deleting a crate.

use chrono::{Duration, Utc};
use diesel::dsl::count_star;

use crate::controllers::cargo_prelude::*;

use crate::schema::*;
use crate::util::errors::internal;
use crate::views::{EncodableCrate, GoodCrate, PublishWarnings};

use super::version_and_crate;

/// Handles the `DELETE /crates/:crate_id/:version` route.
///
/// Actually deletion is allowed only in the first 24 hours from creation
pub async fn delete(
app: AppState,
Path((crate_name, semver)): Path<(String, String)>,
) -> AppResult<Json<GoodCrate>> {
let conn = app.db_read()?;
let (version, krate) = version_and_crate(&conn, &crate_name, &semver)?;

if Utc::now()
.naive_utc()
.signed_duration_since(version.created_at)
> Duration::hours(24)
{
return Err(cargo_err(
"Version deletion is allowed only in the first 24 hours from creation",
));
}

// Create a transaction on the database, if there are no errors,
// commit the transactions to delete the version.
// If there are no remaining versions, delete the crate
conn.transaction(|| {
diesel::delete(versions::table.find(version.id)).execute(&*conn)?;

let top_versions = krate.top_versions(&conn)?;

// we can't check top_versions to know if there aren't remaining versions
// because it excludes yanked versions
let remaining: i64 = versions::table
.filter(versions::crate_id.eq(krate.id))
.select(count_star())
.first(&*conn)
.optional()?
.unwrap_or_default();
if remaining <= 0 {
diesel::delete(crates::table.find(krate.id)).execute(&*conn)?;

let uploader = app.config.uploader();
uploader
.delete_index(app.http_client(), &krate.name)
.map_err(|e| internal(format_args!("failed to delete crate: {e}")))?;
}

Ok(Json(GoodCrate {
krate: EncodableCrate::from_minimal(krate, Some(&top_versions), None, true, None),
warnings: PublishWarnings {
invalid_categories: vec![],
invalid_badges: vec![],
other: vec![],
},
}))
})
}
4 changes: 4 additions & 0 deletions src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ pub fn build_axum_router(state: AppState) -> Router {
.put(krate::owners::add_owners)
.delete(krate::owners::remove_owners),
)
.route(
"/api/v1/crates/:crate_id/:version",
delete(version::delete::delete),
)
.route(
"/api/v1/crates/:crate_id/:version/yank",
delete(version::yank::yank),
Expand Down

0 comments on commit c4cf991

Please sign in to comment.