diff --git a/crates/workspace-server/src/authority.rs b/crates/workspace-server/src/authority.rs index 6263f767..6b038a4c 100644 --- a/crates/workspace-server/src/authority.rs +++ b/crates/workspace-server/src/authority.rs @@ -698,11 +698,20 @@ impl SqliteWorkspaceAuthority { }) } - fn read_ticket_detail(&self, id: &str, request: TicketShowRequest) -> Result { - validate_project_id(id)?; - let ticket = self - .ticket_backend - .show(TicketIdOrSlug::Id(id.to_string()))?; + fn read_ticket_detail( + &self, + reference: &str, + request: TicketShowRequest, + ) -> Result { + let id = self + .store + .resolve_resource_reference( + &self.workspace_id, + WorkspaceResourceKind::Ticket, + reference, + )? + .ok_or_else(|| Error::Ticket(ticket::TicketError::NotFound(reference.to_string())))?; + let ticket = self.ticket_backend.show(TicketIdOrSlug::Id(id))?; self.ticket_detail_from_ticket(ticket, request) } @@ -1147,15 +1156,21 @@ impl ObjectiveAuthority for SqliteWorkspaceAuthority { }) } - fn objective(&self, id: &str) -> Result { - validate_project_id(id)?; - let record = self.objective_record(id)?; + fn objective(&self, reference: &str) -> Result { + let record = self.objective_record(reference)?; self.objective_detail_from_record(record) } - fn show_objective(&self, id: &str, query: ObjectiveShowRequest) -> Result { - let mut detail = self.objective(id)?; - let all_events = self.store.list_objective_events(&self.workspace_id, id)?; + fn show_objective( + &self, + reference: &str, + query: ObjectiveShowRequest, + ) -> Result { + let mut detail = self.objective(reference)?; + let objective_id = detail.id.clone(); + let all_events = self + .store + .list_objective_events(&self.workspace_id, &objective_id)?; let event_limit = query .event_limit .unwrap_or(TICKET_EVENT_LIMIT) @@ -1240,9 +1255,12 @@ impl ObjectiveAuthority for SqliteWorkspaceAuthority { self.objective(&objective_id) } - fn edit_objective(&self, id: &str, input: ObjectiveEditInput) -> Result { - validate_project_id(id)?; - let mut record = self.objective_record(id)?; + fn edit_objective( + &self, + reference: &str, + input: ObjectiveEditInput, + ) -> Result { + let mut record = self.objective_record(reference)?; let mut changed = false; if let Some(title) = input.title { validate_objective_title(&title)?; @@ -1288,60 +1306,85 @@ impl ObjectiveAuthority for SqliteWorkspaceAuthority { )); } record.updated_at = now_rfc3339(); + let objective_id = record.objective_id.clone(); self.store.upsert_objective(&record)?; - self.insert_objective_event(id, "edit", None)?; - self.objective(id) + self.insert_objective_event(&objective_id, "edit", None)?; + self.objective(&objective_id) } - fn set_objective_state(&self, id: &str, state: &str) -> Result { - validate_project_id(id)?; + fn set_objective_state(&self, reference: &str, state: &str) -> Result { validate_objective_state(state)?; - let mut record = self.objective_record(id)?; + let mut record = self.objective_record(reference)?; record.state = state.trim().to_string(); record.updated_at = now_rfc3339(); + let objective_id = record.objective_id.clone(); self.store.upsert_objective(&record)?; - self.insert_objective_event(id, "state", Some(&record.state))?; - self.objective(id) + self.insert_objective_event(&objective_id, "state", Some(&record.state))?; + self.objective(&objective_id) } - fn link_objective_ticket(&self, id: &str, ticket_id: &str) -> Result { - validate_project_id(id)?; - validate_project_id(ticket_id)?; - let _record = self.objective_record(id)?; + fn link_objective_ticket( + &self, + objective_reference: &str, + ticket_reference: &str, + ) -> Result { + let objective_id = self.objective_record(objective_reference)?.objective_id; + let ticket_id = self + .store + .resolve_resource_reference( + &self.workspace_id, + WorkspaceResourceKind::Ticket, + ticket_reference, + )? + .ok_or_else(|| { + Error::Ticket(ticket::TicketError::NotFound(ticket_reference.to_string())) + })?; let now = now_rfc3339(); let mut links = self .store - .list_objective_ticket_links(&self.workspace_id, id)?; + .list_objective_ticket_links(&self.workspace_id, &objective_id)?; if !links.iter().any(|link| link.ticket_id == ticket_id) { links.push(ObjectiveTicketLinkRecord { workspace_id: self.workspace_id.clone(), - objective_id: id.to_string(), - ticket_id: ticket_id.to_string(), + objective_id: objective_id.clone(), + ticket_id: ticket_id.clone(), kind: "linked".to_string(), created_at: now, }); self.store - .replace_objective_ticket_links(&self.workspace_id, id, &links)?; - self.insert_objective_event(id, "link_ticket", Some(ticket_id))?; + .replace_objective_ticket_links(&self.workspace_id, &objective_id, &links)?; + self.insert_objective_event(&objective_id, "link_ticket", Some(&ticket_id))?; } - self.objective(id) + self.objective(&objective_id) } - fn unlink_objective_ticket(&self, id: &str, ticket_id: &str) -> Result { - validate_project_id(id)?; - validate_project_id(ticket_id)?; - let _record = self.objective_record(id)?; + fn unlink_objective_ticket( + &self, + objective_reference: &str, + ticket_reference: &str, + ) -> Result { + let objective_id = self.objective_record(objective_reference)?.objective_id; + let ticket_id = self + .store + .resolve_resource_reference( + &self.workspace_id, + WorkspaceResourceKind::Ticket, + ticket_reference, + )? + .ok_or_else(|| { + Error::Ticket(ticket::TicketError::NotFound(ticket_reference.to_string())) + })?; let mut links = self .store - .list_objective_ticket_links(&self.workspace_id, id)?; + .list_objective_ticket_links(&self.workspace_id, &objective_id)?; let original_len = links.len(); links.retain(|link| link.ticket_id != ticket_id); if links.len() != original_len { self.store - .replace_objective_ticket_links(&self.workspace_id, id, &links)?; - self.insert_objective_event(id, "unlink_ticket", Some(ticket_id))?; + .replace_objective_ticket_links(&self.workspace_id, &objective_id, &links)?; + self.insert_objective_event(&objective_id, "unlink_ticket", Some(&ticket_id))?; } - self.objective(id) + self.objective(&objective_id) } } @@ -2907,6 +2950,8 @@ mod tests { assert_eq!(tickets.items[0].id, "00000000001J2"); assert_eq!(tickets.items[0].state, "ready"); assert_eq!(tickets.items[0].workspace_action_priority, "background"); + let ticket_by_key = authority.ticket(&tickets.items[0].human_key).unwrap(); + assert_eq!(ticket_by_key.id, tickets.items[0].id); let ticket = authority.ticket("00000000001J2").unwrap(); assert!(ticket.body.contains("Ticket body")); @@ -3078,6 +3123,18 @@ mod tests { assert_eq!(objectives.items.len(), 1); assert_eq!(objectives.items[0].id, "00000000001J3"); assert_eq!(objectives.items[0].linked_tickets, vec!["00000000001J2"]); + let objective_by_key = authority.objective(&objectives.items[0].human_key).unwrap(); + assert_eq!(objective_by_key.id, objectives.items[0].id); + assert_eq!( + authority + .show_objective( + &objectives.items[0].human_key, + ObjectiveShowRequest::default(), + ) + .unwrap() + .id, + objectives.items[0].id + ); let objective = authority.objective("00000000001J3").unwrap(); assert!(objective.body.contains("Objective body"));