partial refactoring
This commit is contained in:
parent
a125798e1a
commit
6fc507f056
|
@ -1,2 +1,6 @@
|
|||
# dnet-directindex-application
|
||||
|
||||
### SWORD Deposit Protocol v.3
|
||||
* *[Main site](https://sword.cottagelabs.com/swordv3/)*
|
||||
* *[Protocol Specification](https://swordapp.github.io/swordv3/swordv3.html)*
|
||||
* *[Protocol Behaviours](https://swordapp.github.io/swordv3/swordv3-behaviours.html)*
|
||||
|
|
|
@ -2,6 +2,8 @@ package eu.dnetlib.app.directindex.service;
|
|||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import eu.dnetlib.app.directindex.sword.model.SwordMetadataDocument;
|
||||
|
||||
@Service
|
||||
public class DirectIndexService {
|
||||
|
||||
|
@ -15,4 +17,9 @@ public class DirectIndexService {
|
|||
|
||||
}
|
||||
|
||||
public void prepareMetadataInsertion(final SwordMetadataDocument body) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package eu.dnetlib.app.directindex.sword;
|
||||
|
||||
public class SwordException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -6401402258941503950L;
|
||||
|
||||
private final int httpCode;
|
||||
private final String httpMessage;
|
||||
|
||||
public SwordException(final int httpCode, final String httpMessage) {
|
||||
this.httpCode = httpCode;
|
||||
this.httpMessage = httpMessage;
|
||||
}
|
||||
|
||||
public int getHttpCode() {
|
||||
return httpCode;
|
||||
}
|
||||
|
||||
public String getHttpMessage() {
|
||||
return httpMessage;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package eu.dnetlib.app.directindex.sword;
|
||||
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController("/api/directindex/file")
|
||||
public class SwordFileSetUrlController {
|
||||
|
||||
@PutMapping("/")
|
||||
public @ResponseBody Object replaceFileSet(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("Content-Length") final String contentLength,
|
||||
@RequestHeader("Content-Type") final String contentType,
|
||||
@RequestHeader("Digest") final String digest,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
|
||||
@RequestHeader(value = "Packaging", defaultValue = "http://purl.org/net/sword/3.0/package/Binary") final String packaging) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@DeleteMapping("/")
|
||||
public @ResponseBody Object deleteFileSet(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package eu.dnetlib.app.directindex.sword;
|
||||
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController("/api/directindex/files")
|
||||
public class SwordFileUrlController {
|
||||
|
||||
@GetMapping("/")
|
||||
public @ResponseBody Object getFile(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@PutMapping("/")
|
||||
public @ResponseBody Object replaceFile(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("Content-Length") final String contentLength,
|
||||
@RequestHeader("Content-Type") final String contentType,
|
||||
@RequestHeader("Digest") final String digest,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@DeleteMapping("/")
|
||||
public @ResponseBody Object deleteFile(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
package eu.dnetlib.app.directindex.sword;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import eu.dnetlib.app.directindex.service.DirectIndexService;
|
||||
import eu.dnetlib.app.directindex.sword.model.SwordMetadataDocument;
|
||||
|
||||
@RestController("/api/directindex/metadata")
|
||||
public class SwordMetadataUrlController {
|
||||
|
||||
@Autowired
|
||||
private DirectIndexService service;
|
||||
|
||||
@GetMapping("/")
|
||||
public ResponseEntity<SwordMetadataDocument> getMetadata(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
|
||||
// TODO
|
||||
|
||||
final SwordMetadataDocument metadata = null;
|
||||
|
||||
final HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.set("ETag", null);
|
||||
|
||||
return new ResponseEntity<>(metadata, responseHeaders, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PutMapping("/")
|
||||
public ResponseEntity<Void> replaceMetadata(@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("Content-Length") final String contentLength,
|
||||
@RequestHeader("Content-Type") final String contentType,
|
||||
@RequestHeader("Digest") final String digest,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
|
||||
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat,
|
||||
@RequestBody final SwordMetadataDocument document) {
|
||||
|
||||
service.prepareMetadataReplacement();
|
||||
|
||||
// TODO
|
||||
final HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.set("ETag", null);
|
||||
|
||||
return new ResponseEntity<>(responseHeaders, HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@DeleteMapping("/")
|
||||
public ResponseEntity<Void> deleteMetadata(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
|
||||
service.prepareMetadataDeletion();
|
||||
|
||||
return new ResponseEntity<>(HttpStatus.ACCEPTED);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package eu.dnetlib.app.directindex.sword;
|
||||
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController("/api/directindex/obj")
|
||||
public class SwordObjectUrlController {
|
||||
|
||||
@GetMapping("/")
|
||||
public @ResponseBody Object getObjectStatus(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public @ResponseBody Object appendObjectData(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("Content-Length") final String contentLength,
|
||||
@RequestHeader("Content-Type") final String contentType,
|
||||
@RequestHeader("Digest") final String digest,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader(value = "In-Progress", defaultValue = "false") final boolean inProgress,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
|
||||
@RequestHeader(value = "Packaging", defaultValue = "http://purl.org/net/sword/3.0/package/Binary") final String packaging,
|
||||
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@PutMapping("/")
|
||||
public @ResponseBody Object replaceObject(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("Content-Length") final String contentLength,
|
||||
@RequestHeader("Content-Type") final String contentType,
|
||||
@RequestHeader("Digest") final String digest,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader(value = "In-Progress", defaultValue = "false") final boolean inProgress,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
|
||||
@RequestHeader(value = "Packaging", defaultValue = "http://purl.org/net/sword/3.0/package/Binary") final String packaging,
|
||||
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@DeleteMapping("/")
|
||||
public @ResponseBody Object deleteObject(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,44 +1,62 @@
|
|||
package eu.dnetlib.app.directindex.sword;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import eu.dnetlib.app.directindex.service.DirectIndexService;
|
||||
import eu.dnetlib.app.directindex.sword.model.SwordError;
|
||||
import eu.dnetlib.app.directindex.sword.model.SwordMetadataDocument;
|
||||
import eu.dnetlib.app.directindex.sword.model.SwordService;
|
||||
import eu.dnetlib.app.directindex.sword.model.SwordStatusDocument;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@RestController("/api/directindex/")
|
||||
@RestController("/api/directindex/sword/3.0")
|
||||
public class SwordServiceUrlController {
|
||||
|
||||
@Autowired
|
||||
private DirectIndexService service;
|
||||
|
||||
@GetMapping("/")
|
||||
public SwordService getServiceDocument(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
public SwordService getServiceDocument() {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public ResponseEntity<SwordStatusDocument> makeNewObject(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("Content-Length") final String contentLength,
|
||||
public ResponseEntity<SwordStatusDocument> addMetadata(
|
||||
@RequestHeader("Content-Type") final String contentType,
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("Digest") final String digest,
|
||||
@RequestHeader(value = "In-Progress", defaultValue = "false") final boolean inProgress,
|
||||
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
|
||||
@RequestHeader(value = "Packaging", defaultValue = "http://purl.org/net/sword/3.0/package/Binary") final String packaging,
|
||||
@RequestHeader("Slug") final String slug,
|
||||
@RequestBody final String json) {
|
||||
|
||||
// Content used to create new Object. This can be one of: Metadata, By-Reference, Metadata+By-Reference, Binary File, Packaged
|
||||
// Content, Empty Body
|
||||
@RequestBody final Object content) {
|
||||
// TODO: DIGEST Evaluate if the digest (md5) of the json string
|
||||
|
||||
if (!MediaType.APPLICATION_JSON_VALUE.equals(contentType)) { return new ResponseEntity<>(HttpStatus.UNSUPPORTED_MEDIA_TYPE); }
|
||||
|
||||
if (!"attachment; metadata=true".equals(contentDisposition) || inProgress) { return new ResponseEntity<>(HttpStatus.METHOD_NOT_ALLOWED); }
|
||||
|
||||
if (!"OAF".equals(mdFormat)) { return new ResponseEntity<>(HttpStatus.UNSUPPORTED_MEDIA_TYPE); }
|
||||
|
||||
// TODO
|
||||
final SwordStatusDocument status = null;
|
||||
|
@ -47,12 +65,75 @@ public class SwordServiceUrlController {
|
|||
responseHeaders.setLocation(null);
|
||||
responseHeaders.set("ETag", null);
|
||||
|
||||
return new ResponseEntity<>(status, responseHeaders, isCreated() ? HttpStatus.CREATED : HttpStatus.ACCEPTED);
|
||||
try {
|
||||
service.prepareMetadataInsertion(parseMetadata(json));
|
||||
} catch (final JsonProcessingException e) {
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
return new ResponseEntity<>(status, responseHeaders, HttpStatus.ACCEPTED);
|
||||
|
||||
}
|
||||
|
||||
private boolean isCreated() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
@GetMapping("/metadata")
|
||||
public ResponseEntity<SwordMetadataDocument> getMetadata() {
|
||||
|
||||
// TODO
|
||||
|
||||
final SwordMetadataDocument metadata = null;
|
||||
|
||||
final HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.set("ETag", null);
|
||||
|
||||
return new ResponseEntity<>(metadata, responseHeaders, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PutMapping("/metadata")
|
||||
public ResponseEntity<Void> replaceMetadata(
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("Content-Length") final String contentLength,
|
||||
@RequestHeader("Content-Type") final String contentType,
|
||||
@RequestHeader("Digest") final String digest,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader(value = "Metadata-Format", defaultValue = "http://purl.org/net/sword/3.0/types/Metadata") final String mdFormat,
|
||||
@RequestBody final SwordMetadataDocument document) {
|
||||
|
||||
service.prepareMetadataReplacement();
|
||||
|
||||
// TODO
|
||||
final HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.set("ETag", null);
|
||||
|
||||
return new ResponseEntity<>(responseHeaders, HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@DeleteMapping("/metadata")
|
||||
public ResponseEntity<Void> deleteMetadata(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("If-Match") final boolean ifMatch,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
|
||||
service.prepareMetadataDeletion();
|
||||
|
||||
return new ResponseEntity<>(HttpStatus.ACCEPTED);
|
||||
|
||||
}
|
||||
|
||||
private SwordMetadataDocument parseMetadata(final String json) throws JsonProcessingException, JsonMappingException {
|
||||
return new ObjectMapper().readValue(json, SwordMetadataDocument.class);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Throwable.class)
|
||||
public SwordError handleException(final HttpServletResponse req, final HttpServletResponse res, final Throwable e) throws IOException {
|
||||
|
||||
if (e instanceof SwordException) {
|
||||
final SwordException swe = (SwordException) e;
|
||||
res.sendError(swe.getHttpCode(), swe.getHttpMessage());
|
||||
} else {
|
||||
res.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
}
|
||||
|
||||
return new SwordError(req, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
package eu.dnetlib.app.directindex.sword;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController("/api/directindex/staging")
|
||||
public class SwordTemporaryUrlController {
|
||||
|
||||
@Value("${dnet.directindex.baseurl}")
|
||||
public String baseUrl;
|
||||
|
||||
@PostMapping("/")
|
||||
// Create a Temporary-URL for Segmented File Upload
|
||||
public @ResponseBody Object createTempUrl(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@GetMapping("/{tempfile}")
|
||||
public @ResponseBody Object getUploadInfo(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
|
||||
@PathVariable final String tempfile) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@PostMapping("/{tempfile}")
|
||||
public @ResponseBody Object uploadSegment(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("Content-Disposition") final String contentDisposition,
|
||||
@RequestHeader("Content-Length") final String contentLength,
|
||||
@RequestHeader("Digest") final String digest,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
|
||||
@PathVariable final String tempfile) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@DeleteMapping("/{tempfile}")
|
||||
public @ResponseBody Object abortUplodad(
|
||||
@RequestHeader("Authorization") final String authorization,
|
||||
@RequestHeader("On-Behalf-Of") final String onBehalfOf,
|
||||
@PathVariable final String tempfile) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package eu.dnetlib.app.directindex.sword.model;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
public class SwordError {
|
||||
|
||||
public SwordError(final HttpServletResponse req, final Throwable e) {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
/*
|
||||
{
|
||||
"@context" : "https://swordapp.github.io/swordv3/swordv3.jsonld",
|
||||
|
||||
"@type" : "BadRequest",
|
||||
|
||||
"timestamp" : "[timestamp]",
|
||||
"error" : "error summary",
|
||||
"log" : "text log of any debug information for the client"
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package eu.dnetlib.app.directindex.sword;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.ContentDisposition;
|
||||
|
||||
class CommonTest {
|
||||
|
||||
@Test
|
||||
public void testContentDisposition() {
|
||||
final ContentDisposition cd = ContentDisposition.parse("attachment; metadata=true");
|
||||
assertTrue(cd.isAttachment());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue