// Copyright (C) 2023 Vaughn Nugent // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import { includes, isArray, isEmpty, join, map } from 'lodash-es'; import { get } from '@vueuse/core'; import { type WebMessage } from "@vnuge/vnlib.browser" import { type AxiosRequestConfig } from 'axios'; import { type MaybeRef } from 'vue'; import type { PostMeta, ContentMeta, ContentApi, BlogEntity, BlogAdminContext } from "../types"; /** * Configures a content api for a given content endpoint and channel * @param contentUrl The content endpoint url * @param channel The channel to get the content for * @returns A content api object */ export const useContent = (context : BlogAdminContext, channel: MaybeRef): ContentApi => { const axios = context.getAxios(); const getUrl = (): string => { const url = context.getContentUrl(); //Return the url with the channel id query return `${url}?channel=${get(channel)}`; } const getContentType = (file: File): string => { if (isEmpty(file.type)) { return 'application/octet-stream' } if (includes(file.type, 'javascript')) { return 'application/javascript' } if (includes(file.type, 'json')) { return 'application/json' } if (includes(file.type, 'xml')) { return 'application/xml' } return file.type; } /** * Gets the raw content item from the server and returns a string of the content * @param cotentId The id of the content to get the raw value of * @returns A promise that resolves to the raw content string */ const _getContent = async (cotentId: string): Promise => { const url = getUrl(); const response = await axios.get(`${url}&id=${cotentId}`); return await response.data; } const getPostContent = async (post: BlogEntity): Promise => { return await _getContent(post.id); } const getAllItems = async (): Promise => { const url = getUrl(); const response = await axios.get(url); return response.data; } const deleteContent = async (content: ContentMeta | ContentMeta[]): Promise => { const url = getUrl(); if(isArray(content)){ const ids = join(map(content, x => x.id)); //bulk delete by setting multiple ids const { data } = await axios.delete>(`${url}&ids=${ids}`); //Delete results returns a webmessage that contains the ids of the successfully deleted items const deleted = data.getResultOrThrow(); if(deleted.length !== content.length){ throw { message: 'Some items failed to delete' } } } else{ await axios.delete(`${url}&id=${content.id}`); } } const uploadContent = async (file: File, name: string, config?:AxiosRequestConfig): Promise => { const url = getUrl(); //Endpoint returns the new content meta for the uploaded content const { data } = await axios.put>(url, file, { ...config, headers: { 'Content-Type': getContentType(file), //Set the content name header as the supplied content name 'X-Content-Name': name } }); return data.getResultOrThrow(); } const updatePostContent = async (post: PostMeta, content: string): Promise => { const url = getUrl(); const { data } = await axios.put>(`${url}&id=${post.id}`, content, { headers: { 'Content-Type': 'text/html', //Set the content name header as the post id 'X-Content-Name': `Content for post ${post.id}` } }); return data.getResultOrThrow(); } const updateContent = async (content: ContentMeta, data: File, config?: AxiosRequestConfig): Promise => { const url = getUrl(); const response = await axios.put(`${url}&id=${content.id}`, data, { ...config, headers: { 'Content-Type': getContentType(data), //Set the content name header as the supplied content name 'X-Content-Name': content.name } }); return response.data; } const updateContentName = async (content: ContentMeta, name: string): Promise => { const url = getUrl(); //Create a new object with the same properties as the content meta, but with the new name const ct = { ...content, name: name } const { data } = await axios.patch>(url, ct); return data.getResultOrThrow(); } const getPublicUrl = async (content: ContentMeta): Promise => { //Get the public url from the server const response = await axios.get(`${getUrl()}&id=${content.id}&getlink=true`); //Response is a web-message if (response.data?.success !== true) { throw { response } } return response.data.result; } const getContent = async (id: string): Promise => { const index = await getAllItems(); return index.find(x => x.id === id); } const downloadContent = async (content: ContentMeta): Promise => { const url = getUrl(); const { data } = await axios.get(`${url}&id=${content.id}`, { responseType: 'blob' }); return data; } return { getPostContent, getAllItems, delete:deleteContent, uploadContent, updateContentName, updatePostContent, updateContent, getPublicUrl, getContent, downloadContent, }; }