Skip to content

Commit

Permalink
feat: allow admin scoped user to recreate any project (#651)
Browse files Browse the repository at this point in the history
* feat: allow admin scoped user to recreate any project

* refactor: address review
  • Loading branch information
oddgrd authored Feb 24, 2023
1 parent f8d5ac8 commit 5187f6a
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 16 deletions.
6 changes: 4 additions & 2 deletions gateway/src/api/latest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,13 @@ async fn post_project(
State(RouterState {
service, sender, ..
}): State<RouterState>,
User { name, .. }: User,
User { name, claim, .. }: User,
Path(project): Path<ProjectName>,
) -> Result<AxumJson<project::Response>, Error> {
let is_admin = claim.scopes.contains(&Scope::Admin);

let state = service
.create_project(project.clone(), name.clone())
.create_project(project.clone(), name.clone(), is_admin)
.await?;

service
Expand Down
60 changes: 46 additions & 14 deletions gateway/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,26 +361,36 @@ impl GatewayService {
&self,
project_name: ProjectName,
account_name: AccountName,
is_admin: bool,
) -> Result<Project, Error> {
if let Some(row) = query("SELECT project_name, account_name, initial_key, project_state FROM projects WHERE project_name = ?1 AND account_name = ?2")
.bind(&project_name)
.bind(&account_name)
.fetch_optional(&self.db)
.await?
if let Some(row) = query(
r#"
SELECT project_name, account_name, initial_key, project_state
FROM projects
WHERE (project_name = ?1)
AND (account_name = ?2 OR ?3)
"#,
)
.bind(&project_name)
.bind(&account_name)
.bind(is_admin)
.fetch_optional(&self.db)
.await?
{
// If the project already exists and belongs to this account
let project = row.get::<SqlxJson<Project>, _>("project_state").0;
if project.is_destroyed() {
// But is in `::Destroyed` state, recreate it
let mut creating = ProjectCreating::new_with_random_initial_key(project_name.clone());
let mut creating =
ProjectCreating::new_with_random_initial_key(project_name.clone());
// Restore previous custom domain, if any
match self.find_custom_domain_for_project(&project_name).await {
Ok(custom_domain) => {
creating = creating.with_fqdn(custom_domain.fqdn.to_string());
}
Err(error) if error.kind() == ErrorKind::CustomDomainNotFound => {
// no previous custom domain
},
}
Err(error) => return Err(error),
}
let project = Project::Creating(creating);
Expand Down Expand Up @@ -582,7 +592,7 @@ pub mod tests {
};

let project = svc
.create_project(matrix.clone(), neo.clone())
.create_project(matrix.clone(), neo.clone(), false)
.await
.unwrap();

Expand Down Expand Up @@ -643,7 +653,8 @@ pub mod tests {

// If recreated by a different user
assert!(matches!(
svc.create_project(matrix.clone(), trinity.clone()).await,
svc.create_project(matrix.clone(), trinity.clone(), false)
.await,
Err(Error {
kind: ErrorKind::ProjectAlreadyExists,
..
Expand All @@ -652,7 +663,28 @@ pub mod tests {

// If recreated by the same user
assert!(matches!(
svc.create_project(matrix, neo).await,
svc.create_project(matrix.clone(), neo, false).await,
Ok(Project::Creating(_))
));

let mut work = svc
.new_task()
.project(matrix.clone())
.and_then(task::destroy())
.build();

while let TaskResult::Pending(_) = work.poll(()).await {}
assert!(matches!(work.poll(()).await, TaskResult::Done(())));

// After project has been destroyed again...
assert!(matches!(
svc.find_project(&matrix).await,
Ok(Project::Destroyed(_))
));

// If recreated by an admin
assert!(matches!(
svc.create_project(matrix, trinity, true).await,
Ok(Project::Creating(_))
));

Expand All @@ -667,7 +699,7 @@ pub mod tests {
let neo: AccountName = "neo".parse().unwrap();
let matrix: ProjectName = "matrix".parse().unwrap();

svc.create_project(matrix.clone(), neo.clone())
svc.create_project(matrix.clone(), neo.clone(), false)
.await
.unwrap();

Expand Down Expand Up @@ -732,7 +764,7 @@ pub mod tests {
);

let _ = svc
.create_project(project_name.clone(), account.clone())
.create_project(project_name.clone(), account.clone(), false)
.await
.unwrap();

Expand Down Expand Up @@ -786,7 +818,7 @@ pub mod tests {
);

let _ = svc
.create_project(project_name.clone(), account.clone())
.create_project(project_name.clone(), account.clone(), false)
.await
.unwrap();

Expand All @@ -804,7 +836,7 @@ pub mod tests {
assert!(matches!(work.poll(()).await, TaskResult::Done(())));

let recreated_project = svc
.create_project(project_name.clone(), account.clone())
.create_project(project_name.clone(), account.clone(), false)
.await
.unwrap();

Expand Down

0 comments on commit 5187f6a

Please sign in to comment.