dev_servers.rs

  1use rpc::proto;
  2use sea_orm::{
  3    ActiveValue, ColumnTrait, DatabaseTransaction, EntityTrait, IntoActiveModel, QueryFilter,
  4};
  5
  6use super::{dev_server, dev_server_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 dev_server_projects_update(
 33        &self,
 34        user_id: UserId,
 35    ) -> crate::Result<proto::DevServerProjectsUpdate> {
 36        self.transaction(|tx| async move {
 37            self.dev_server_projects_update_internal(user_id, &tx).await
 38        })
 39        .await
 40    }
 41
 42    pub async fn dev_server_projects_update_internal(
 43        &self,
 44        user_id: UserId,
 45        tx: &DatabaseTransaction,
 46    ) -> crate::Result<proto::DevServerProjectsUpdate> {
 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 dev_server_projects = dev_server_project::Entity::find()
 53            .filter(
 54                dev_server_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::DevServerProjectsUpdate {
 62            dev_servers: dev_servers
 63                .into_iter()
 64                .map(|d| d.to_proto(proto::DevServerStatus::Offline))
 65                .collect(),
 66            dev_server_projects: dev_server_projects
 67                .into_iter()
 68                .map(|(dev_server_project, project)| dev_server_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::DevServerProjectsUpdate)> {
 79        self.transaction(|tx| async move {
 80            if name.trim().is_empty() {
 81                return Err(anyhow::anyhow!(proto::ErrorCode::Forbidden))?;
 82            }
 83
 84            let dev_server = dev_server::Entity::insert(dev_server::ActiveModel {
 85                id: ActiveValue::NotSet,
 86                hashed_token: ActiveValue::Set(hashed_access_token.to_string()),
 87                name: ActiveValue::Set(name.trim().to_string()),
 88                user_id: ActiveValue::Set(user_id),
 89            })
 90            .exec_with_returning(&*tx)
 91            .await?;
 92
 93            let dev_server_projects = self
 94                .dev_server_projects_update_internal(user_id, &tx)
 95                .await?;
 96
 97            Ok((dev_server, dev_server_projects))
 98        })
 99        .await
100    }
101
102    pub async fn update_dev_server_token(
103        &self,
104        id: DevServerId,
105        hashed_token: &str,
106        user_id: UserId,
107    ) -> crate::Result<proto::DevServerProjectsUpdate> {
108        self.transaction(|tx| async move {
109            let Some(dev_server) = dev_server::Entity::find_by_id(id).one(&*tx).await? else {
110                return Err(anyhow::anyhow!("no dev server with id {}", id))?;
111            };
112            if dev_server.user_id != user_id {
113                return Err(anyhow::anyhow!(proto::ErrorCode::Forbidden))?;
114            }
115
116            dev_server::Entity::update(dev_server::ActiveModel {
117                hashed_token: ActiveValue::Set(hashed_token.to_string()),
118                ..dev_server.clone().into_active_model()
119            })
120            .exec(&*tx)
121            .await?;
122
123            let dev_server_projects = self
124                .dev_server_projects_update_internal(user_id, &tx)
125                .await?;
126
127            Ok(dev_server_projects)
128        })
129        .await
130    }
131
132    pub async fn rename_dev_server(
133        &self,
134        id: DevServerId,
135        name: &str,
136        user_id: UserId,
137    ) -> crate::Result<proto::DevServerProjectsUpdate> {
138        self.transaction(|tx| async move {
139            let Some(dev_server) = dev_server::Entity::find_by_id(id).one(&*tx).await? else {
140                return Err(anyhow::anyhow!("no dev server with id {}", id))?;
141            };
142            if dev_server.user_id != user_id || name.trim().is_empty() {
143                return Err(anyhow::anyhow!(proto::ErrorCode::Forbidden))?;
144            }
145
146            dev_server::Entity::update(dev_server::ActiveModel {
147                name: ActiveValue::Set(name.trim().to_string()),
148                ..dev_server.clone().into_active_model()
149            })
150            .exec(&*tx)
151            .await?;
152
153            let dev_server_projects = self
154                .dev_server_projects_update_internal(user_id, &tx)
155                .await?;
156
157            Ok(dev_server_projects)
158        })
159        .await
160    }
161
162    pub async fn delete_dev_server(
163        &self,
164        id: DevServerId,
165        user_id: UserId,
166    ) -> crate::Result<proto::DevServerProjectsUpdate> {
167        self.transaction(|tx| async move {
168            let Some(dev_server) = dev_server::Entity::find_by_id(id).one(&*tx).await? else {
169                return Err(anyhow::anyhow!("no dev server with id {}", id))?;
170            };
171            if dev_server.user_id != user_id {
172                return Err(anyhow::anyhow!(proto::ErrorCode::Forbidden))?;
173            }
174
175            dev_server_project::Entity::delete_many()
176                .filter(dev_server_project::Column::DevServerId.eq(id))
177                .exec(&*tx)
178                .await?;
179
180            dev_server::Entity::delete(dev_server.into_active_model())
181                .exec(&*tx)
182                .await?;
183
184            let dev_server_projects = self
185                .dev_server_projects_update_internal(user_id, &tx)
186                .await?;
187
188            Ok(dev_server_projects)
189        })
190        .await
191    }
192}