dev_servers.rs

  1use rpc::proto;
  2use sea_orm::{
  3    ActiveValue, ColumnTrait, DatabaseTransaction, EntityTrait, IntoActiveModel, QueryFilter,
  4};
  5
  6use super::{dev_server, remote_project, Database, DevServerId, UserId};
  7
  8impl Database {
  9    pub async fn get_dev_server(
 10        &self,
 11        dev_server_id: DevServerId,
 12    ) -> crate::Result<dev_server::Model> {
 13        self.transaction(|tx| async move {
 14            Ok(dev_server::Entity::find_by_id(dev_server_id)
 15                .one(&*tx)
 16                .await?
 17                .ok_or_else(|| anyhow::anyhow!("no dev server with id {}", dev_server_id))?)
 18        })
 19        .await
 20    }
 21
 22    pub async fn get_dev_servers(&self, user_id: UserId) -> crate::Result<Vec<dev_server::Model>> {
 23        self.transaction(|tx| async move {
 24            Ok(dev_server::Entity::find()
 25                .filter(dev_server::Column::UserId.eq(user_id))
 26                .all(&*tx)
 27                .await?)
 28        })
 29        .await
 30    }
 31
 32    pub async fn remote_projects_update(
 33        &self,
 34        user_id: UserId,
 35    ) -> crate::Result<proto::RemoteProjectsUpdate> {
 36        self.transaction(
 37            |tx| async move { self.remote_projects_update_internal(user_id, &tx).await },
 38        )
 39        .await
 40    }
 41
 42    pub async fn remote_projects_update_internal(
 43        &self,
 44        user_id: UserId,
 45        tx: &DatabaseTransaction,
 46    ) -> crate::Result<proto::RemoteProjectsUpdate> {
 47        let dev_servers = dev_server::Entity::find()
 48            .filter(dev_server::Column::UserId.eq(user_id))
 49            .all(tx)
 50            .await?;
 51
 52        let remote_projects = remote_project::Entity::find()
 53            .filter(
 54                remote_project::Column::DevServerId
 55                    .is_in(dev_servers.iter().map(|d| d.id).collect::<Vec<_>>()),
 56            )
 57            .find_also_related(super::project::Entity)
 58            .all(tx)
 59            .await?;
 60
 61        Ok(proto::RemoteProjectsUpdate {
 62            dev_servers: dev_servers
 63                .into_iter()
 64                .map(|d| d.to_proto(proto::DevServerStatus::Offline))
 65                .collect(),
 66            remote_projects: remote_projects
 67                .into_iter()
 68                .map(|(remote_project, project)| remote_project.to_proto(project))
 69                .collect(),
 70        })
 71    }
 72
 73    pub async fn create_dev_server(
 74        &self,
 75        name: &str,
 76        hashed_access_token: &str,
 77        user_id: UserId,
 78    ) -> crate::Result<(dev_server::Model, proto::RemoteProjectsUpdate)> {
 79        self.transaction(|tx| async move {
 80            let dev_server = dev_server::Entity::insert(dev_server::ActiveModel {
 81                id: ActiveValue::NotSet,
 82                hashed_token: ActiveValue::Set(hashed_access_token.to_string()),
 83                name: ActiveValue::Set(name.to_string()),
 84                user_id: ActiveValue::Set(user_id),
 85            })
 86            .exec_with_returning(&*tx)
 87            .await?;
 88
 89            let remote_projects = self.remote_projects_update_internal(user_id, &tx).await?;
 90
 91            Ok((dev_server, remote_projects))
 92        })
 93        .await
 94    }
 95
 96    pub async fn delete_dev_server(
 97        &self,
 98        id: DevServerId,
 99        user_id: UserId,
100    ) -> crate::Result<proto::RemoteProjectsUpdate> {
101        self.transaction(|tx| async move {
102            let Some(dev_server) = dev_server::Entity::find_by_id(id).one(&*tx).await? else {
103                return Err(anyhow::anyhow!("no dev server with id {}", id))?;
104            };
105            if dev_server.user_id != user_id {
106                return Err(anyhow::anyhow!(proto::ErrorCode::Forbidden))?;
107            }
108
109            remote_project::Entity::delete_many()
110                .filter(remote_project::Column::DevServerId.eq(id))
111                .exec(&*tx)
112                .await?;
113
114            dev_server::Entity::delete(dev_server.into_active_model())
115                .exec(&*tx)
116                .await?;
117
118            let remote_projects = self.remote_projects_update_internal(user_id, &tx).await?;
119
120            Ok(remote_projects)
121        })
122        .await
123    }
124}