mirror of https://github.com/halo-dev/halo
feat: add support for remote URL attachment downloads (#7602)
#### What type of PR is this? /area ui /kind feature /milestone 2.21.x #### What this PR does / why we need it: Add support for remote URL attachment downloads <img width="1031" alt="image" src="https://github.com/user-attachments/assets/f85eee2f-a40b-49ff-9ced-31136f59e67c" /> #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/7017 #### Does this PR introduce a user-facing change? ```release-note 支持通过远程地址下载到附件库 ```pull/7613/head
parent
79226998d3
commit
a4a418b22e
|
@ -15420,7 +15420,7 @@
|
|||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UploadFromUrlRequest"
|
||||
"$ref": "#/components/schemas/UcUploadFromUrlRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -20583,12 +20583,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -22355,12 +22355,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -23386,6 +23386,22 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"UcUploadFromUrlRequest": {
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Custom file name"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "url"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UcUploadRequest": {
|
||||
"required": [
|
||||
"file"
|
||||
|
@ -23445,12 +23461,22 @@
|
|||
},
|
||||
"UploadFromUrlRequest": {
|
||||
"required": [
|
||||
"policyName",
|
||||
"url"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"description": "Custom file name"
|
||||
},
|
||||
"groupName": {
|
||||
"type": "string",
|
||||
"description": "The name of the group to which the attachment belongs"
|
||||
},
|
||||
"policyName": {
|
||||
"type": "string",
|
||||
"description": "Storage policy name"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
|
|
|
@ -5471,12 +5471,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6007,12 +6007,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6468,13 +6468,16 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"description": "Custom file name"
|
||||
},
|
||||
"groupName": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"description": "The name of the group to which the attachment belongs"
|
||||
},
|
||||
"policyName": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"description": "Storage policy name"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
|
|
|
@ -12903,12 +12903,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -14281,12 +14281,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2609,12 +2609,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -3183,12 +3183,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1420,7 +1420,7 @@
|
|||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UploadFromUrlRequest"
|
||||
"$ref": "#/components/schemas/UcUploadFromUrlRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2470,12 +2470,12 @@
|
|||
},
|
||||
"visible": {
|
||||
"type": "string",
|
||||
"default": "PUBLIC",
|
||||
"enum": [
|
||||
"PUBLIC",
|
||||
"INTERNAL",
|
||||
"PRIVATE"
|
||||
]
|
||||
],
|
||||
"default": "PUBLIC"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2911,6 +2911,22 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"UcUploadFromUrlRequest": {
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Custom file name"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "url"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UcUploadRequest": {
|
||||
"required": [
|
||||
"file"
|
||||
|
@ -2944,21 +2960,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"UploadFromUrlRequest": {
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "url"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UserConnection": {
|
||||
"required": [
|
||||
"apiVersion",
|
||||
|
|
|
@ -5,12 +5,10 @@ import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
|
|||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.Assert;
|
||||
import run.halo.app.extension.AbstractExtension;
|
||||
import run.halo.app.extension.GVK;
|
||||
|
|
|
@ -73,7 +73,7 @@ public class FileTypeDetectUtils {
|
|||
/**
|
||||
* <p>Recommend to use this method to verify whether the file extension matches the file type
|
||||
* after matching the file type to avoid XSS attacks such as bypassing detection by polyglot
|
||||
* file</p>
|
||||
* file.</p>
|
||||
*
|
||||
* @param mimeType file mime type,such as "image/png"
|
||||
* @param fileName file name,such as "test.png"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package run.halo.app.theme.router;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import run.halo.app.extension.ListResult;
|
||||
import run.halo.app.infra.utils.PathUtils;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A utility class for template page url.
|
||||
|
|
|
@ -118,9 +118,11 @@ public class AttachmentEndpoint implements CustomEndpoint {
|
|||
}
|
||||
|
||||
public record UploadFromUrlRequest(@Schema(requiredMode = REQUIRED) URL url,
|
||||
@Schema(requiredMode = REQUIRED) String policyName,
|
||||
String groupName,
|
||||
String filename) {
|
||||
@Schema(requiredMode = REQUIRED, description = "Storage "
|
||||
+ "policy name") String policyName,
|
||||
@Schema(description = "The name of the group to which the "
|
||||
+ "attachment belongs") String groupName,
|
||||
@Schema(description = "Custom file name") String filename) {
|
||||
public UploadFromUrlRequest {
|
||||
if (Objects.isNull(url)) {
|
||||
throw new ServerWebInputException("Required url is missing.");
|
||||
|
|
|
@ -333,8 +333,9 @@ public class UcAttachmentEndpoint implements CustomEndpoint {
|
|||
return GroupVersion.parseAPIVersion("uc.api.storage.halo.run/v1alpha1");
|
||||
}
|
||||
|
||||
@Schema(name = "UcUploadFromUrlRequest")
|
||||
public record UploadFromUrlRequest(@Schema(requiredMode = REQUIRED) URL url,
|
||||
String filename) {
|
||||
@Schema(description = "Custom file name") String filename) {
|
||||
public UploadFromUrlRequest {
|
||||
if (Objects.isNull(url)) {
|
||||
throw new ServerWebInputException("Required url is missing.");
|
||||
|
|
|
@ -147,14 +147,13 @@ public class DefaultAttachmentService implements AttachmentService {
|
|||
AtomicReference<String> fileNameRef = new AtomicReference<>(filename);
|
||||
|
||||
Mono<Flux<DataBuffer>> contentMono = dataBufferFetcher.head(uri)
|
||||
.map(response -> {
|
||||
var httpHeaders = response.getHeaders();
|
||||
.map(httpHeaders -> {
|
||||
if (!StringUtils.hasText(fileNameRef.get())) {
|
||||
fileNameRef.set(getExternalUrlFilename(uri, httpHeaders));
|
||||
}
|
||||
MediaType contentType = httpHeaders.getContentType();
|
||||
mediaTypeRef.set(contentType);
|
||||
return response;
|
||||
return httpHeaders;
|
||||
})
|
||||
.map(response -> dataBufferFetcher.fetch(uri));
|
||||
|
||||
|
|
|
@ -2,10 +2,11 @@ package run.halo.app.infra;
|
|||
|
||||
import java.net.URI;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.client.ExchangeStrategies;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
@ -21,6 +22,8 @@ import reactor.netty.http.client.HttpClient;
|
|||
public class DefaultReactiveUrlDataBufferFetcher implements ReactiveUrlDataBufferFetcher {
|
||||
private final HttpClient httpClient = HttpClient.create()
|
||||
.followRedirect(true);
|
||||
private final ContentLengthFetcher contentLengthFetcher = new ContentLengthFetcher();
|
||||
|
||||
private final WebClient webClient = WebClient.builder()
|
||||
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||
.build();
|
||||
|
@ -35,10 +38,32 @@ public class DefaultReactiveUrlDataBufferFetcher implements ReactiveUrlDataBuffe
|
|||
}
|
||||
|
||||
@Override
|
||||
public Mono<ResponseEntity<Void>> head(URI uri) {
|
||||
return webClient.head()
|
||||
.uri(uri)
|
||||
.retrieve()
|
||||
.toBodilessEntity();
|
||||
public Mono<HttpHeaders> head(URI uri) {
|
||||
return contentLengthFetcher.fetchContentLength(uri);
|
||||
}
|
||||
|
||||
static class ContentLengthFetcher {
|
||||
|
||||
private final WebClient webClient;
|
||||
|
||||
ContentLengthFetcher() {
|
||||
this.webClient = WebClient.builder()
|
||||
.exchangeStrategies(ExchangeStrategies.builder()
|
||||
.codecs(config -> config.defaultCodecs().maxInMemorySize(1))
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
Mono<HttpHeaders> fetchContentLength(URI url) {
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.exchangeToMono(response -> {
|
||||
HttpHeaders headers = response.headers().asHttpHeaders();
|
||||
|
||||
return response.bodyToMono(byte[].class)
|
||||
.onErrorResume(ex -> Mono.empty())
|
||||
.thenReturn(headers);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package run.halo.app.infra;
|
|||
|
||||
import java.net.URI;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
@ -28,5 +28,5 @@ public interface ReactiveUrlDataBufferFetcher {
|
|||
* @param uri uri to fetch
|
||||
* @return response entity
|
||||
*/
|
||||
Mono<ResponseEntity<Void>> head(URI uri);
|
||||
Mono<HttpHeaders> head(URI uri);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
@ -303,10 +304,11 @@ class AttachmentEndpointTest {
|
|||
attachment.setMetadata(metadata);
|
||||
|
||||
ResponseEntity<Void> response = new ResponseEntity<>(HttpStatusCode.valueOf(200));
|
||||
HttpHeaders headers = response.getHeaders();
|
||||
DataBuffer dataBuffer = mock(DataBuffer.class);
|
||||
|
||||
when(handler.upload(any())).thenReturn(Mono.just(attachment));
|
||||
when(dataBufferFetcher.head(any())).thenReturn(Mono.just(response));
|
||||
when(dataBufferFetcher.head(any())).thenReturn(Mono.just(headers));
|
||||
when(dataBufferFetcher.fetch(any())).thenReturn(Flux.just(dataBuffer));
|
||||
when(extensionGetter.getExtensions(AttachmentHandler.class))
|
||||
.thenReturn(Flux.just(handler));
|
||||
|
|
|
@ -6,6 +6,8 @@ import {
|
|||
VDropdown,
|
||||
VDropdownItem,
|
||||
VModal,
|
||||
VTabItem,
|
||||
VTabs,
|
||||
} from "@halo-dev/components";
|
||||
import { useLocalStorage } from "@vueuse/core";
|
||||
import { onMounted, ref } from "vue";
|
||||
|
@ -18,6 +20,7 @@ import AttachmentGroupBadge from "./AttachmentGroupBadge.vue";
|
|||
import AttachmentGroupEditingModal from "./AttachmentGroupEditingModal.vue";
|
||||
import AttachmentPolicyBadge from "./AttachmentPolicyBadge.vue";
|
||||
import AttachmentPolicyEditingModal from "./AttachmentPolicyEditingModal.vue";
|
||||
import UploadFromUrl from "./UploadFromUrl.vue";
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "close"): void;
|
||||
|
@ -62,6 +65,8 @@ const onGroupEditingModalClose = async () => {
|
|||
await handleFetchGroups();
|
||||
groupEditingModal.value = false;
|
||||
};
|
||||
|
||||
const activeTab = ref("upload");
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -156,6 +161,15 @@ const onGroupEditingModalClose = async () => {
|
|||
</template>
|
||||
</AttachmentGroupBadge>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<VTabs v-model:active-id="activeTab" type="outline">
|
||||
<VTabItem
|
||||
id="upload"
|
||||
:label="
|
||||
$t('core.attachment.upload_modal.upload_options.local_upload')
|
||||
"
|
||||
>
|
||||
<UppyUpload
|
||||
endpoint="/apis/api.console.halo.run/v1alpha1/attachments/upload"
|
||||
:disabled="!selectedPolicyName"
|
||||
|
@ -172,6 +186,18 @@ const onGroupEditingModalClose = async () => {
|
|||
"
|
||||
:done-button-handler="() => modal?.close()"
|
||||
/>
|
||||
</VTabItem>
|
||||
<VTabItem
|
||||
id="download"
|
||||
:label="$t('core.attachment.upload_modal.upload_options.download')"
|
||||
>
|
||||
<UploadFromUrl
|
||||
:policy-name="selectedPolicyName"
|
||||
:group-name="selectedGroupName"
|
||||
/>
|
||||
</VTabItem>
|
||||
</VTabs>
|
||||
</div>
|
||||
</div>
|
||||
</VModal>
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
<script lang="ts" setup>
|
||||
import { setFocus } from "@/formkit/utils/focus";
|
||||
import { reset } from "@formkit/core";
|
||||
import { consoleApiClient } from "@halo-dev/api-client";
|
||||
import { Toast, VButton } from "@halo-dev/components";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
policyName: string;
|
||||
groupName: string;
|
||||
}>(),
|
||||
{}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
setFocus("url");
|
||||
});
|
||||
|
||||
const downloading = ref(false);
|
||||
|
||||
async function onSubmit(data: { url: string }) {
|
||||
try {
|
||||
downloading.value = true;
|
||||
|
||||
await consoleApiClient.storage.attachment.externalTransferAttachment({
|
||||
uploadFromUrlRequest: {
|
||||
url: data.url,
|
||||
policyName: props.policyName,
|
||||
groupName: props.groupName,
|
||||
},
|
||||
});
|
||||
|
||||
Toast.success(
|
||||
t("core.attachment.upload_modal.download_form.toast.success")
|
||||
);
|
||||
|
||||
reset("url");
|
||||
} catch (error) {
|
||||
return error;
|
||||
} finally {
|
||||
downloading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FormKit
|
||||
id="upload-from-url"
|
||||
type="form"
|
||||
name="upload-from-url"
|
||||
:config="{ validationVisibility: 'submit' }"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<FormKit
|
||||
id="url"
|
||||
type="url"
|
||||
name="url"
|
||||
:label="$t('core.attachment.upload_modal.download_form.fields.url.label')"
|
||||
:validation="[['required'], ['url']]"
|
||||
/>
|
||||
</FormKit>
|
||||
|
||||
<div class="mt-4">
|
||||
<VButton
|
||||
type="secondary"
|
||||
:loading="downloading"
|
||||
@click="$formkit.submit('upload-from-url')"
|
||||
>
|
||||
{{ $t("core.common.buttons.download") }}
|
||||
</VButton>
|
||||
</div>
|
||||
</template>
|
|
@ -322,6 +322,7 @@ models/thumbnail.ts
|
|||
models/totp-auth-link-response.ts
|
||||
models/totp-request.ts
|
||||
models/two-factor-auth-settings.ts
|
||||
models/uc-upload-from-url-request.ts
|
||||
models/uc-upload-request-form-data.ts
|
||||
models/upgrade-from-uri-request.ts
|
||||
models/upload-from-url-request.ts
|
||||
|
|
|
@ -26,9 +26,9 @@ import { Attachment } from '../models';
|
|||
// @ts-ignore
|
||||
import { AttachmentList } from '../models';
|
||||
// @ts-ignore
|
||||
import { UcUploadRequestFormData } from '../models';
|
||||
import { UcUploadFromUrlRequest } from '../models';
|
||||
// @ts-ignore
|
||||
import { UploadFromUrlRequest } from '../models';
|
||||
import { UcUploadRequestFormData } from '../models';
|
||||
/**
|
||||
* AttachmentV1alpha1UcApi - axios parameter creator
|
||||
* @export
|
||||
|
@ -100,14 +100,14 @@ export const AttachmentV1alpha1UcApiAxiosParamCreator = function (configuration?
|
|||
},
|
||||
/**
|
||||
* Upload attachment from the given URL.
|
||||
* @param {UploadFromUrlRequest} uploadFromUrlRequest
|
||||
* @param {UcUploadFromUrlRequest} ucUploadFromUrlRequest
|
||||
* @param {boolean} [waitForPermalink] Wait for permalink.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
externalTransferAttachment1: async (uploadFromUrlRequest: UploadFromUrlRequest, waitForPermalink?: boolean, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'uploadFromUrlRequest' is not null or undefined
|
||||
assertParamExists('externalTransferAttachment1', 'uploadFromUrlRequest', uploadFromUrlRequest)
|
||||
externalTransferAttachment1: async (ucUploadFromUrlRequest: UcUploadFromUrlRequest, waitForPermalink?: boolean, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'ucUploadFromUrlRequest' is not null or undefined
|
||||
assertParamExists('externalTransferAttachment1', 'ucUploadFromUrlRequest', ucUploadFromUrlRequest)
|
||||
const localVarPath = `/apis/uc.api.storage.halo.run/v1alpha1/attachments/-/upload-from-url`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
|
@ -139,7 +139,7 @@ export const AttachmentV1alpha1UcApiAxiosParamCreator = function (configuration?
|
|||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(uploadFromUrlRequest, localVarRequestOptions, configuration)
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(ucUploadFromUrlRequest, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
|
@ -303,13 +303,13 @@ export const AttachmentV1alpha1UcApiFp = function(configuration?: Configuration)
|
|||
},
|
||||
/**
|
||||
* Upload attachment from the given URL.
|
||||
* @param {UploadFromUrlRequest} uploadFromUrlRequest
|
||||
* @param {UcUploadFromUrlRequest} ucUploadFromUrlRequest
|
||||
* @param {boolean} [waitForPermalink] Wait for permalink.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async externalTransferAttachment1(uploadFromUrlRequest: UploadFromUrlRequest, waitForPermalink?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Attachment>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.externalTransferAttachment1(uploadFromUrlRequest, waitForPermalink, options);
|
||||
async externalTransferAttachment1(ucUploadFromUrlRequest: UcUploadFromUrlRequest, waitForPermalink?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Attachment>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.externalTransferAttachment1(ucUploadFromUrlRequest, waitForPermalink, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['AttachmentV1alpha1UcApi.externalTransferAttachment1']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
|
@ -372,7 +372,7 @@ export const AttachmentV1alpha1UcApiFactory = function (configuration?: Configur
|
|||
* @throws {RequiredError}
|
||||
*/
|
||||
externalTransferAttachment1(requestParameters: AttachmentV1alpha1UcApiExternalTransferAttachment1Request, options?: RawAxiosRequestConfig): AxiosPromise<Attachment> {
|
||||
return localVarFp.externalTransferAttachment1(requestParameters.uploadFromUrlRequest, requestParameters.waitForPermalink, options).then((request) => request(axios, basePath));
|
||||
return localVarFp.externalTransferAttachment1(requestParameters.ucUploadFromUrlRequest, requestParameters.waitForPermalink, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* List attachments of the current user uploaded.
|
||||
|
@ -438,10 +438,10 @@ export interface AttachmentV1alpha1UcApiCreateAttachmentForPostRequest {
|
|||
export interface AttachmentV1alpha1UcApiExternalTransferAttachment1Request {
|
||||
/**
|
||||
*
|
||||
* @type {UploadFromUrlRequest}
|
||||
* @type {UcUploadFromUrlRequest}
|
||||
* @memberof AttachmentV1alpha1UcApiExternalTransferAttachment1
|
||||
*/
|
||||
readonly uploadFromUrlRequest: UploadFromUrlRequest
|
||||
readonly ucUploadFromUrlRequest: UcUploadFromUrlRequest
|
||||
|
||||
/**
|
||||
* Wait for permalink.
|
||||
|
@ -561,7 +561,7 @@ export class AttachmentV1alpha1UcApi extends BaseAPI {
|
|||
* @memberof AttachmentV1alpha1UcApi
|
||||
*/
|
||||
public externalTransferAttachment1(requestParameters: AttachmentV1alpha1UcApiExternalTransferAttachment1Request, options?: RawAxiosRequestConfig) {
|
||||
return AttachmentV1alpha1UcApiFp(this.configuration).externalTransferAttachment1(requestParameters.uploadFromUrlRequest, requestParameters.waitForPermalink, options).then((request) => request(this.axios, this.basePath));
|
||||
return AttachmentV1alpha1UcApiFp(this.configuration).externalTransferAttachment1(requestParameters.ucUploadFromUrlRequest, requestParameters.waitForPermalink, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -233,6 +233,7 @@ export * from './thumbnail-spec';
|
|||
export * from './totp-auth-link-response';
|
||||
export * from './totp-request';
|
||||
export * from './two-factor-auth-settings';
|
||||
export * from './uc-upload-from-url-request';
|
||||
export * from './uc-upload-request-form-data';
|
||||
export * from './upgrade-from-uri-request';
|
||||
export * from './upload-from-url-request';
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Halo
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 2.21.0-SNAPSHOT
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface UcUploadFromUrlRequest
|
||||
*/
|
||||
export interface UcUploadFromUrlRequest {
|
||||
/**
|
||||
* Custom file name
|
||||
* @type {string}
|
||||
* @memberof UcUploadFromUrlRequest
|
||||
*/
|
||||
'filename'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UcUploadFromUrlRequest
|
||||
*/
|
||||
'url': string;
|
||||
}
|
||||
|
|
@ -21,11 +21,23 @@
|
|||
*/
|
||||
export interface UploadFromUrlRequest {
|
||||
/**
|
||||
*
|
||||
* Custom file name
|
||||
* @type {string}
|
||||
* @memberof UploadFromUrlRequest
|
||||
*/
|
||||
'filename'?: string;
|
||||
/**
|
||||
* The name of the group to which the attachment belongs
|
||||
* @type {string}
|
||||
* @memberof UploadFromUrlRequest
|
||||
*/
|
||||
'groupName'?: string;
|
||||
/**
|
||||
* Storage policy name
|
||||
* @type {string}
|
||||
* @memberof UploadFromUrlRequest
|
||||
*/
|
||||
'policyName': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
|
|
|
@ -222,6 +222,16 @@ core:
|
|||
policy_editing_modal:
|
||||
toast:
|
||||
policy_name_exists: Storage policy name already exists
|
||||
upload_modal:
|
||||
upload_options:
|
||||
local_upload: Upload
|
||||
download: Download from url
|
||||
download_form:
|
||||
fields:
|
||||
url:
|
||||
label: URL
|
||||
toast:
|
||||
success: Downloaded successfully
|
||||
uc_attachment:
|
||||
empty:
|
||||
title: There are no attachments.
|
||||
|
|
|
@ -158,8 +158,8 @@ core:
|
|||
back:
|
||||
title: Layout not saved
|
||||
description: >-
|
||||
The current layout has not been saved, if you leave, the current layout
|
||||
will be lost, do you want to continue?
|
||||
The current layout has not been saved, if you leave, the current
|
||||
layout will be lost, do you want to continue?
|
||||
confirm_text: Leave
|
||||
change_breakpoint:
|
||||
tips_not_saved: Please save the current layout first
|
||||
|
@ -754,6 +754,15 @@ core:
|
|||
title: No storage policy
|
||||
description: Before uploading, a new storage policy needs to be created.
|
||||
not_select: Please select a storage policy first.
|
||||
upload_options:
|
||||
local_upload: Upload
|
||||
download: Download from url
|
||||
download_form:
|
||||
fields:
|
||||
url:
|
||||
label: URL
|
||||
toast:
|
||||
success: Downloaded successfully
|
||||
select_modal:
|
||||
title: Select attachment
|
||||
providers:
|
||||
|
|
|
@ -711,6 +711,15 @@ core:
|
|||
title: 没有存储策略
|
||||
description: 在上传之前,需要新建一个存储策略
|
||||
not_select: 请先选择存储策略
|
||||
upload_options:
|
||||
local_upload: 本地上传
|
||||
download: 通过链接下载
|
||||
download_form:
|
||||
fields:
|
||||
url:
|
||||
label: 链接地址
|
||||
toast:
|
||||
success: 下载成功
|
||||
select_modal:
|
||||
title: 选择附件
|
||||
providers:
|
||||
|
|
|
@ -696,6 +696,15 @@ core:
|
|||
title: 沒有存儲策略
|
||||
description: 在上傳之前,需要新建一個存儲策略
|
||||
not_select: 請先選擇存儲策略
|
||||
upload_options:
|
||||
local_upload: 本地上傳
|
||||
download: 通過鏈接下載
|
||||
download_form:
|
||||
fields:
|
||||
url:
|
||||
label: 鏈接地址
|
||||
toast:
|
||||
success: 下載成功
|
||||
select_modal:
|
||||
title: 選擇附件
|
||||
providers:
|
||||
|
|
Loading…
Reference in New Issue