Skip to content

Commit d805ea8

Browse files
committed
allow updating extension identifiers
1 parent 0ba1554 commit d805ea8

File tree

3 files changed

+117
-6
lines changed

3 files changed

+117
-6
lines changed

apps/backend/src/models/extension.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ impl Extension {
188188
platforms: &BTreeMap<ExtensionPlatform, ExtensionPlatformData>,
189189
) -> Result<i32, sqlx::Error> {
190190
let identifier_random = rand::distr::Alphanumeric.sample_string(&mut rand::rng(), 8);
191+
let mut transaction = database.write().begin().await?;
191192

192193
let row = sqlx::query(
193194
r#"
@@ -205,7 +206,7 @@ impl Extension {
205206
.bind(description)
206207
.bind(serde_json::to_value(platforms).unwrap())
207208
.bind("_default.jpeg")
208-
.fetch_one(database.write())
209+
.fetch_one(&mut *transaction)
209210
.await?;
210211

211212
sqlx::query!(
@@ -215,9 +216,11 @@ impl Extension {
215216
row.get::<i32, _>("id"),
216217
format!("{identifier}:{identifier_random}")
217218
)
218-
.execute(database.write())
219+
.execute(&mut *transaction)
219220
.await?;
220221

222+
transaction.commit().await?;
223+
221224
Ok(row.get("id"))
222225
}
223226

apps/backend/src/routes/user/admin/extensions/_extension_/mod.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,14 @@ mod get {
9999
mod patch {
100100
use crate::{
101101
models::extension::{
102-
ExtensionPlatform, ExtensionPlatformData, ExtensionType, MinimalExtensionPlatformData,
102+
ExtensionPlatform, ExtensionPlatformData, ExtensionStatus, ExtensionType,
103+
MinimalExtensionPlatformData,
103104
},
104105
response::{ApiResponse, ApiResponseResult},
105106
routes::{ApiError, GetState, user::admin::extensions::_extension_::GetExtension},
106107
};
108+
use axum::http::StatusCode;
109+
use rand::distr::SampleString;
107110
use serde::{Deserialize, Serialize};
108111
use std::collections::BTreeMap;
109112
use utoipa::ToSchema;
@@ -114,6 +117,13 @@ mod patch {
114117
#[validate(length(min = 3, max = 63))]
115118
#[schema(min_length = 3, max_length = 63)]
116119
name: Option<String>,
120+
#[validate(
121+
length(min = 3, max = 48),
122+
regex(path = "*crate::models::extension::IDENTIFIER_REGEX")
123+
)]
124+
#[schema(min_length = 3, max_length = 48)]
125+
#[schema(pattern = "^[a-z]+$")]
126+
identifier: Option<String>,
117127
r#type: Option<ExtensionType>,
118128
unlisted: Option<bool>,
119129
#[validate(length(min = 3, max = 255))]
@@ -279,6 +289,49 @@ mod patch {
279289
}
280290
}
281291

292+
let mut transaction = state.database.write().begin().await?;
293+
294+
if extension.status != ExtensionStatus::Approved
295+
&& let Some(identifier) = data.identifier
296+
{
297+
match sqlx::query!(
298+
"UPDATE extensions
299+
SET identifier = $2
300+
WHERE extensions.id = $1",
301+
extension.id,
302+
identifier
303+
)
304+
.execute(&mut *transaction)
305+
.await
306+
{
307+
Ok(_) => {}
308+
Err(err) if err.to_string().contains("unique constraint") => {
309+
return ApiResponse::error("extension with identifier already exists")
310+
.with_status(StatusCode::CONFLICT)
311+
.ok();
312+
}
313+
Err(err) => {
314+
tracing::error!("failed to create extension: {:#?}", err);
315+
316+
return ApiResponse::error("failed to create extension")
317+
.with_status(StatusCode::INTERNAL_SERVER_ERROR)
318+
.ok();
319+
}
320+
}
321+
322+
let identifier_random = rand::distr::Alphanumeric.sample_string(&mut rand::rng(), 8);
323+
324+
sqlx::query!(
325+
"UPDATE extensions
326+
SET identifier = $2
327+
WHERE extensions.id = $1",
328+
extension.id,
329+
format!("{identifier}:{identifier_random}")
330+
)
331+
.execute(&mut *transaction)
332+
.await?;
333+
}
334+
282335
sqlx::query!(
283336
"UPDATE extensions
284337
SET name = $2, type = $3, unlisted = $4, summary = $5, description = $6, platforms = $7
@@ -291,8 +344,9 @@ mod patch {
291344
extension.description,
292345
serde_json::to_value(&extension.platforms)?
293346
)
294-
.execute(state.database.write())
347+
.execute(&mut *transaction)
295348
.await?;
349+
transaction.commit().await?;
296350
state.cache.clear_extension(&extension).await?;
297351

298352
ApiResponse::json(Response {}).ok()

apps/backend/src/routes/user/extensions/_extension_/mod.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,14 @@ mod get {
104104
mod patch {
105105
use crate::{
106106
models::extension::{
107-
ExtensionPlatform, ExtensionPlatformData, ExtensionType, MinimalExtensionPlatformData,
107+
ExtensionPlatform, ExtensionPlatformData, ExtensionStatus, ExtensionType,
108+
MinimalExtensionPlatformData,
108109
},
109110
response::{ApiResponse, ApiResponseResult},
110111
routes::{ApiError, GetState, user::extensions::_extension_::GetExtension},
111112
};
113+
use axum::http::StatusCode;
114+
use rand::distr::SampleString;
112115
use serde::{Deserialize, Serialize};
113116
use std::collections::BTreeMap;
114117
use utoipa::ToSchema;
@@ -119,6 +122,13 @@ mod patch {
119122
#[validate(length(min = 3, max = 63))]
120123
#[schema(min_length = 3, max_length = 63)]
121124
name: Option<String>,
125+
#[validate(
126+
length(min = 3, max = 48),
127+
regex(path = "*crate::models::extension::IDENTIFIER_REGEX")
128+
)]
129+
#[schema(min_length = 3, max_length = 48)]
130+
#[schema(pattern = "^[a-z]+$")]
131+
identifier: Option<String>,
122132
r#type: Option<ExtensionType>,
123133
unlisted: Option<bool>,
124134
#[validate(length(min = 3, max = 255))]
@@ -284,6 +294,49 @@ mod patch {
284294
}
285295
}
286296

297+
let mut transaction = state.database.write().begin().await?;
298+
299+
if extension.status != ExtensionStatus::Approved
300+
&& let Some(identifier) = data.identifier
301+
{
302+
match sqlx::query!(
303+
"UPDATE extensions
304+
SET identifier = $2
305+
WHERE extensions.id = $1",
306+
extension.id,
307+
identifier
308+
)
309+
.execute(&mut *transaction)
310+
.await
311+
{
312+
Ok(_) => {}
313+
Err(err) if err.to_string().contains("unique constraint") => {
314+
return ApiResponse::error("extension with identifier already exists")
315+
.with_status(StatusCode::CONFLICT)
316+
.ok();
317+
}
318+
Err(err) => {
319+
tracing::error!("failed to create extension: {:#?}", err);
320+
321+
return ApiResponse::error("failed to create extension")
322+
.with_status(StatusCode::INTERNAL_SERVER_ERROR)
323+
.ok();
324+
}
325+
}
326+
327+
let identifier_random = rand::distr::Alphanumeric.sample_string(&mut rand::rng(), 8);
328+
329+
sqlx::query!(
330+
"UPDATE extensions
331+
SET identifier = $2
332+
WHERE extensions.id = $1",
333+
extension.id,
334+
format!("{identifier}:{identifier_random}")
335+
)
336+
.execute(&mut *transaction)
337+
.await?;
338+
}
339+
287340
sqlx::query!(
288341
"UPDATE extensions
289342
SET name = $2, type = $3, unlisted = $4, summary = $5, description = $6, platforms = $7
@@ -296,8 +349,9 @@ mod patch {
296349
extension.description,
297350
serde_json::to_value(&extension.platforms)?
298351
)
299-
.execute(state.database.write())
352+
.execute(&mut *transaction)
300353
.await?;
354+
transaction.commit().await?;
301355
state.cache.clear_extension(&extension).await?;
302356

303357
ApiResponse::json(Response {}).ok()

0 commit comments

Comments
 (0)