Rename and fix the delete content source API endpoint

- Delete file objects on deleting content by source via API
  Previously only entries were deleted, not the associated file objects
- Add new db adapter to delete multiple file objects (by name)
This commit is contained in:
Debanjum
2025-03-07 13:25:17 +05:30
parent 29403551b2
commit b692e690b4
3 changed files with 24 additions and 15 deletions

View File

@@ -595,48 +595,48 @@ export default function SettingsView() {
}
};
const disconnectContent = async (type: string) => {
const disconnectContent = async (source: string) => {
try {
const response = await fetch(`/api/content/${type}`, {
const response = await fetch(`/api/content/source/${source}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
});
if (!response.ok) throw new Error(`Failed to disconnect ${type}`);
if (!response.ok) throw new Error(`Failed to disconnect ${source}`);
// Set updated user settings
if (userConfig) {
let newUserConfig = userConfig;
if (type === "computer") {
if (source === "computer") {
newUserConfig.enabled_content_source.computer = false;
} else if (type === "notion") {
} else if (source === "notion") {
newUserConfig.enabled_content_source.notion = false;
newUserConfig.notion_token = null;
setNotionToken(newUserConfig.notion_token);
} else if (type === "github") {
} else if (source === "github") {
newUserConfig.enabled_content_source.github = false;
}
setUserConfig(newUserConfig);
}
// Notify user about disconnecting content source
if (type === "computer") {
if (source === "computer") {
toast({
title: `✅ Deleted Synced Files`,
description: "Your synced documents have been deleted.",
});
} else {
toast({
title: `✅ Disconnected ${type}`,
description: `Your ${type} integration to Khoj has been disconnected.`,
title: `✅ Disconnected ${source}`,
description: `Your ${source} integration to Khoj has been disconnected.`,
});
}
} catch (error) {
console.error(`Error disconnecting ${type}:`, error);
console.error(`Error disconnecting ${source}:`, error);
toast({
title: `⚠️ Failed to Disconnect ${type}`,
description: `Failed to disconnect from ${type}. Try again or contact team@khoj.dev`,
title: `⚠️ Failed to Disconnect ${source}`,
description: `Failed to disconnect from ${source}. Try again or contact team@khoj.dev`,
});
}
};

View File

@@ -1549,6 +1549,11 @@ class FileObjectAdapters:
async def adelete_file_object_by_name(user: KhojUser, file_name: str):
return await FileObject.objects.filter(user=user, file_name=file_name).adelete()
@staticmethod
@arequire_valid_user
async def adelete_file_objects_by_names(user: KhojUser, file_names: List[str]):
return await FileObject.objects.filter(user=user, file_name__in=file_names).adelete()
@staticmethod
@arequire_valid_user
async def adelete_all_file_objects(user: KhojUser):

View File

@@ -420,7 +420,7 @@ async def get_content_source(
return await sync_to_async(list)(EntryAdapters.get_all_filenames_by_source(user, content_source)) # type: ignore[call-arg]
@api_content.delete("/{content_source}", status_code=200)
@api_content.delete("/source/{content_source}", status_code=200)
@requires(["authenticated"])
async def delete_content_source(
request: Request,
@@ -434,7 +434,12 @@ async def delete_content_source(
raise ValueError(f"Invalid content source: {content_source}")
elif content_object != "Computer":
await content_object.objects.filter(user=user).adelete()
await sync_to_async(EntryAdapters.delete_all_entries)(user, file_source=content_source)
else:
# Delete file objects from the given source
file_list = await sync_to_async(list)(EntryAdapters.get_all_filenames_by_source(user, content_source)) # type: ignore[call-arg]
await FileObjectAdapters.adelete_file_objects_by_names(user, file_list)
# Delete entries from the given source
await EntryAdapters.adelete_all_entries(user, file_source=content_source)
if content_source == DbEntry.EntrySource.NOTION:
await NotionConfig.objects.filter(user=user).adelete()
@@ -449,7 +454,6 @@ async def delete_content_source(
metadata={"content_source": content_source},
)
enabled_content = await sync_to_async(EntryAdapters.get_unique_file_types)(user)
return {"status": "ok"}