Skip to content

Commit

Permalink
Merge branch 'main' into zip-files-development
Browse files Browse the repository at this point in the history
  • Loading branch information
bbpennel committed Oct 29, 2024
2 parents 18db8be + 836328f commit 7818823
Show file tree
Hide file tree
Showing 103 changed files with 18,738 additions and 11,434 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ jobs:
restore-keys: v1-npm-deps-

- run: npm --prefix static/js/vue-cdr-access install
- run: npm --prefix static/js/admin/vue-permissions-editor install
- run: npm --prefix static/js/admin/vue-cdr-admin install

- run: npm install -g [email protected]
- run: npm --prefix static/js/vue-cdr-access run test
- run: npm --prefix static/js/admin/vue-permissions-editor run test
- run: npm --prefix static/js/admin/vue-cdr-admin run test

- name: Report to CodeClimate
uses: paambaati/[email protected]
Expand All @@ -103,7 +103,7 @@ jobs:
${{github.workspace}}/**/target/site/jacoco/jacoco.xml:jacoco
${{github.workspace}}/**/target/site/jacoco-it/jacoco.xml:jacoco
${{github.workspace}}/static/js/vue-cdr-access/coverage/lcov.info:lcov
${{github.workspace}}/static/js/admin/vue-permissions-editor/coverage/lcov.info:lcov
${{github.workspace}}/static/js/admin/vue-cdr-admin/coverage/lcov.info:lcov
- name: View fedora service logs
if: always()
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ static/js/cdr-access.js
static/css/cdr_access.css
static/css/cdr_vue_modal_styles.css
static/js/vue-access-index.js
static/js/vue-admin-index.js
static/js/vue-permissions-index.js
static/js/vue-cdr-access/.env
static/css/cdr-ui.css
Expand Down
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ build-admin-concat:
static/css/admin/fontawesome/all.min.css \
static/css/structure_browse.css \
static/css/cdr_vue_modal_styles.css \
static/js/admin/vue-permissions-editor/dist/assets/index.css \
static/js/admin/vue-cdr-admin/dist/assets/index.css \
> static/css/cdr_admin.css

ifneq ($(VERSION), "")
Expand All @@ -44,11 +44,11 @@ ifneq ($(VERSION), "")
endif

build-admin-npm:
# Build vue permissions application files
npm --prefix static/js/admin/vue-permissions-editor ci
npm --prefix static/js/admin/vue-permissions-editor run build
# Build vue admin application files
npm --prefix static/js/admin/vue-cdr-admin ci
npm --prefix static/js/admin/vue-cdr-admin run build

cp static/js/admin/vue-permissions-editor/dist/assets/vue-permissions-index.js static/js/vue-permissions-index.js
cp static/js/admin/vue-cdr-admin/dist/assets/vue-admin-index.js static/js/vue-admin-index.js

build-access-concat:
# Make sure file is empty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class DatastreamPermissionUtil {
DS_PERMISSION_MAP = new EnumMap<>(DatastreamType.class);
DS_PERMISSION_MAP.put(DatastreamType.FULLTEXT_EXTRACTION, Permission.viewHidden);
DS_PERMISSION_MAP.put(DatastreamType.JP2_ACCESS_COPY, Permission.viewAccessCopies);
DS_PERMISSION_MAP.put(DatastreamType.AUDIO_ACCESS_COPY, Permission.viewAccessCopies);
DS_PERMISSION_MAP.put(DatastreamType.ACCESS_SURROGATE, Permission.viewAccessCopies);
DS_PERMISSION_MAP.put(DatastreamType.MD_DESCRIPTIVE, Permission.viewMetadata);
DS_PERMISSION_MAP.put(DatastreamType.MD_DESCRIPTIVE_HISTORY, Permission.viewHidden);
Expand Down
2 changes: 1 addition & 1 deletion etc/solr-config/access/conf/schema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@
<field name="timestamp" type="date" indexed="true" stored="true" default="NOW" multiValued="false"/>
<!-- Descriptive Fields -->
<field name="title" type="sortableText" indexed="true" stored="true" required="true"/>
<!-- View behavior for UV -->
<!-- View behavior for Clover -->
<field name="viewBehavior" type="string" indexed="true" stored="true" />

<!-- Index fields -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import java.util.stream.Collectors;

import static edu.unc.lib.boxc.indexing.solr.test.MockRepositoryObjectHelpers.makeFileObject;
import static edu.unc.lib.boxc.model.api.DatastreamType.AUDIO_ACCESS_COPY;
import static edu.unc.lib.boxc.model.api.DatastreamType.JP2_ACCESS_COPY;
import static edu.unc.lib.boxc.model.api.DatastreamType.ORIGINAL_FILE;
import static edu.unc.lib.boxc.model.api.DatastreamType.TECHNICAL_METADATA;
Expand Down Expand Up @@ -118,6 +119,7 @@ public class SetDatastreamFilterTest {
private static final long PREMIS_SIZE = 893l;

private static final long JP2_SIZE = 11;
private static final long AUDIO_SIZE = 11;

private AutoCloseable closeable;

Expand Down Expand Up @@ -255,6 +257,8 @@ public void fileObjectAudioOnlyBinaryTest() throws Exception {
fileResource(TECHNICAL_METADATA.getId(), FILE2_SIZE, FILE2_MIMETYPE, FILE2_NAME, FILE2_DIGEST));
when(binObj2.getBinaryStream()).thenReturn(getClass().getResourceAsStream("/datastream/techmd_mp3.xml"));
when(fileObj.getBinaryObjects()).thenReturn(Arrays.asList(binObj, binObj2));
List<Derivative> derivs = makeAudioDerivative();
when(derivativeService.getDerivatives(pid)).thenReturn(derivs);
dip.setContentObject(fileObj);

filter.filter(dip);
Expand All @@ -263,6 +267,8 @@ public void fileObjectAudioOnlyBinaryTest() throws Exception {
FILE_MP3_SIZE, FILE_MP3_MIMETYPE, FILE_MP3_NAME, FILE_MP3_DIGEST, null, FILE_MP3_EXTENT);
assertContainsDatastream(idb.getDatastream(), TECHNICAL_METADATA.getId(),
FILE2_SIZE, FILE2_MIMETYPE, FILE2_NAME, FILE2_DIGEST, null, null);
assertContainsDatastream(idb.getDatastream(), AUDIO_ACCESS_COPY.getId(),
AUDIO_SIZE, AUDIO_ACCESS_COPY.getMimetype(), "access.m4a", null, null, null);
}

@Test
Expand Down Expand Up @@ -297,6 +303,8 @@ public void fileObjectAudioOnlyBinaryWithDotMillisecondsSeperatorTest() throws E
fileResource(TECHNICAL_METADATA.getId(), FILE2_SIZE, FILE2_MIMETYPE, FILE2_NAME, FILE2_DIGEST));
when(binObj2.getBinaryStream()).thenReturn(getClass().getResourceAsStream("/datastream/techmd_dot_separated_milliseconds.xml"));
when(fileObj.getBinaryObjects()).thenReturn(Arrays.asList(binObj, binObj2));
List<Derivative> derivs = makeAudioDerivative();
when(derivativeService.getDerivatives(pid)).thenReturn(derivs);
dip.setContentObject(fileObj);

filter.filter(dip);
Expand All @@ -305,6 +313,8 @@ public void fileObjectAudioOnlyBinaryWithDotMillisecondsSeperatorTest() throws E
FILE_MP3_SIZE, FILE_MP3_MIMETYPE, FILE_MP3_NAME, FILE_MP3_DIGEST, null, FILE_MP3_EXTENT);
assertContainsDatastream(idb.getDatastream(), TECHNICAL_METADATA.getId(),
FILE2_SIZE, FILE2_MIMETYPE, FILE2_NAME, FILE2_DIGEST, null, null);
assertContainsDatastream(idb.getDatastream(), AUDIO_ACCESS_COPY.getId(),
AUDIO_SIZE, AUDIO_ACCESS_COPY.getMimetype(), "access.m4a", null, null, null);
}

@Test
Expand Down Expand Up @@ -768,4 +778,11 @@ private List<Derivative> makeJP2Derivative() throws IOException {

return List.of(new Derivative(JP2_ACCESS_COPY, jp2File));
}

private List<Derivative> makeAudioDerivative() throws IOException {
File m4aFile = derivDir.resolve("access.m4a").toFile();
FileUtils.write(m4aFile, "m4a content", "UTF-8");

return List.of(new Derivative(AUDIO_ACCESS_COPY, m4aFile));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
public enum DatastreamType {
ACCESS_SURROGATE("access_surrogate", "application/octet-stream", null, null, EXTERNAL),
AUDIO_ACCESS_COPY("audio", "audio/aac", "m4a", null, EXTERNAL),
FULLTEXT_EXTRACTION("fulltext", "text/plain", "txt", null, EXTERNAL),
JP2_ACCESS_COPY("jp2", "image/jp2", "jp2", null, EXTERNAL),
MD_DESCRIPTIVE("md_descriptive", "text/xml", "xml", METADATA_CONTAINER, INTERNAL),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.nio.file.Paths;
import java.util.List;

import static edu.unc.lib.boxc.model.api.DatastreamType.AUDIO_ACCESS_COPY;
import static edu.unc.lib.boxc.model.api.DatastreamType.FULLTEXT_EXTRACTION;
import static edu.unc.lib.boxc.model.api.DatastreamType.JP2_ACCESS_COPY;
import static edu.unc.lib.boxc.model.api.DatastreamType.ORIGINAL_FILE;
Expand Down Expand Up @@ -73,18 +74,22 @@ public void testGetDerivativeNotExist() throws Exception {
public void testGetDerivatives() throws Exception {
File originalDerivFile1 = createDerivative(pid, FULLTEXT_EXTRACTION);
File originalDerivFil21 = createDerivative(pid, JP2_ACCESS_COPY);
File originalDerivFile3 = createDerivative(pid, AUDIO_ACCESS_COPY);

List<Derivative> derivs = derivativeService.getDerivatives(pid);
assertEquals(2, derivs.size());
assertEquals(3, derivs.size());

Derivative textDeriv = findDerivative(derivs, FULLTEXT_EXTRACTION);
Derivative jp2Deriv = findDerivative(derivs, JP2_ACCESS_COPY);
Derivative audioDeriv = findDerivative(derivs, AUDIO_ACCESS_COPY);

assertNotNull(textDeriv);
assertNotNull(jp2Deriv);
assertNotNull(audioDeriv);

assertEquals(originalDerivFile1, textDeriv.getFile());
assertEquals(originalDerivFil21, jp2Deriv.getFile());
assertEquals(originalDerivFile3, audioDeriv.getFile());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import edu.unc.lib.boxc.auth.fcrepo.models.AgentPrincipalsImpl;

/**
* Request object for updating the view settings of the UV
* Request object for updating the view settings of Clover
* @author sharonluong
*/
public class ViewSettingRequest {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package edu.unc.lib.boxc.search.solr.filters;

import edu.unc.lib.boxc.search.api.SearchFieldKey;
import edu.unc.lib.boxc.search.api.filters.QueryFilter;

import java.util.List;
import java.util.stream.Collectors;

/**
* Filter which restricts results to entries which contain populated values for the given key with
* the specified field search value
*
* @author lfarrell
*/
public class HasValuesFilter implements QueryFilter {
private final SearchFieldKey fieldKey;
private final List<String> fieldValues;

protected HasValuesFilter(SearchFieldKey fieldKey, List<String> fieldValues) {
this.fieldKey = fieldKey;
this.fieldValues = fieldValues;
}

@Override
public String toFilterString() {
return fieldValues.stream().map(v -> getFieldKey().getSolrField() + ":" + v)
.collect(Collectors.joining(" OR "));
}

@Override
public SearchFieldKey getFieldKey() {
return fieldKey;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public String toFilterString() {
var fileTypeFilter = getFileTypes().stream().map( type -> fileTypeField + ":" + type)
.collect(Collectors.joining(" OR ", "(", ")"));
var datastreamFilter = SearchFieldKey.DATASTREAM.getSolrField() + ":" + DatastreamType.JP2_ACCESS_COPY.getId() + "|*";
return "(" + fileTypeFilter + ") OR (" + datastreamFilter + ")";
var datastreamFilterAudio = SearchFieldKey.DATASTREAM.getSolrField() + ":" + DatastreamType.AUDIO_ACCESS_COPY.getId() + "|*";
return "(" + fileTypeFilter + ") OR (" + datastreamFilter + ") OR (" + datastreamFilterAudio + ")";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,14 @@ public static QueryFilter createFilter(SearchFieldKey fieldKey) {
public static QueryFilter createIIIFv3ViewableFilter(List<String> fileTypes) {
return new IIIFv3ViewableFilter(fileTypes);
}

/**
*
* @param fieldKey searchField
* @param fieldValues list of values to search for
* @return new QueryFilter instance with the provided file type
*/
public static QueryFilter createHasValuesFilter(SearchFieldKey fieldKey, List<String> fieldValues) {
return new HasValuesFilter(fieldKey, fieldValues);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.junit.jupiter.api.Test;

import java.util.HashSet;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertInstanceOf;

Expand Down Expand Up @@ -33,4 +34,10 @@ public void HasPopulatedFieldFilterTest() {
var filter = QueryFilterFactory.createFilter(SearchFieldKey.STREAMING_TYPE);
assertInstanceOf(HasPopulatedFieldFilter.class, filter);
}

@Test
public void HasValuesFilterTest() {
var filter = QueryFilterFactory.createHasValuesFilter(SearchFieldKey.FILE_FORMAT_TYPE, List.of("application/pdf"));
assertInstanceOf(HasValuesFilter.class, filter);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package edu.unc.lib.boxc.services.camel.audio;

import edu.unc.lib.boxc.services.camel.util.CdrFcrepoHeaders;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.regex.Pattern;

/**
* Processor which validates and prepares audio objects for producing derivatives
* @author krwong
*/
public class AudioDerivativeProcessor implements Processor {
private static final Logger log = LoggerFactory.getLogger(AudioDerivativeProcessor.class);

private static final Pattern MIMETYPE_PATTERN =
Pattern.compile("^(audio.(basic|mpeg|mp4|x-aiff|x-ms-wma|x-wave|x-wav|wav|wave|3gpp))$");

/**
* Returns true if the subject of the exchange is a binary which
* is eligible for having audio derivatives generated from it.
* @param exchange
* @return
*/
public static boolean allowedAudioType(Exchange exchange) {
Message in = exchange.getIn();
String mimetype = (String) in.getHeader(CdrFcrepoHeaders.CdrBinaryMimeType);
String binPath = (String) in.getHeader(CdrFcrepoHeaders.CdrBinaryPath);

if (!MIMETYPE_PATTERN.matcher(mimetype).matches()) {
log.debug("File type {} on object {} is not applicable for audio derivatives", mimetype, binPath);
return false;
}

log.debug("Object {} with type {} is permitted for audio derivatives", binPath, mimetype);
return true;
}

@Override
public void process(Exchange exchange) throws Exception {
Message in = exchange.getIn();
String mimetype = (String) in.getHeader(CdrFcrepoHeaders.CdrBinaryMimeType);

String binPath = (String) in.getHeader(CdrFcrepoHeaders.CdrBinaryPath);
log.debug("Keeping existing audio path as {} for type {}", binPath, mimetype);
in.setHeader(CdrFcrepoHeaders.CdrAudioPath, binPath);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package edu.unc.lib.boxc.services.camel.audio;

import edu.unc.lib.boxc.model.api.exceptions.RepositoryException;
import edu.unc.lib.boxc.services.camel.images.AddDerivativeProcessor;
import edu.unc.lib.boxc.services.camel.util.CdrFcrepoHeaders;
import org.apache.camel.BeanInject;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spi.UuidGenerator;
import org.apache.camel.support.DefaultUuidGenerator;
import org.slf4j.Logger;

import static org.slf4j.LoggerFactory.getLogger;

/**
* Router which triggers the creation of audio derivatives
* @author krwong
*/
public class AudioEnhancementsRouter extends RouteBuilder {
private static final Logger log = getLogger(AudioEnhancementsRouter.class);

@BeanInject(value = "addAudioAccessCopyProcessor")
private AddDerivativeProcessor addAudioAccessCopyProcessor;

private UuidGenerator uuidGenerator;

/**
* Configure the audio enhancement route workflow.
*/
@Override
public void configure() throws Exception {
AudioDerivativeProcessor audioDerivProcessor = new AudioDerivativeProcessor();

uuidGenerator = new DefaultUuidGenerator();

onException(RepositoryException.class)
.redeliveryDelay("{{error.retryDelay}}")
.maximumRedeliveries("{{error.maxRedeliveries}}")
.backOffMultiplier("{{error.backOffMultiplier}}")
.retryAttemptedLogLevel(LoggingLevel.WARN);

from("direct:process.enhancement.audioAccessCopy")
.routeId("AudioAccessCopy")
.startupOrder(25)
.log(LoggingLevel.DEBUG, log, "Access copy triggered")
.filter().method(addAudioAccessCopyProcessor, "needsRun")
.filter().method(audioDerivProcessor, "allowedAudioType")
.bean(audioDerivProcessor)
.log(LoggingLevel.INFO, log, "Creating/Updating AAC access copy for ${headers[CdrAudioPath]}")
// Generate an random identifier to avoid derivative collisions
.setBody(exchange -> uuidGenerator.generateUuid())
.setHeader(CdrFcrepoHeaders.CdrTempPath, simple("${properties:services.tempDirectory}/${body}-audio"))
.doTry()
.recipientList(simple("exec:/bin/sh?args=${properties:cdr.enhancement.bin}/convertAudio.sh "
+ "${headers[CdrAudioPath]} ${headers[CdrTempPath]}"))
.bean(addAudioAccessCopyProcessor)
.endDoTry()
.doFinally()
.bean(addAudioAccessCopyProcessor, "cleanupTempFile")
.end();
}
}
Loading

0 comments on commit 7818823

Please sign in to comment.