summaryrefslogtreecommitdiff
path: root/makima/src/server/handlers/files.rs
diff options
context:
space:
mode:
Diffstat (limited to 'makima/src/server/handlers/files.rs')
-rw-r--r--makima/src/server/handlers/files.rs207
1 files changed, 1 insertions, 206 deletions
diff --git a/makima/src/server/handlers/files.rs b/makima/src/server/handlers/files.rs
index 711be41..023b9ff 100644
--- a/makima/src/server/handlers/files.rs
+++ b/makima/src/server/handlers/files.rs
@@ -145,26 +145,7 @@ pub async fn create_file(
.into_response();
};
- // Verify the contract exists and belongs to the owner
- match repository::get_contract_for_owner(pool, req.contract_id, auth.owner_id).await {
- Ok(None) => {
- return (
- StatusCode::NOT_FOUND,
- Json(ApiError::new("CONTRACT_NOT_FOUND", "Contract not found")),
- )
- .into_response();
- }
- Err(e) => {
- tracing::error!("Failed to verify contract: {}", e);
- return (
- StatusCode::INTERNAL_SERVER_ERROR,
- Json(ApiError::new("DB_ERROR", e.to_string())),
- )
- .into_response();
- }
- Ok(Some(_)) => {} // Contract exists, proceed
- }
-
+ // Legacy contract scope removed; files are owner-scoped only now.
match repository::create_file_for_owner(pool, auth.owner_id, req).await {
Ok(file) => (StatusCode::CREATED, Json(file)).into_response(),
Err(e) => {
@@ -336,189 +317,3 @@ pub async fn delete_file(
}
}
-/// Sync a file from its linked repository file.
-///
-/// This endpoint triggers an async sync operation. The file must have a
-/// repo_file_path set, and its contract must have a linked repository.
-/// A connected daemon will read the file and update the file content.
-#[utoipa::path(
- post,
- path = "/api/v1/files/{id}/sync-from-repo",
- params(
- ("id" = Uuid, Path, description = "File ID")
- ),
- responses(
- (status = 202, description = "Sync operation started"),
- (status = 400, description = "File not linked to repository", body = ApiError),
- (status = 401, description = "Unauthorized", body = ApiError),
- (status = 404, description = "File not found", body = ApiError),
- (status = 503, description = "No daemon available", body = ApiError),
- (status = 500, description = "Internal server error", body = ApiError),
- ),
- security(
- ("bearer_auth" = []),
- ("api_key" = [])
- ),
- tag = "Files"
-)]
-pub async fn sync_file_from_repo(
- State(state): State<SharedState>,
- Authenticated(auth): Authenticated,
- Path(id): Path<Uuid>,
-) -> impl IntoResponse {
- let Some(ref pool) = state.db_pool else {
- return (
- StatusCode::SERVICE_UNAVAILABLE,
- Json(ApiError::new("DB_UNAVAILABLE", "Database not configured")),
- )
- .into_response();
- };
-
- // Get the file and verify it has a repo_file_path
- let file = match repository::get_file_for_owner(pool, id, auth.owner_id).await {
- Ok(Some(f)) => f,
- Ok(None) => {
- return (
- StatusCode::NOT_FOUND,
- Json(ApiError::new("NOT_FOUND", "File not found")),
- )
- .into_response();
- }
- Err(e) => {
- tracing::error!("Failed to get file {}: {}", id, e);
- return (
- StatusCode::INTERNAL_SERVER_ERROR,
- Json(ApiError::new("DB_ERROR", e.to_string())),
- )
- .into_response();
- }
- };
-
- // Check if file has a repo path and contract_id
- let contract_id = match file.contract_id {
- Some(id) => id,
- None => {
- return (
- StatusCode::BAD_REQUEST,
- Json(ApiError::new(
- "NO_CONTRACT",
- "File is not associated with a contract",
- )),
- )
- .into_response();
- }
- };
-
- let repo_file_path = match file.repo_file_path {
- Some(ref path) if !path.is_empty() => path.clone(),
- _ => {
- return (
- StatusCode::BAD_REQUEST,
- Json(ApiError::new(
- "NOT_LINKED",
- "File is not linked to a repository file",
- )),
- )
- .into_response();
- }
- };
-
- // Get contract repositories
- let repositories = match repository::list_contract_repositories(pool, contract_id).await {
- Ok(repos) => repos,
- Err(e) => {
- tracing::error!("Failed to get contract repositories: {}", e);
- return (
- StatusCode::INTERNAL_SERVER_ERROR,
- Json(ApiError::new("DB_ERROR", e.to_string())),
- )
- .into_response();
- }
- };
-
- // Check if contract has repositories
- if repositories.is_empty() {
- return (
- StatusCode::BAD_REQUEST,
- Json(ApiError::new(
- "NO_REPOSITORY",
- "Contract has no linked repositories",
- )),
- )
- .into_response();
- }
-
- // Use the first repository's local path
- let repo = &repositories[0];
- let repo_local_path = match &repo.local_path {
- Some(path) if !path.is_empty() => path.clone(),
- _ => {
- return (
- StatusCode::BAD_REQUEST,
- Json(ApiError::new(
- "NO_LOCAL_PATH",
- "Repository has no local path configured",
- )),
- )
- .into_response();
- }
- };
-
- // Find a connected daemon for this owner
- let daemon_id = state
- .daemon_connections
- .iter()
- .find(|entry| entry.value().owner_id == auth.owner_id)
- .map(|entry| entry.value().id);
-
- let daemon_id = match daemon_id {
- Some(id) => id,
- None => {
- return (
- StatusCode::SERVICE_UNAVAILABLE,
- Json(ApiError::new(
- "NO_DAEMON",
- "No daemon connected. Start a daemon to sync files from repository.",
- )),
- )
- .into_response();
- }
- };
-
- // Send ReadRepoFile command to daemon
- // Use the file ID as the request_id so we can match the response
- let command = DaemonCommand::ReadRepoFile {
- request_id: id,
- contract_id,
- file_path: repo_file_path,
- repo_path: repo_local_path,
- };
-
- if let Err(e) = state.send_daemon_command(daemon_id, command).await {
- tracing::error!("Failed to send ReadRepoFile command: {}", e);
- return (
- StatusCode::INTERNAL_SERVER_ERROR,
- Json(ApiError::new("DAEMON_ERROR", e)),
- )
- .into_response();
- }
-
- // Update status to indicate sync in progress
- if let Err(e) = sqlx::query("UPDATE files SET repo_sync_status = 'syncing' WHERE id = $1")
- .bind(id)
- .execute(pool)
- .await
- {
- tracing::warn!("Failed to update repo_sync_status: {}", e);
- }
-
- // Return 202 Accepted - the sync happens asynchronously
- (
- StatusCode::ACCEPTED,
- Json(serde_json::json!({
- "message": "Sync operation started",
- "fileId": id,
- })),
- )
- .into_response()
-}