Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(resource): add ArchiveRepresentation to API V1 (DEV-393) (DEV-394) #1984

Merged
merged 8 commits into from Jan 31, 2022
Expand Up @@ -81,6 +81,8 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) {
makeVideoFileValue(valueProps, projectShortcode, responderManager, userProfile)
case OntologyConstants.KnoraBase.DocumentFileValue =>
makeDocumentFileValue(valueProps, projectShortcode, responderManager, userProfile)
case OntologyConstants.KnoraBase.ArchiveFileValue =>
makeArchiveFileValue(valueProps, projectShortcode, responderManager, userProfile)
case OntologyConstants.KnoraBase.LinkValue => makeLinkValue(valueProps, responderManager, userProfile)
}
}
Expand All @@ -106,6 +108,15 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) {
def makeSipiDocumentGetUrlFromFilename(documentFileValueV1: DocumentFileValueV1): String =
s"${settings.externalSipiIIIFGetUrl}/${documentFileValueV1.projectShortcode}/${documentFileValueV1.internalFilename}/file"

/**
* Creates a URL for accessing a archive file via Sipi.
*
* @param archiveFileValueV1 the archive file value.
* @return a Sipi URL.
*/
def makeSipiArchiveGetUrlFromFilename(archiveFileValueV1: ArchiveFileValueV1): String =
s"${settings.externalSipiIIIFGetUrl}/${archiveFileValueV1.projectShortcode}/${archiveFileValueV1.internalFilename}/file"

/**
* Creates a URL for accessing a text file via Sipi.
*
Expand Down Expand Up @@ -197,6 +208,13 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) {
path = makeSipiDocumentGetUrlFromFilename(documentFileValueV1)
)

case archiveFileValueV1: ArchiveFileValueV1 =>
LocationV1(
format_name = mimeType2V1Format(archiveFileValueV1.internalMimeType),
origname = archiveFileValueV1.originalFilename,
path = makeSipiArchiveGetUrlFromFilename(archiveFileValueV1)
)

case textFileValue: TextFileValueV1 =>
LocationV1(
format_name = mimeType2V1Format(textFileValue.internalMimeType),
Expand Down Expand Up @@ -398,6 +416,8 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) {

case _: DocumentFileValueV1 => basicObjectResponse

case _: ArchiveFileValueV1 => basicObjectResponse

case _: AudioFileValueV1 => basicObjectResponse

case _: MovingImageFileValueV1 => basicObjectResponse
Expand Down Expand Up @@ -916,6 +936,30 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) {
)
}

/**
* Converts a [[ValueProps]] into a [[ArchiveFileValueV1]].
*
* @param valueProps a [[ValueProps]] representing the SPARQL query results to be converted.
* @return a [[ArchiveFileValueV1]].
*/
private def makeArchiveFileValue(
valueProps: ValueProps,
projectShortcode: String,
responderManager: ActorRef,
userProfile: UserADM
)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ApiValueV1] = {
val predicates = valueProps.literalData

Future(
ArchiveFileValueV1(
internalMimeType = predicates(OntologyConstants.KnoraBase.InternalMimeType).literals.head,
internalFilename = predicates(OntologyConstants.KnoraBase.InternalFilename).literals.head,
originalFilename = predicates.get(OntologyConstants.KnoraBase.OriginalFilename).map(_.literals.head),
projectShortcode = projectShortcode
)
)
}

/**
* Converts a [[ValueProps]] into a [[AudioFileValueV1]].
*
Expand Down
Expand Up @@ -1611,6 +1611,64 @@ case class DocumentFileValueV1(
)
}

/**
* A representation of a compressed archive in a binary format.
*
* @param internalMimeType the MIME-type of the internal representation.
* @param internalFilename the internal filename of the object.
* @param originalFilename the original filename of the object at the time of the import.
*/
case class ArchiveFileValueV1(
internalMimeType: String,
internalFilename: String,
originalFilename: Option[String] = None,
originalMimeType: Option[String] = None,
projectShortcode: String
) extends FileValueV1 {
def valueTypeIri: IRI = OntologyConstants.KnoraBase.ArchiveFileValue

def toJsValue: JsValue = ApiValueV1JsonProtocol.archiveFileValueV1Format.write(this)

override def toString: String = internalFilename

/**
* Checks if a new archive file value would duplicate an existing archive file value.
*
* @param other another [[ValueV1]].
* @return `true` if `other` is a duplicate of `this`.
*/
override def isDuplicateOfOtherValue(other: ApiValueV1): Boolean =
other match {
case archiveFileValueV1: ArchiveFileValueV1 => archiveFileValueV1 == this
case otherValue =>
throw InconsistentRepositoryDataException(s"Cannot compare a $valueTypeIri to a ${otherValue.valueTypeIri}")
}

/**
* Checks if a new version of a archive file value would be redundant given the current version of the value.
*
* @param currentVersion the current version of the value.
* @return `true` if this [[UpdateValueV1]] is redundant given `currentVersion`.
*/
override def isRedundant(currentVersion: ApiValueV1): Boolean =
currentVersion match {
case archiveFileValueV1: ArchiveFileValueV1 => archiveFileValueV1 == this
case other =>
throw InconsistentRepositoryDataException(s"Cannot compare a $valueTypeIri to a ${other.valueTypeIri}")
}

override def toFileValueContentV2: FileValueContentV2 =
ArchiveFileValueContentV2(
ontologySchema = InternalSchema,
fileValue = FileValueV2(
internalFilename = internalFilename,
internalMimeType = internalMimeType,
originalFilename = originalFilename,
originalMimeType = Some(internalMimeType)
)
)
}

case class AudioFileValueV1(
internalMimeType: String,
internalFilename: String,
Expand Down Expand Up @@ -1861,6 +1919,7 @@ object ApiValueV1JsonProtocol extends SprayJsonSupport with DefaultJsonProtocol
implicit val dateValueV1Format: JsonFormat[DateValueV1] = jsonFormat5(DateValueV1)
implicit val stillImageFileValueV1Format: JsonFormat[StillImageFileValueV1] = jsonFormat7(StillImageFileValueV1)
implicit val documentFileValueV1Format: JsonFormat[DocumentFileValueV1] = jsonFormat8(DocumentFileValueV1)
implicit val archiveFileValueV1Format: JsonFormat[ArchiveFileValueV1] = jsonFormat5(ArchiveFileValueV1)
implicit val textFileValueV1Format: JsonFormat[TextFileValueV1] = jsonFormat5(TextFileValueV1)
implicit val audioFileValueV1Format: JsonFormat[AudioFileValueV1] = jsonFormat6(AudioFileValueV1)
implicit val movingImageFileValueV1Format: JsonFormat[MovingImageFileValueV1] = jsonFormat9(MovingImageFileValueV1)
Expand Down
Expand Up @@ -20,10 +20,11 @@ import org.knora.webapi.messages.store.sipimessages.GetFileMetadataResponse
import org.knora.webapi.messages.util.standoff.StandoffTagUtilV2
import org.knora.webapi.messages.util.standoff.StandoffTagUtilV2.TextWithStandoffTagsV2
import org.knora.webapi.messages.v1.responder.valuemessages.{
MovingImageFileValueV1,
ArchiveFileValueV1,
AudioFileValueV1,
DocumentFileValueV1,
FileValueV1,
MovingImageFileValueV1,
StillImageFileValueV1,
TextFileValueV1
}
Expand Down Expand Up @@ -258,11 +259,11 @@ object RouteUtilV1 {
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/zip",
"application/x-tar",
"application/x-iso9660-image",
"application/gzip"
"application/vnd.openxmlformats-officedocument.presentationml.presentation"
// "application/zip",
// "application/x-tar",
// "application/x-iso9660-image",
// "application/gzip"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You forgot to remove what you've moved to archiveMimeTypes

)

/**
Expand All @@ -283,6 +284,16 @@ object RouteUtilV1 {
"video/mp4"
)

/**
* MIME types used in Sipi to store archive files.
*/
private val archiveMimeTypes: Set[String] = Set(
"application/zip",
"application/x-tar",
"application/gzip",
"application/x-7z-compressed"
)

/**
* Converts file metadata from Sipi into a [[FileValueV1]].
*
Expand Down Expand Up @@ -348,6 +359,14 @@ object RouteUtilV1 {
dimY =
fileMetadataResponse.height.getOrElse(throw SipiException(s"Sipi did not return the height of the video"))
)
} else if (archiveMimeTypes.contains(fileMetadataResponse.internalMimeType)) {
ArchiveFileValueV1(
internalFilename = filename,
internalMimeType = fileMetadataResponse.internalMimeType,
originalFilename = fileMetadataResponse.originalFilename,
originalMimeType = fileMetadataResponse.originalMimeType,
projectShortcode = projectShortcode
)
} else {
throw BadRequestException(s"MIME type ${fileMetadataResponse.internalMimeType} not supported in Knora API v1")
}
Expand Down
Expand Up @@ -364,6 +364,27 @@ DELETE {
}
}

case archiveFileValue: ArchiveFileValueV1 => {
?newValue knora-base:internalFilename """@archiveFileValue.internalFilename""" .
?newValue knora-base:internalMimeType """@archiveFileValue.internalMimeType""" .

@archiveFileValue.originalFilename match {
case Some(definedOriginalFilename) => {
?newValue knora-base:originalFilename """@definedOriginalFilename""" .
}

case None => {}
}

@archiveFileValue.originalMimeType match {
case Some(definedOriginalMimeType) => {
?newValue knora-base:originalMimeType """@definedOriginalMimeType""" .
}

case None => {}
}
}

case listValue: HierarchicalListValueV1 => {

?newValue knora-base:valueHasListNode <@listValue.hierarchicalListIri> .
Expand Down
Expand Up @@ -320,6 +320,27 @@
}
}

case archiveFileValue: ArchiveFileValueV1 => {
<@newValueIri> knora-base:internalFilename """@archiveFileValue.internalFilename""" ;
knora-base:internalMimeType """@archiveFileValue.internalMimeType""" .

@archiveFileValue.originalFilename match {
case Some(definedOriginalFilename) => {
<@newValueIri> knora-base:originalFilename """@definedOriginalFilename""" .
}

case None => {}
}

@archiveFileValue.originalMimeType match {
case Some(definedOriginalMimeType) => {
<@newValueIri> knora-base:originalMimeType """@definedOriginalMimeType""" .
}

case None => {}
}
}

case listValue: HierarchicalListValueV1 => {

<@newValueIri> knora-base:valueHasListNode <@listValue.hierarchicalListIri> .
Expand Down
Expand Up @@ -850,9 +850,9 @@ class KnoraSipiIntegrationV1ITSpec
uploadedZipFile.originalFilename should ===(minimalZipOriginalFilename)

// Create a resource for the Zip file.
val createDocumentResourceParams = JsObject(
val archiveResourceParams = JsObject(
Map(
"restype_id" -> JsString("http://www.knora.org/ontology/0001/anything#ThingDocument"),
"restype_id" -> JsString("http://www.knora.org/ontology/knora-base#ArchiveRepresentation"),
"label" -> JsString("Zip file"),
"project_id" -> JsString("http://rdfh.ch/projects/0001"),
"properties" -> JsObject(),
Expand All @@ -863,7 +863,7 @@ class KnoraSipiIntegrationV1ITSpec
// Send the JSON in a POST request to the Knora API server.
val createDocumentResourceRequest: HttpRequest = Post(
baseApiUrl + "/v1/resources",
HttpEntity(ContentTypes.`application/json`, createDocumentResourceParams.compactPrint)
HttpEntity(ContentTypes.`application/json`, archiveResourceParams.compactPrint)
) ~> addCredentials(BasicHttpCredentials(userEmail, password))

val createDocumentResourceResponseJson: JsObject = getResponseJson(createDocumentResourceRequest)
Expand Down