mirror of https://github.com/halo-dev/halo
feat: API to save external links as attachments (#6364)
#### What type of PR is this? /kind api-change /kind feature /area core #### What this PR does / why we need it: see #2335 增加将第三方资源转存为附件资源的接口。 `/apis/api.console.halo.run/v1alpha1/attachments/-/upload-from-url` UC: `/apis/uc.api.content.halo.run/v1alpha1/attachments/-/upload-from-url` 其中参数为 ```json { "url": "string", "filename": "string", "groupName": "string", "policyName": "string" } ``` #### How to test it? 测试能否将第三方接口的资源保存至附件中。 测试各类附件,例如图片、视频、文本等。 #### Does this PR introduce a user-facing change? ```release-note 增加通过链接转存第三方资源至附件库的接口 ```pull/6515/head
parent
21db06a507
commit
e5bbbb3b7b
|
@ -2250,6 +2250,36 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/apis/api.console.halo.run/v1alpha1/attachments/-/upload-from-url": {
|
||||
"post": {
|
||||
"operationId": "ExternalTransferAttachment",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UploadFromUrlRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"default": {
|
||||
"content": {
|
||||
"*/*": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Attachment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "default response"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"AttachmentV1alpha1Console"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/apis/api.console.halo.run/v1alpha1/attachments/upload": {
|
||||
"post": {
|
||||
"operationId": "UploadAttachment",
|
||||
|
@ -14136,6 +14166,47 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/apis/uc.api.content.halo.run/v1alpha1/attachments/-/upload-from-url": {
|
||||
"post": {
|
||||
"description": "Upload attachment from the given URL.",
|
||||
"operationId": "ExternalTransferAttachment_1",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Wait for permalink.",
|
||||
"in": "query",
|
||||
"name": "waitForPermalink",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UploadFromUrlRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"default": {
|
||||
"content": {
|
||||
"*/*": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Attachment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "default response"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"AttachmentV1alpha1Uc"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/apis/uc.api.content.halo.run/v1alpha1/posts": {
|
||||
"get": {
|
||||
"description": "List posts owned by the current user.",
|
||||
|
@ -22621,6 +22692,21 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"UploadFromUrlRequest": {
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "url"
|
||||
}
|
||||
}
|
||||
},
|
||||
"User": {
|
||||
"required": [
|
||||
"apiVersion",
|
||||
|
|
|
@ -117,6 +117,36 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/apis/api.console.halo.run/v1alpha1/attachments/-/upload-from-url": {
|
||||
"post": {
|
||||
"operationId": "ExternalTransferAttachment",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UploadFromUrlRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"default": {
|
||||
"content": {
|
||||
"*/*": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Attachment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "default response"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"AttachmentV1alpha1Console"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/apis/api.console.halo.run/v1alpha1/attachments/upload": {
|
||||
"post": {
|
||||
"operationId": "UploadAttachment",
|
||||
|
@ -6246,6 +6276,28 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"UploadFromUrlRequest": {
|
||||
"required": [
|
||||
"policyName",
|
||||
"url"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupName": {
|
||||
"type": "string"
|
||||
},
|
||||
"policyName": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "url"
|
||||
}
|
||||
}
|
||||
},
|
||||
"User": {
|
||||
"required": [
|
||||
"apiVersion",
|
||||
|
|
|
@ -57,6 +57,47 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/apis/uc.api.content.halo.run/v1alpha1/attachments/-/upload-from-url": {
|
||||
"post": {
|
||||
"description": "Upload attachment from the given URL.",
|
||||
"operationId": "ExternalTransferAttachment",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Wait for permalink.",
|
||||
"in": "query",
|
||||
"name": "waitForPermalink",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UploadFromUrlRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"default": {
|
||||
"content": {
|
||||
"*/*": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Attachment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "default response"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"AttachmentV1alpha1Uc"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/apis/uc.api.content.halo.run/v1alpha1/posts": {
|
||||
"get": {
|
||||
"description": "List posts owned by the current user.",
|
||||
|
@ -1943,6 +1984,21 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"UploadFromUrlRequest": {
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "url"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UserDevice": {
|
||||
"required": [
|
||||
"active",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package run.halo.app.core.extension.service;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
import java.util.function.Consumer;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
|
@ -91,4 +92,15 @@ public interface AttachmentService {
|
|||
*/
|
||||
Mono<URI> getSharedURL(Attachment attachment, Duration ttl);
|
||||
|
||||
/**
|
||||
* Transfer external links to attachments.
|
||||
*
|
||||
* @param url external url
|
||||
* @param policyName policy name
|
||||
* @param groupName group name
|
||||
* @param filename filename
|
||||
* @return attachment
|
||||
*/
|
||||
Mono<Attachment> uploadFromUrl(@NonNull URL url, @NonNull String policyName,
|
||||
String groupName, String filename);
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldS
|
|||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
|
@ -102,6 +104,29 @@ public class AttachmentEndpoint implements CustomEndpoint {
|
|||
))
|
||||
.response(responseBuilder().implementation(Attachment.class))
|
||||
.build())
|
||||
.POST("/attachments/-/upload-from-url", contentType(MediaType.APPLICATION_JSON),
|
||||
request -> request.bodyToMono(UploadFromUrlRequest.class)
|
||||
.flatMap(uploadFromUrlRequest -> {
|
||||
var url = uploadFromUrlRequest.url();
|
||||
var policyName = uploadFromUrlRequest.policyName();
|
||||
var groupName = uploadFromUrlRequest.groupName();
|
||||
var fileName = uploadFromUrlRequest.filename();
|
||||
return attachmentService.uploadFromUrl(url, policyName,
|
||||
groupName, fileName);
|
||||
})
|
||||
.flatMap(attachment -> ServerResponse.ok().bodyValue(attachment)),
|
||||
builder -> builder
|
||||
.operationId("ExternalTransferAttachment")
|
||||
.tag(tag)
|
||||
.requestBody(requestBodyBuilder()
|
||||
.required(true)
|
||||
.content(contentBuilder()
|
||||
.mediaType(MediaType.APPLICATION_JSON_VALUE)
|
||||
.schema(schemaBuilder().implementation(UploadFromUrlRequest.class))
|
||||
))
|
||||
.response(responseBuilder().implementation(Attachment.class))
|
||||
.build()
|
||||
)
|
||||
.GET("/attachments", this::search,
|
||||
builder -> {
|
||||
builder
|
||||
|
@ -275,6 +300,21 @@ public class AttachmentEndpoint implements CustomEndpoint {
|
|||
}
|
||||
}
|
||||
|
||||
public record UploadFromUrlRequest(@Schema(requiredMode = REQUIRED) URL url,
|
||||
@Schema(requiredMode = REQUIRED) String policyName,
|
||||
String groupName,
|
||||
String filename) {
|
||||
public UploadFromUrlRequest {
|
||||
if (Objects.isNull(url)) {
|
||||
throw new ServerWebInputException("Required url is missing.");
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(policyName)) {
|
||||
throw new ServerWebInputException("Policy name must not be blank");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(types = "object")
|
||||
public interface IUploadRequest {
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package run.halo.app.core.extension.service.impl;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.multipart.FilePart;
|
||||
|
@ -29,6 +33,7 @@ import run.halo.app.core.extension.attachment.endpoint.UploadOption;
|
|||
import run.halo.app.core.extension.service.AttachmentService;
|
||||
import run.halo.app.extension.ConfigMap;
|
||||
import run.halo.app.extension.ReactiveExtensionClient;
|
||||
import run.halo.app.infra.ReactiveUrlDataBufferFetcher;
|
||||
import run.halo.app.plugin.extensionpoint.ExtensionGetter;
|
||||
|
||||
@Component
|
||||
|
@ -38,10 +43,14 @@ public class DefaultAttachmentService implements AttachmentService {
|
|||
|
||||
private final ExtensionGetter extensionGetter;
|
||||
|
||||
private final ReactiveUrlDataBufferFetcher dataBufferFetcher;
|
||||
|
||||
public DefaultAttachmentService(ReactiveExtensionClient client,
|
||||
ExtensionGetter extensionGetter) {
|
||||
ExtensionGetter extensionGetter,
|
||||
ReactiveUrlDataBufferFetcher dataBufferFetcher) {
|
||||
this.client = client;
|
||||
this.extensionGetter = extensionGetter;
|
||||
this.dataBufferFetcher = dataBufferFetcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,6 +139,45 @@ public class DefaultAttachmentService implements AttachmentService {
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Attachment> uploadFromUrl(@NonNull URL url, @NonNull String policyName,
|
||||
String groupName, String filename) {
|
||||
var uri = URI.create(url.toString());
|
||||
AtomicReference<MediaType> mediaTypeRef = new AtomicReference<>();
|
||||
AtomicReference<String> fileNameRef = new AtomicReference<>(filename);
|
||||
|
||||
Mono<Flux<DataBuffer>> contentMono = dataBufferFetcher.head(uri)
|
||||
.map(response -> {
|
||||
var httpHeaders = response.getHeaders();
|
||||
if (!StringUtils.hasText(fileNameRef.get())) {
|
||||
fileNameRef.set(getExternalUrlFilename(uri, httpHeaders));
|
||||
}
|
||||
MediaType contentType = httpHeaders.getContentType();
|
||||
mediaTypeRef.set(contentType);
|
||||
return response;
|
||||
})
|
||||
.map(response -> dataBufferFetcher.fetch(uri));
|
||||
|
||||
return contentMono.flatMap(
|
||||
(content) -> upload(policyName, groupName, fileNameRef.get(), content,
|
||||
mediaTypeRef.get())
|
||||
)
|
||||
.onErrorResume(throwable -> Mono.error(
|
||||
new ServerWebInputException(
|
||||
"Failed to transfer the attachment from the external URL."))
|
||||
);
|
||||
}
|
||||
|
||||
private static String getExternalUrlFilename(URI externalUrl, HttpHeaders httpHeaders) {
|
||||
String fileName = httpHeaders.getContentDisposition().getFilename();
|
||||
if (!StringUtils.hasText(fileName)) {
|
||||
var path = externalUrl.getPath();
|
||||
fileName = Paths.get(path).getFileName().toString();
|
||||
}
|
||||
// TODO get file extension from media type
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private <T> Mono<T> authenticationConsumer(Function<Authentication, Mono<T>> func) {
|
||||
return ReactiveSecurityContextHolder.getContext()
|
||||
.switchIfEmpty(Mono.error(() -> new ResponseStatusException(HttpStatus.UNAUTHORIZED,
|
||||
|
|
|
@ -8,10 +8,13 @@ import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
|
|||
import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder;
|
||||
import static org.springdoc.core.fn.builders.schema.Builder.schemaBuilder;
|
||||
import static org.springdoc.webflux.core.fn.SpringdocRouteBuilder.route;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.contentType;
|
||||
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
|
@ -79,53 +82,106 @@ public class UcPostAttachmentEndpoint implements CustomEndpoint {
|
|||
)
|
||||
.response(responseBuilder().implementation(Attachment.class))
|
||||
)
|
||||
.POST("/attachments/-/upload-from-url", contentType(MediaType.APPLICATION_JSON),
|
||||
this::uploadFromUrlForPost,
|
||||
builder -> builder
|
||||
.operationId("ExternalTransferAttachment")
|
||||
.description("Upload attachment from the given URL.")
|
||||
.tag(tag)
|
||||
.parameter(parameterBuilder()
|
||||
.name("waitForPermalink")
|
||||
.description("Wait for permalink.")
|
||||
.in(ParameterIn.QUERY)
|
||||
.required(false)
|
||||
.implementation(boolean.class))
|
||||
.requestBody(requestBodyBuilder()
|
||||
.required(true)
|
||||
.content(contentBuilder()
|
||||
.mediaType(MediaType.APPLICATION_JSON_VALUE)
|
||||
.schema(schemaBuilder().implementation(UploadFromUrlRequest.class))
|
||||
))
|
||||
.response(responseBuilder().implementation(Attachment.class))
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Mono<ServerResponse> uploadFromUrlForPost(ServerRequest request) {
|
||||
var uploadFromUrlRequestMono = request.bodyToMono(UploadFromUrlRequest.class);
|
||||
|
||||
var uploadAttachment = getPostSettingMono()
|
||||
.flatMap(postSetting -> uploadFromUrlRequestMono.flatMap(
|
||||
uploadFromUrlRequest -> {
|
||||
var url = uploadFromUrlRequest.url();
|
||||
var fileName = uploadFromUrlRequest.filename();
|
||||
return attachmentService.uploadFromUrl(url,
|
||||
postSetting.getAttachmentPolicyName(),
|
||||
postSetting.getAttachmentGroupName(),
|
||||
fileName
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
var waitForPermalink = request.queryParam("waitForPermalink")
|
||||
.map(Boolean::valueOf)
|
||||
.orElse(false);
|
||||
if (waitForPermalink) {
|
||||
uploadAttachment = waitForPermalink(uploadAttachment);
|
||||
}
|
||||
return ServerResponse.ok().body(uploadAttachment, Attachment.class);
|
||||
}
|
||||
|
||||
private Mono<ServerResponse> createAttachmentForPost(ServerRequest request) {
|
||||
var postAttachmentRequestMono = request.body(BodyExtractors.toMultipartData())
|
||||
.map(PostAttachmentRequest::from)
|
||||
.cache();
|
||||
|
||||
var postSettingMono = systemSettingFetcher.fetchPost()
|
||||
.<SystemSetting.Post>handle((postSetting, sink) -> {
|
||||
var attachmentPolicyName = postSetting.getAttachmentPolicyName();
|
||||
if (StringUtils.isBlank(attachmentPolicyName)) {
|
||||
sink.error(new ServerWebInputException(
|
||||
"Please configure storage policy for post attachment first."));
|
||||
return;
|
||||
}
|
||||
sink.next(postSetting);
|
||||
});
|
||||
|
||||
// get settings
|
||||
var createdAttachment = postSettingMono.flatMap(postSetting -> postAttachmentRequestMono
|
||||
.flatMap(postAttachmentRequest -> getCurrentUser().flatMap(
|
||||
username -> attachmentService.upload(username,
|
||||
postSetting.getAttachmentPolicyName(),
|
||||
postSetting.getAttachmentGroupName(),
|
||||
postAttachmentRequest.file(),
|
||||
linkWith(postAttachmentRequest)))));
|
||||
var createdAttachment =
|
||||
getPostSettingMono().flatMap(postSetting -> postAttachmentRequestMono
|
||||
.flatMap(postAttachmentRequest -> getCurrentUser().flatMap(
|
||||
username -> attachmentService.upload(username,
|
||||
postSetting.getAttachmentPolicyName(),
|
||||
postSetting.getAttachmentGroupName(),
|
||||
postAttachmentRequest.file(),
|
||||
linkWith(postAttachmentRequest)))));
|
||||
|
||||
var waitForPermalink = request.queryParam("waitForPermalink")
|
||||
.map(Boolean::valueOf)
|
||||
.orElse(false);
|
||||
if (waitForPermalink) {
|
||||
createdAttachment = createdAttachment.flatMap(attachment ->
|
||||
attachmentService.getPermalink(attachment)
|
||||
.doOnNext(permalink -> {
|
||||
var status = attachment.getStatus();
|
||||
if (status == null) {
|
||||
status = new Attachment.AttachmentStatus();
|
||||
attachment.setStatus(status);
|
||||
}
|
||||
status.setPermalink(permalink.toString());
|
||||
})
|
||||
.thenReturn(attachment));
|
||||
createdAttachment = waitForPermalink(createdAttachment);
|
||||
}
|
||||
return ServerResponse.ok().body(createdAttachment, Attachment.class);
|
||||
}
|
||||
|
||||
private Mono<Attachment> waitForPermalink(Mono<Attachment> createdAttachment) {
|
||||
createdAttachment = createdAttachment.flatMap(attachment ->
|
||||
attachmentService.getPermalink(attachment)
|
||||
.doOnNext(permalink -> {
|
||||
var status = attachment.getStatus();
|
||||
if (status == null) {
|
||||
status = new Attachment.AttachmentStatus();
|
||||
attachment.setStatus(status);
|
||||
}
|
||||
status.setPermalink(permalink.toString());
|
||||
})
|
||||
.thenReturn(attachment));
|
||||
return createdAttachment;
|
||||
}
|
||||
|
||||
private Mono<SystemSetting.Post> getPostSettingMono() {
|
||||
return systemSettingFetcher.fetchPost().handle((postSetting, sink) -> {
|
||||
var attachmentPolicyName = postSetting.getAttachmentPolicyName();
|
||||
if (StringUtils.isBlank(attachmentPolicyName)) {
|
||||
sink.error(new ServerWebInputException(
|
||||
"Please configure storage policy for post attachment first."));
|
||||
return;
|
||||
}
|
||||
sink.next(postSetting);
|
||||
});
|
||||
}
|
||||
|
||||
private Consumer<Attachment> linkWith(PostAttachmentRequest request) {
|
||||
return attachment -> {
|
||||
var labels = attachment.getMetadata().getLabels();
|
||||
|
@ -165,6 +221,15 @@ public class UcPostAttachmentEndpoint implements CustomEndpoint {
|
|||
return GroupVersion.parseAPIVersion("uc.api.content.halo.run/v1alpha1");
|
||||
}
|
||||
|
||||
public record UploadFromUrlRequest(@Schema(requiredMode = REQUIRED) URL url,
|
||||
String filename) {
|
||||
public UploadFromUrlRequest {
|
||||
if (Objects.isNull(url)) {
|
||||
throw new ServerWebInputException("Required url is missing.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(types = "object")
|
||||
public record PostAttachmentRequest(
|
||||
@Schema(requiredMode = REQUIRED, description = "Attachment data.")
|
||||
|
|
|
@ -3,10 +3,12 @@ package run.halo.app.infra;
|
|||
import java.net.URI;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
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.WebClient;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
|
||||
/**
|
||||
|
@ -31,4 +33,12 @@ public class DefaultReactiveUrlDataBufferFetcher implements ReactiveUrlDataBuffe
|
|||
.retrieve()
|
||||
.bodyToFlux(DataBuffer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ResponseEntity<Void>> head(URI uri) {
|
||||
return webClient.head()
|
||||
.uri(uri)
|
||||
.retrieve()
|
||||
.toBodilessEntity();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@ package run.halo.app.infra;
|
|||
|
||||
import java.net.URI;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* <p>{@link DataBuffer} stream fetcher from uri.</p>
|
||||
|
@ -10,7 +12,6 @@ import reactor.core.publisher.Flux;
|
|||
* @author guqing
|
||||
* @since 2.6.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ReactiveUrlDataBufferFetcher {
|
||||
|
||||
/**
|
||||
|
@ -20,4 +21,12 @@ public interface ReactiveUrlDataBufferFetcher {
|
|||
* @return data buffer flux
|
||||
*/
|
||||
Flux<DataBuffer> fetch(URI uri);
|
||||
|
||||
/**
|
||||
* <p>Get head of the uri.</p>
|
||||
*
|
||||
* @param uri uri to fetch
|
||||
* @return response entity
|
||||
*/
|
||||
Mono<ResponseEntity<Void>> head(URI uri);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package run.halo.app.infra.utils;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import java.util.regex.Pattern;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -9,6 +10,20 @@ public final class FileNameUtils {
|
|||
private FileNameUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the file name has an extension.
|
||||
*
|
||||
* @param filename is name of file.
|
||||
* @return True if file name has extension, otherwise false.
|
||||
*/
|
||||
public static boolean hasFileExtension(String filename) {
|
||||
if (filename == null || filename.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
var extensionRegex = ".*\\.[a-zA-Z0-9]+$";
|
||||
return Pattern.matches(extensionRegex, filename);
|
||||
}
|
||||
|
||||
public static String removeFileExtension(String filename, boolean removeAllExtensions) {
|
||||
if (filename == null || filename.isEmpty()) {
|
||||
return filename;
|
||||
|
|
|
@ -17,10 +17,15 @@ rules:
|
|||
- apiGroups: [ "api.console.halo.run" ]
|
||||
resources: [ "attachments" ]
|
||||
verbs: [ "*" ]
|
||||
- apiGroups: [ "api.console.halo.run" ]
|
||||
resources: [ "attachments/upload-from-url" ]
|
||||
verbs: [ "create" ]
|
||||
- apiGroups: [ "" ]
|
||||
resources: [ "settings" ]
|
||||
verbs: [ "get" ]
|
||||
- nonResourceURLs: [ "/apis/api.console.halo.run/v1alpha1/attachments/upload" ]
|
||||
- nonResourceURLs: [
|
||||
"/apis/api.console.halo.run/v1alpha1/attachments/upload"
|
||||
]
|
||||
verbs: [ "create" ]
|
||||
---
|
||||
apiVersion: v1alpha1
|
||||
|
|
|
@ -114,3 +114,6 @@ rules:
|
|||
- apiGroups: [ "uc.api.content.halo.run" ]
|
||||
resources: [ "attachments" ]
|
||||
verbs: [ "create", "update", "delete" ]
|
||||
- apiGroups: [ "uc.api.content.halo.run" ]
|
||||
resources: [ "attachments/upload-from-url" ]
|
||||
verbs: [ "create" ]
|
||||
|
|
|
@ -18,8 +18,11 @@ import org.junit.jupiter.api.Test;
|
|||
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.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.MultipartBodyBuilder;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
|
@ -35,6 +38,7 @@ import run.halo.app.extension.ListResult;
|
|||
import run.halo.app.extension.Metadata;
|
||||
import run.halo.app.extension.PageRequest;
|
||||
import run.halo.app.extension.ReactiveExtensionClient;
|
||||
import run.halo.app.infra.ReactiveUrlDataBufferFetcher;
|
||||
import run.halo.app.plugin.extensionpoint.ExtensionGetter;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
|
@ -46,13 +50,17 @@ class AttachmentEndpointTest {
|
|||
@Mock
|
||||
ExtensionGetter extensionGetter;
|
||||
|
||||
@Mock
|
||||
ReactiveUrlDataBufferFetcher dataBufferFetcher;
|
||||
|
||||
AttachmentEndpoint endpoint;
|
||||
|
||||
WebTestClient webClient;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
var attachmentService = new DefaultAttachmentService(client, extensionGetter);
|
||||
var attachmentService =
|
||||
new DefaultAttachmentService(client, extensionGetter, dataBufferFetcher);
|
||||
endpoint = new AttachmentEndpoint(attachmentService, client);
|
||||
webClient = WebTestClient.bindToRouterFunction(endpoint.endpoint())
|
||||
.apply(springSecurity())
|
||||
|
@ -263,4 +271,78 @@ class AttachmentEndpointTest {
|
|||
verify(client).listBy(eq(Attachment.class), any(), any(PageRequest.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class ExternalTransferTest {
|
||||
@Test
|
||||
void shouldResponseErrorIfNoPermalinkProvided() {
|
||||
webClient
|
||||
.mutateWith(mockUser("fake-user").password("fake-password"))
|
||||
.post()
|
||||
.uri("/attachments/-/upload-from-url")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(Map.of("policyName", "fake-policy"))
|
||||
.exchange()
|
||||
.expectStatus().isBadRequest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTransferSuccessfully() {
|
||||
var policySpec = new PolicySpec();
|
||||
policySpec.setConfigMapName("fake-configmap");
|
||||
var policyMetadata = new Metadata();
|
||||
policyMetadata.setName("fake-policy");
|
||||
var policy = new Policy();
|
||||
policy.setSpec(policySpec);
|
||||
policy.setMetadata(policyMetadata);
|
||||
|
||||
var cm = new ConfigMap();
|
||||
var cmMetadata = new Metadata();
|
||||
cmMetadata.setName("fake-configmap");
|
||||
cm.setData(Map.of());
|
||||
|
||||
when(client.get(Policy.class, "fake-policy")).thenReturn(Mono.just(policy));
|
||||
when(client.get(ConfigMap.class, "fake-configmap")).thenReturn(Mono.just(cm));
|
||||
|
||||
var handler = mock(AttachmentHandler.class);
|
||||
var metadata = new Metadata();
|
||||
metadata.setName("fake-attachment");
|
||||
var attachment = new Attachment();
|
||||
attachment.setMetadata(metadata);
|
||||
|
||||
ResponseEntity<Void> response = new ResponseEntity<>(HttpStatusCode.valueOf(200));
|
||||
DataBuffer dataBuffer = mock(DataBuffer.class);
|
||||
|
||||
when(handler.upload(any())).thenReturn(Mono.just(attachment));
|
||||
when(dataBufferFetcher.head(any())).thenReturn(Mono.just(response));
|
||||
when(dataBufferFetcher.fetch(any())).thenReturn(Flux.just(dataBuffer));
|
||||
when(extensionGetter.getExtensions(AttachmentHandler.class))
|
||||
.thenReturn(Flux.just(handler));
|
||||
when(client.create(attachment)).thenReturn(Mono.just(attachment));
|
||||
|
||||
var fakeValue =
|
||||
Map.of("policyName", "fake-policy", "url",
|
||||
"http://localhost:8090/fake-url.jpg");
|
||||
webClient
|
||||
.mutateWith(mockUser("fake-user").password("fake-password"))
|
||||
.post()
|
||||
.uri("/attachments/-/upload-from-url")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(fakeValue)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody()
|
||||
.jsonPath("$.metadata.name").isEqualTo("fake-attachment")
|
||||
.jsonPath("$.spec.ownerName").isEqualTo("fake-user")
|
||||
.jsonPath("$.spec.policyName").isEqualTo("fake-policy")
|
||||
;
|
||||
|
||||
verify(client).get(Policy.class, "fake-policy");
|
||||
verify(client).get(ConfigMap.class, "fake-configmap");
|
||||
verify(client).create(attachment);
|
||||
verify(dataBufferFetcher).head(any());
|
||||
verify(dataBufferFetcher).fetch(any());
|
||||
verify(handler).upload(any());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -320,6 +320,7 @@ models/totp-auth-link-response.ts
|
|||
models/totp-request.ts
|
||||
models/two-factor-auth-settings.ts
|
||||
models/upgrade-from-uri-request.ts
|
||||
models/upload-from-url-request.ts
|
||||
models/user-connection-list.ts
|
||||
models/user-connection-spec.ts
|
||||
models/user-connection.ts
|
||||
|
|
|
@ -25,12 +25,57 @@ import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError, ope
|
|||
import { Attachment } from '../models';
|
||||
// @ts-ignore
|
||||
import { AttachmentList } from '../models';
|
||||
// @ts-ignore
|
||||
import { UploadFromUrlRequest } from '../models';
|
||||
/**
|
||||
* AttachmentV1alpha1ConsoleApi - axios parameter creator
|
||||
* @export
|
||||
*/
|
||||
export const AttachmentV1alpha1ConsoleApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {UploadFromUrlRequest} uploadFromUrlRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
externalTransferAttachment: async (uploadFromUrlRequest: UploadFromUrlRequest, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'uploadFromUrlRequest' is not null or undefined
|
||||
assertParamExists('externalTransferAttachment', 'uploadFromUrlRequest', uploadFromUrlRequest)
|
||||
const localVarPath = `/apis/api.console.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);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication basicAuth required
|
||||
// http basic authentication required
|
||||
setBasicAuthToObject(localVarRequestOptions, configuration)
|
||||
|
||||
// authentication bearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(uploadFromUrlRequest, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {number} [page] Page number. Default is 0.
|
||||
|
@ -178,6 +223,18 @@ export const AttachmentV1alpha1ConsoleApiAxiosParamCreator = function (configura
|
|||
export const AttachmentV1alpha1ConsoleApiFp = function(configuration?: Configuration) {
|
||||
const localVarAxiosParamCreator = AttachmentV1alpha1ConsoleApiAxiosParamCreator(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {UploadFromUrlRequest} uploadFromUrlRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async externalTransferAttachment(uploadFromUrlRequest: UploadFromUrlRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Attachment>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.externalTransferAttachment(uploadFromUrlRequest, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['AttachmentV1alpha1ConsoleApi.externalTransferAttachment']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {number} [page] Page number. Default is 0.
|
||||
|
@ -221,6 +278,15 @@ export const AttachmentV1alpha1ConsoleApiFp = function(configuration?: Configura
|
|||
export const AttachmentV1alpha1ConsoleApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||
const localVarFp = AttachmentV1alpha1ConsoleApiFp(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {AttachmentV1alpha1ConsoleApiExternalTransferAttachmentRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
externalTransferAttachment(requestParameters: AttachmentV1alpha1ConsoleApiExternalTransferAttachmentRequest, options?: RawAxiosRequestConfig): AxiosPromise<Attachment> {
|
||||
return localVarFp.externalTransferAttachment(requestParameters.uploadFromUrlRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {AttachmentV1alpha1ConsoleApiSearchAttachmentsRequest} requestParameters Request parameters.
|
||||
|
@ -242,6 +308,20 @@ export const AttachmentV1alpha1ConsoleApiFactory = function (configuration?: Con
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Request parameters for externalTransferAttachment operation in AttachmentV1alpha1ConsoleApi.
|
||||
* @export
|
||||
* @interface AttachmentV1alpha1ConsoleApiExternalTransferAttachmentRequest
|
||||
*/
|
||||
export interface AttachmentV1alpha1ConsoleApiExternalTransferAttachmentRequest {
|
||||
/**
|
||||
*
|
||||
* @type {UploadFromUrlRequest}
|
||||
* @memberof AttachmentV1alpha1ConsoleApiExternalTransferAttachment
|
||||
*/
|
||||
readonly uploadFromUrlRequest: UploadFromUrlRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for searchAttachments operation in AttachmentV1alpha1ConsoleApi.
|
||||
* @export
|
||||
|
@ -340,6 +420,17 @@ export interface AttachmentV1alpha1ConsoleApiUploadAttachmentRequest {
|
|||
* @extends {BaseAPI}
|
||||
*/
|
||||
export class AttachmentV1alpha1ConsoleApi extends BaseAPI {
|
||||
/**
|
||||
*
|
||||
* @param {AttachmentV1alpha1ConsoleApiExternalTransferAttachmentRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof AttachmentV1alpha1ConsoleApi
|
||||
*/
|
||||
public externalTransferAttachment(requestParameters: AttachmentV1alpha1ConsoleApiExternalTransferAttachmentRequest, options?: RawAxiosRequestConfig) {
|
||||
return AttachmentV1alpha1ConsoleApiFp(this.configuration).externalTransferAttachment(requestParameters.uploadFromUrlRequest, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AttachmentV1alpha1ConsoleApiSearchAttachmentsRequest} requestParameters Request parameters.
|
||||
|
|
|
@ -23,6 +23,8 @@ import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObj
|
|||
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base';
|
||||
// @ts-ignore
|
||||
import { Attachment } from '../models';
|
||||
// @ts-ignore
|
||||
import { UploadFromUrlRequest } from '../models';
|
||||
/**
|
||||
* AttachmentV1alpha1UcApi - axios parameter creator
|
||||
* @export
|
||||
|
@ -87,6 +89,54 @@ export const AttachmentV1alpha1UcApiAxiosParamCreator = function (configuration?
|
|||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = localVarFormParams;
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Upload attachment from the given URL.
|
||||
* @param {UploadFromUrlRequest} uploadFromUrlRequest
|
||||
* @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)
|
||||
const localVarPath = `/apis/uc.api.content.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);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication basicAuth required
|
||||
// http basic authentication required
|
||||
setBasicAuthToObject(localVarRequestOptions, configuration)
|
||||
|
||||
// authentication bearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
if (waitForPermalink !== undefined) {
|
||||
localVarQueryParameter['waitForPermalink'] = waitForPermalink;
|
||||
}
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(uploadFromUrlRequest, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
|
@ -117,6 +167,19 @@ export const AttachmentV1alpha1UcApiFp = function(configuration?: Configuration)
|
|||
const localVarOperationServerBasePath = operationServerMap['AttachmentV1alpha1UcApi.createAttachmentForPost']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
* Upload attachment from the given URL.
|
||||
* @param {UploadFromUrlRequest} uploadFromUrlRequest
|
||||
* @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);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['AttachmentV1alpha1UcApi.externalTransferAttachment1']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -136,6 +199,15 @@ export const AttachmentV1alpha1UcApiFactory = function (configuration?: Configur
|
|||
createAttachmentForPost(requestParameters: AttachmentV1alpha1UcApiCreateAttachmentForPostRequest, options?: RawAxiosRequestConfig): AxiosPromise<Attachment> {
|
||||
return localVarFp.createAttachmentForPost(requestParameters.file, requestParameters.waitForPermalink, requestParameters.postName, requestParameters.singlePageName, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Upload attachment from the given URL.
|
||||
* @param {AttachmentV1alpha1UcApiExternalTransferAttachment1Request} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
externalTransferAttachment1(requestParameters: AttachmentV1alpha1UcApiExternalTransferAttachment1Request, options?: RawAxiosRequestConfig): AxiosPromise<Attachment> {
|
||||
return localVarFp.externalTransferAttachment1(requestParameters.uploadFromUrlRequest, requestParameters.waitForPermalink, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -174,6 +246,27 @@ export interface AttachmentV1alpha1UcApiCreateAttachmentForPostRequest {
|
|||
readonly singlePageName?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for externalTransferAttachment1 operation in AttachmentV1alpha1UcApi.
|
||||
* @export
|
||||
* @interface AttachmentV1alpha1UcApiExternalTransferAttachment1Request
|
||||
*/
|
||||
export interface AttachmentV1alpha1UcApiExternalTransferAttachment1Request {
|
||||
/**
|
||||
*
|
||||
* @type {UploadFromUrlRequest}
|
||||
* @memberof AttachmentV1alpha1UcApiExternalTransferAttachment1
|
||||
*/
|
||||
readonly uploadFromUrlRequest: UploadFromUrlRequest
|
||||
|
||||
/**
|
||||
* Wait for permalink.
|
||||
* @type {boolean}
|
||||
* @memberof AttachmentV1alpha1UcApiExternalTransferAttachment1
|
||||
*/
|
||||
readonly waitForPermalink?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* AttachmentV1alpha1UcApi - object-oriented interface
|
||||
* @export
|
||||
|
@ -191,5 +284,16 @@ export class AttachmentV1alpha1UcApi extends BaseAPI {
|
|||
public createAttachmentForPost(requestParameters: AttachmentV1alpha1UcApiCreateAttachmentForPostRequest, options?: RawAxiosRequestConfig) {
|
||||
return AttachmentV1alpha1UcApiFp(this.configuration).createAttachmentForPost(requestParameters.file, requestParameters.waitForPermalink, requestParameters.postName, requestParameters.singlePageName, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload attachment from the given URL.
|
||||
* @param {AttachmentV1alpha1UcApiExternalTransferAttachment1Request} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -236,6 +236,7 @@ export * from './totp-auth-link-response';
|
|||
export * from './totp-request';
|
||||
export * from './two-factor-auth-settings';
|
||||
export * from './upgrade-from-uri-request';
|
||||
export * from './upload-from-url-request';
|
||||
export * from './user';
|
||||
export * from './user-connection';
|
||||
export * from './user-connection-list';
|
||||
|
|
|
@ -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.19.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 UploadFromUrlRequest
|
||||
*/
|
||||
export interface UploadFromUrlRequest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UploadFromUrlRequest
|
||||
*/
|
||||
'filename'?: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof UploadFromUrlRequest
|
||||
*/
|
||||
'url': string;
|
||||
}
|
||||
|
Loading…
Reference in New Issue