import axios, { type AxiosResponse } from "axios"; import type { AnyHistory, HistorySummaryExtended } from "@/api"; import { GalaxyApi } from "@/api"; import { prependPath } from "@/utils/redirect"; import { ApiError, errorMessageAsString, type GalaxyApiResult, rethrowSimple } from "@/utils/simple-error"; /** * Generic json getter * @param response * @return response.data or throws an error if response status is not 200 */ function doResponse(response: AxiosResponse) { if (response.status !== 200) { throw new Error(response.statusText); } return response.data; } /** * Some current endpoints don't accept JSON, so we need to * do some massaging to send in old form post data. */ function formData(fields = {} as Record) { return Object.keys(fields).reduce((result, fieldName) => { result.set(fieldName, fields[fieldName]); return result; }, new FormData()); } /** * Extended history request parameters. * Retrieves additional details which are usually more "expensive". */ const extendedHistoryParams = { view: "summary", keys: "size,contents_active,user_id", }; /** * Create a new history, select it as the current history, and return it if successful. * @return the new history or throws an error if new history creation fails */ export async function createAndSelectNewHistory() { const url = "history/create_new_current"; const response = await axios.get(prependPath(url)); const newHistoryId = response?.data?.id || null; if (!newHistoryId) { throw new Error("failed to create and select new history"); } return doResponse(response); } /** * Get current history from server and return it. * @param since timestamp to get histories since * @return the current history */ export async function getCurrentHistoryFromServer(since: string | undefined = undefined) { const url = "history/current_history_json"; const response = await axios.get(prependPath(url), { params: { since: since } }); return doResponse(response); } /** * Set current history on server and return it. * @param historyId Encoded history id * @return the current history */ export async function setCurrentHistoryOnServer(historyId: string) { const url = "history/set_as_current"; const response = await axios.get(prependPath(url), { params: { id: historyId } }); return doResponse(response); } /** * Get list of histories from server and return them. * @param offset to start from (default = 0) * @param limit of histories to load (default = null; in which case no limit) * @param queryString to append to url in the form `q=filter&qv=val&q=...` * @return list of histories */ export async function getHistoryList(offset = 0, limit: number | null = null, queryString = "") { // TODO: to convert this to openapi-fetch we need to fix the query string handling // in the caller code to use the query object instead of a string const params = `view=summary&order=update_time&offset=${offset}`; let url = `api/histories?${params}`; if (limit !== null) { url += `&limit=${limit}`; } if (queryString !== "") { url += `&${queryString}`; } const response = await axios.get(prependPath(url)); return doResponse(response); } /** Load one history by id */ export async function getHistoryByIdFromServer(id: string): Promise> { const { data, error, response } = await GalaxyApi().GET("/api/histories/{history_id}", { params: { path: { history_id: id }, query: extendedHistoryParams, }, }); if (error) { return { data: undefined, error: new ApiError(errorMessageAsString(error), response.status) }; } // We know that the data is a HistorySummaryExtended because we requested it // with the extendedHistoryParams return { data: data as HistorySummaryExtended, error: undefined }; } /** * Set permissions to private for indicated history * TODO: rewrite API endpoint for this * @param history the history to secure * @return the secured history */ export async function secureHistoryOnServer(history: AnyHistory) { const { id } = history; const url = "history/make_private"; const response = await axios.post(prependPath(url), formData({ history_id: id })); if (response.status !== 200) { throw new Error(response.statusText); } const result = await getHistoryByIdFromServer(id); if (result.error) { throw result.error; } return { securedHistory: result.data, message: response.data.message as string, sharingStatusChanged: response.data.sharing_status_changed as boolean, }; } /** * Update specific fields in history * @param historyId the history id to update * @param payload fields to update * @return the updated history */ export async function updateHistoryFields(historyId: string, payload: Record) { const { data, error } = await GalaxyApi().PUT("/api/histories/{history_id}", { params: { path: { history_id: historyId }, query: extendedHistoryParams, }, body: payload, }); if (error) { rethrowSimple(error); } // We know that the data is a HistorySummaryExtended because we requested it // with the extendedHistoryParams return data as HistorySummaryExtended; }