update nextcloud for file support

This commit is contained in:
Matthias Hochmeister
2026-03-13 13:46:08 +01:00
parent e36de3199a
commit e26d77ef35
10 changed files with 600 additions and 24 deletions

View File

@@ -138,6 +138,7 @@ interface NextcloudChatMessage {
timestamp: number;
messageType: string;
systemMessage: string;
messageParameters: Record<string, any>;
}
async function getAllConversations(loginName: string, appPassword: string): Promise<NextcloudConversation[]> {
@@ -253,6 +254,7 @@ async function getMessages(token: string, loginName: string, appPassword: string
timestamp: m.timestamp,
messageType: m.messageType ?? '',
systemMessage: m.systemMessage ?? '',
messageParameters: m.messageParameters ?? {},
}));
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 401) {
@@ -412,5 +414,151 @@ async function getConversations(loginName: string, appPassword: string): Promise
}
}
async function uploadFileToTalk(
token: string,
fileBuffer: Buffer,
filename: string,
mimetype: string,
loginName: string,
appPassword: string,
): Promise<void> {
const baseUrl = environment.nextcloudUrl;
if (!baseUrl || !isValidServiceUrl(baseUrl)) {
throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
}
const authHeader = `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`;
// Add timestamp to avoid filename conflicts
const ext = filename.includes('.') ? filename.slice(filename.lastIndexOf('.')) : '';
const base = filename.includes('.') ? filename.slice(0, filename.lastIndexOf('.')) : filename;
const safeName = `${base}_${Date.now()}${ext}`;
const remotePath = `/Talk/${safeName}`;
try {
// Step 1: Upload via WebDAV
await httpClient.put(
`${baseUrl}/remote.php/dav/files/${encodeURIComponent(loginName)}${remotePath}`,
fileBuffer,
{
headers: {
'Authorization': authHeader,
'Content-Type': mimetype,
},
},
);
// Step 2: Share file to room
await httpClient.post(
`${baseUrl}/ocs/v2.php/apps/spreed/api/v1/chat/${encodeURIComponent(token)}/share`,
{ path: remotePath, shareType: 10 },
{
headers: {
'Authorization': authHeader,
'OCS-APIRequest': 'true',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
},
);
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 401) {
const err = new Error('Nextcloud authentication invalid');
(err as any).code = 'NEXTCLOUD_AUTH_INVALID';
throw err;
}
if (axios.isAxiosError(error)) {
logger.error('NextcloudService.uploadFileToTalk failed', {
status: error.response?.status,
statusText: error.response?.statusText,
});
throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
}
logger.error('NextcloudService.uploadFileToTalk failed', { error });
throw new Error('Failed to upload file to Nextcloud Talk');
}
}
async function downloadFile(
filePath: string,
loginName: string,
appPassword: string,
): Promise<any> {
const baseUrl = environment.nextcloudUrl;
if (!baseUrl || !isValidServiceUrl(baseUrl)) {
throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
}
const authHeader = `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`;
try {
const response = await httpClient.get(
`${baseUrl}/remote.php/dav/files/${encodeURIComponent(loginName)}/${filePath.replace(/^\//, '')}`,
{
headers: { 'Authorization': authHeader },
responseType: 'stream',
},
);
return response;
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 401) {
const err = new Error('Nextcloud authentication invalid');
(err as any).code = 'NEXTCLOUD_AUTH_INVALID';
throw err;
}
if (axios.isAxiosError(error)) {
logger.error('NextcloudService.downloadFile failed', {
status: error.response?.status,
statusText: error.response?.statusText,
});
throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
}
logger.error('NextcloudService.downloadFile failed', { error });
throw new Error('Failed to download file from Nextcloud');
}
}
async function getFilePreview(
fileId: number,
width: number,
height: number,
loginName: string,
appPassword: string,
): Promise<any> {
const baseUrl = environment.nextcloudUrl;
if (!baseUrl || !isValidServiceUrl(baseUrl)) {
throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
}
const authHeader = `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`;
try {
const response = await httpClient.get(
`${baseUrl}/index.php/core/preview`,
{
params: { fileId, x: width, y: height, a: 1 },
headers: { 'Authorization': authHeader },
responseType: 'stream',
},
);
return response;
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 401) {
const err = new Error('Nextcloud authentication invalid');
(err as any).code = 'NEXTCLOUD_AUTH_INVALID';
throw err;
}
if (axios.isAxiosError(error)) {
logger.error('NextcloudService.getFilePreview failed', {
status: error.response?.status,
statusText: error.response?.statusText,
});
throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
}
logger.error('NextcloudService.getFilePreview failed', { error });
throw new Error('Failed to get file preview from Nextcloud');
}
}
export type { NextcloudChatMessage, GetMessagesOptions };
export default { initiateLoginFlow, pollLoginFlow, getConversations, getAllConversations, getMessages, sendMessage, markAsRead };
export default { initiateLoginFlow, pollLoginFlow, getConversations, getAllConversations, getMessages, sendMessage, markAsRead, uploadFileToTalk, downloadFile, getFilePreview };