diff --git a/code/aspen_app/app-configs/version.json b/code/aspen_app/app-configs/version.json index e64102c80a..8556ad677b 100644 --- a/code/aspen_app/app-configs/version.json +++ b/code/aspen_app/app-configs/version.json @@ -1,5 +1,5 @@ { - "version": "24.08.00", - "build": "270", - "patch": "0" + "version": "24.09.00", + "build": "275", + "patch": "2" } \ No newline at end of file diff --git a/code/aspen_app/src/screens/MyAccount/TitlesOnHold/MyHold.js b/code/aspen_app/src/screens/MyAccount/TitlesOnHold/MyHold.js index 17e61a8e20..c5cccb0279 100644 --- a/code/aspen_app/src/screens/MyAccount/TitlesOnHold/MyHold.js +++ b/code/aspen_app/src/screens/MyAccount/TitlesOnHold/MyHold.js @@ -1,16 +1,16 @@ import { MaterialCommunityIcons, MaterialIcons } from '@expo/vector-icons'; import { useNavigation } from '@react-navigation/native'; -import CachedImage from 'expo-cached-image'; +import DateTimePickerModal from 'react-native-modal-datetime-picker'; import { Image } from 'expo-image'; import _ from 'lodash'; -import { Actionsheet, Box, Button, Center, Checkbox, HStack, Icon, Pressable, Text, useDisclose, VStack } from 'native-base'; +import { Actionsheet, Box, Button, Center, Checkbox, HStack, Icon, Pressable, Text, useDisclose, VStack, useToken, useColorModeValue } from 'native-base'; import React from 'react'; import { popAlert } from '../../../components/loadError'; import { HoldsContext, LanguageContext, LibrarySystemContext, UserContext } from '../../../context/initialContext'; import { getAuthor, getBadge, getCleanTitle, getExpirationDate, getFormat, getOnHoldFor, getPickupLocation, getPosition, getStatus, getTitle, getType } from '../../../helpers/item'; import { navigateStack } from '../../../helpers/RootNavigator'; -import { getTermFromDictionary, getTranslationsWithValues } from '../../../translations/TranslationService'; -import { cancelHold, cancelHolds, cancelVdxRequest, thawHold, thawHolds } from '../../../util/accountActions'; +import { getTermFromDictionary } from '../../../translations/TranslationService'; +import { cancelHold, cancelHolds, cancelVdxRequest, freezeHold, freezeHolds, thawHold, thawHolds } from '../../../util/accountActions'; import { formatDiscoveryVersion } from '../../../util/loadLibrary'; import { checkoutItem } from '../../../util/recordActions'; import { SelectPickupLocation } from './SelectPickupLocation'; @@ -89,6 +89,9 @@ export const MyHold = (props) => { } } + const freezingHoldLabel = getTermFromDictionary(language, 'freezing_hold'); + const freezeHoldLabel = getTermFromDictionary(language, 'freeze_hold'); + const openGroupedWork = (item, title) => { navigateStack('AccountScreenTab', 'MyHold', { id: item, @@ -251,7 +254,7 @@ export const MyHold = (props) => { ); } else { - return ; + return ; } } else { return null; @@ -371,6 +374,8 @@ export const ManageSelectedHolds = (props) => { const numToFreezeLabel = getTermFromDictionary(language, 'freeze_selected_holds') + ' (' + numToFreeze + ')'; const numToThawLabel = getTermFromDictionary(language, 'thaw_selected_holds') + ' (' + numToThaw + ')'; const numSelectedLabel = getTermFromDictionary(language, 'manage_selected') + ' (' + numSelected + ')'; + const freezingHoldLabel = getTermFromDictionary(language, 'freezing_hold'); + const freezeHoldLabel = getTermFromDictionary(language, 'freeze_hold'); const cancelActionItem = () => { if (numToCancel > 0) { @@ -424,7 +429,7 @@ export const ManageSelectedHolds = (props) => { {cancelActionItem()} - + {thawActionItem()} @@ -489,6 +494,8 @@ export const ManageAllHolds = (props) => { const numToCancelLabel = getTermFromDictionary(language, 'cancel_all_holds') + ' (' + numToCancel + ')'; const numToFreezeLabel = getTermFromDictionary(language, 'freeze_all_holds') + ' (' + numToFreeze + ')'; const numToThawLabel = getTermFromDictionary(language, 'thaw_all_holds') + ' (' + numToThaw + ')'; + const freezingHoldLabel = getTermFromDictionary(language, 'freezing_hold'); + const freezeHoldLabel = getTermFromDictionary(language, 'freeze_hold'); if (numToManage >= 1) { return ( @@ -511,7 +518,7 @@ export const ManageAllHolds = (props) => { }}> {numToCancelLabel} - + { - const { label, language, libraryContext, onClose, freezeId, recordId, source, userId, resetGroup, isOpen } = props; + const { freezingLabel, freezeLabel, label, libraryContext, onClose, freezeId, recordId, source, userId, resetGroup, isOpen } = props; let data = props.data; + const { language } = React.useContext(LanguageContext); const [loading, setLoading] = React.useState(false); const textColor = useToken('colors', useColorModeValue('text.500', 'text.50')); const colorMode = useColorModeValue(false, true); - let actionLabel = getTermFromDictionary(language, 'freeze_hold'); + let actionLabel = freezeLabel; if (label) { actionLabel = label; } @@ -57,7 +59,7 @@ export const SelectThawDate = (props) => { } onPress={showDatePicker}> {actionLabel} - + ); }; \ No newline at end of file diff --git a/code/aspen_app/src/screens/Search/Facets/RadioGroup.js b/code/aspen_app/src/screens/Search/Facets/RadioGroup.js index 3be58f3f7e..3f0a399060 100644 --- a/code/aspen_app/src/screens/Search/Facets/RadioGroup.js +++ b/code/aspen_app/src/screens/Search/Facets/RadioGroup.js @@ -41,7 +41,9 @@ export default class Facet_RadioGroup extends Component { componentDidUpdate(prevProps, prevState) { if (prevState.value !== this.state.applied) { - this.renderValue(); + console.log('prevState.value', prevState.value); + console.log('this.state.applied', this.state.applied); + //this.renderValue(); } } @@ -59,17 +61,22 @@ export default class Facet_RadioGroup extends Component { const { category, value } = this.state; if (category !== 'sort_by') { console.log('payload > ', payload); + console.log('value > ', value); if (payload === value) { + console.log('new is same as old. removing.'); removeAppliedFilter(category, payload); this.setState({ value: '', }); } else { + console.log('new value. adding.'); addAppliedFilter(category, payload, false); this.setState({ value: payload, }); } + + console.log('current state value: ' + this.state.value); } else { console.log('payload > ', payload); console.log('value > ', value); @@ -94,6 +101,8 @@ export default class Facet_RadioGroup extends Component { const { items, category, title, updater, applied } = this.state; const name = category + '_group'; + console.log(items); + if (category === 'sort_by') { return ( diff --git a/code/web/RecordDrivers/GroupedWorkDriver.php b/code/web/RecordDrivers/GroupedWorkDriver.php index 7dd8ce12db..49e2f3c043 100644 --- a/code/web/RecordDrivers/GroupedWorkDriver.php +++ b/code/web/RecordDrivers/GroupedWorkDriver.php @@ -92,7 +92,7 @@ public function assignBasicTitleDetails() { $summPublisher = null; $summPubDate = null; - $summPlaceOfPublication = null; + $summPlaceOfPublication = null; $summPhysicalDesc = null; $summEdition = null; $summLanguage = null; @@ -532,8 +532,8 @@ public function getAcceleratedReaderDisplayString() { /** * Get the authors of the work. * - * @access protected - * @return string + * @access protected + * @return string */ public function getAuthors() { return isset($this->fields['author']) ? $this->fields['author'] : null; @@ -647,12 +647,12 @@ public function getBrowseResult() { /** * Assign necessary Smarty variables and return a template name * to load in order to display the requested citation format. - * For legal values, see getCitationFormats(). Returns null if + * For legal values, see getCitationFormats(). Returns null if * format is not supported. * * @param string $format Citation format to display. - * @access public - * @return string Name of Smarty template file to display. + * @access public + * @return string Name of Smarty template file to display. */ public function getCitation($format) { require_once ROOT_DIR . '/sys/CitationBuilder.php'; @@ -697,10 +697,10 @@ public function getCitation($format) { /** * Get an array of strings representing citation formats supported - * by this record's data (empty if none). Legal values: "APA", "MLA". + * by this record's data (empty if none). Legal values: "APA", "MLA". * - * @access public - * @return array Strings representing citation formats. + * @access public + * @return array Strings representing citation formats. */ public function getCitationFormats() { return [ @@ -716,7 +716,7 @@ public function getCitationFormats() { * Return the first valid ISBN found in the record (favoring ISBN-10 over * ISBN-13 when possible). * - * @return mixed + * @return mixed */ public function getCleanISBN() { require_once ROOT_DIR . '/sys/ISBN.php'; @@ -767,10 +767,10 @@ public function getCleanUPC() { * load in order to display a summary of the item suitable for use in * search results. * - * @access public + * @access public * @param string $view The current view. * - * @return string Name of Smarty template file to display. + * @return string Name of Smarty template file to display. */ public function getCombinedResult($view = 'list') { if ($view == 'covers') { // Displaying Results as bookcover tiles @@ -1029,8 +1029,8 @@ public function getDetailedContributors() { /** * Get the edition of the current record. * - * @access protected - * @return array + * @access protected + * @return array */ public function getEditions() { if (isset($this->fields['edition'])) { @@ -1047,11 +1047,11 @@ public function getEditions() { /** * Get the text to represent this record in the body of an email. * - * @access public - * @return string Text for inclusion in email. + * @access public + * @return string Text for inclusion in email. */ public function getEmail() { - return " " . $this->getTitle() . "\n"; + return " " . $this->getTitle() . "\n"; } public function getExploreMoreInfo() { @@ -1136,8 +1136,8 @@ public function getIndexedSeries() { * Get an array of all ISBNs associated with the record (may be empty). * The primary ISBN is the first entry * - * @access protected - * @return array + * @access protected + * @return array */ public function getISBNs() { // If ISBN is in the index, it should automatically be an array... but if @@ -1165,8 +1165,8 @@ public function getISBNs() { /** * Get an array of all ISBNs associated with the record (may be empty). * - * @access protected - * @return array + * @access protected + * @return array */ public function getISSNs() { // If ISBN is in the index, it should automatically be an array... but if @@ -1214,11 +1214,11 @@ public function getLexileScore() { * load in order to display a summary of the item suitable for use in * user's favorites list. * - * @access public + * @access public * @param int $listId ID of list containing desired tags/notes (or - * null to show tags/notes from all user's lists). + * null to show tags/notes from all user's lists). * @param bool $allowEdit Should we display edit controls? - * @return string Name of Smarty template file to display. + * @return string Name of Smarty template file to display. */ public function getListEntry($listId = null, $allowEdit = true) { global $interface; @@ -1294,10 +1294,10 @@ public function getListEntry($listId = null, $allowEdit = true) { * load in order to display a summary of the item suitable for use in * user's favorites list. * - * @access public + * @access public * @param int $listId ID of list containing desired tags/notes (or - * null to show tags/notes from all user's lists). - * @return string Name of Smarty template file to display. + * null to show tags/notes from all user's lists). + * @return string Name of Smarty template file to display. */ public function getCourseReserveEntry($listId = null) { global $configArray; @@ -1566,7 +1566,7 @@ public function getPermanentId() { public function getPrimaryAuthor($useHighlighting = false) { // Don't check for highlighted values if highlighting is disabled: // MDN: 1/26 - author actually contains more information than author display. - // It also includes dates lived so we will use that instead if possible + // It also includes dates lived so we will use that instead if possible if ($this->highlight && $useHighlighting) { if (isset($this->fields['_highlighting']['author'][0])) { return $this->fields['_highlighting']['author'][0]; @@ -1625,8 +1625,8 @@ function getPlaceOfPublication () { * The Table of Contents extracted from the record. * Returns null if no Table of Contents is available. * - * @access public - * @return array Array of elements in the table of contents + * @access public + * @return array Array of elements in the table of contents */ public function getTableOfContentsNotes() { $tableOfContentsNotes = []; @@ -1650,8 +1650,8 @@ public function getTableOfContentsNotes() { /** * Get the publishers of the record. * - * @access protected - * @return array + * @access protected + * @return array */ public function getPublishers() { return $this->fields['publisherStr'] ?? []; @@ -1772,7 +1772,7 @@ public function getRelatedManifestations() { global $searchSource; /** - * @var $key + * @var $key * @var Grouping_Manifestation $manifestation */ foreach ($this->_relatedManifestations as $key => $manifestation) { @@ -1878,10 +1878,10 @@ public function getScrollerTitle($index, $scrollerName) { * load in order to display a summary of the item suitable for use in * search results. * - * @access public + * @access public * @param string $view The current view. * - * @return string Name of Smarty template file to display. + * @return string Name of Smarty template file to display. */ public function getSearchResult($view = 'list') { if ($view == 'covers') { // Displaying Results as bookcover tiles @@ -2236,8 +2236,8 @@ public function getGroupedWorkObject() : ?GroupedWork { * load in order to display the full record information on the Staff * View tab of the record view page. * - * @access public - * @return string Name of Smarty template file to display. + * @access public + * @return string Name of Smarty template file to display. */ public function getStaffView() { global $interface; @@ -2475,8 +2475,8 @@ public function getTitle($useHighlighting = false) { * The Table of Contents extracted from the record. * Returns null if no Table of Contents is available. * - * @access public - * @return array Array of elements in the table of contents + * @access public + * @return array Array of elements in the table of contents */ public function getTableOfContents() { $tableOfContents = []; @@ -2502,8 +2502,8 @@ public function getTableOfContents() { * useful for retrieving additional information (like tags and user * comments) from the external MySQL database. * - * @access public - * @return string Unique identifier. + * @access public + * @return string Unique identifier. */ public function getUniqueID() { return $this->fields['id']; @@ -2512,7 +2512,7 @@ public function getUniqueID() { /** * Get the UPC associated with the record (may be empty). * - * @return array + * @return array */ public function getUPCs() { // If UPCs is in the index, it should automatically be an array... but if @@ -2879,7 +2879,7 @@ private function loadRelatedRecords($forCovers = false, $forceLoadFromDB = true) $this->_relatedManifestations = []; //Get the variations from the database and add to the appropriate manifestation - /** @var $allVariations Grouping_Variation[] */ + /** @var $allVariations Grouping_Variation[] */ $allVariations = []; foreach ($variations as $variation) { if (!array_key_exists($variation['format'], $this->_relatedManifestations)) { @@ -3025,7 +3025,7 @@ private function loadRelatedRecords($forCovers = false, $forceLoadFromDB = true) * @return array */ protected function loadScopingDetails($solrScope) { - //First load scoping information from the index. This is stored as multiple values + //First load scoping information from the index. This is stored as multiple values //within the scoping details field for the scope. //Each field is $scopingInfoFieldName = 'scoping_details_' . $solrScope; @@ -3084,11 +3084,11 @@ private function getRawVariationsDataFromDB($uniqueVariationIds) { } else { $uniqueVariationsIdsString = implode(',', $uniqueVariationIds); $variationQuery = "SELECT grouped_work_variation.id, indexed_language.language, indexed_econtent_source.eContentSource, indexed_format.format, indexed_format_category.formatCategory FROM grouped_work_variation - LEFT JOIN indexed_language on primaryLanguageId = indexed_language.id - LEFT JOIN indexed_econtent_source on eContentSourceId = indexed_econtent_source.id - LEFT JOIN indexed_format on formatId = indexed_format.id - LEFT JOIN indexed_format_category on formatCategoryId = indexed_format_category.id - where grouped_work_variation.id IN ($uniqueVariationsIdsString)"; + LEFT JOIN indexed_language on primaryLanguageId = indexed_language.id + LEFT JOIN indexed_econtent_source on eContentSourceId = indexed_econtent_source.id + LEFT JOIN indexed_format on formatId = indexed_format.id + LEFT JOIN indexed_format_category on formatCategoryId = indexed_format_category.id + where grouped_work_variation.id IN ($uniqueVariationsIdsString)"; $variationResults = $aspen_db->query($variationQuery, PDO::FETCH_ASSOC); $variations = $variationResults->fetchAll(); $variationResults->closeCursor(); @@ -3105,16 +3105,16 @@ private function getRawRecordDataFromDB($uniqueRecordIds) { } else { $uniqueRecordIdsString = implode(',', $uniqueRecordIds); $recordQuery = "SELECT grouped_work_records.id, recordIdentifier, isClosedCaptioned, indexed_record_source.source, indexed_record_source.subSource, indexed_edition.edition, indexed_publisher.publisher, indexed_publication_date.publicationDate, indexed_place_of_publication.placeOfPublication, indexed_physical_description.physicalDescription, indexed_format.format, indexed_format_category.formatCategory, indexed_language.language, hasParentRecord, hasChildRecord FROM grouped_work_records - LEFT JOIN indexed_record_source ON sourceId = indexed_record_source.id - LEFT JOIN indexed_edition ON editionId = indexed_edition.id - LEFT JOIN indexed_publisher ON publisherId = indexed_publisher.id - LEFT JOIN indexed_publication_date ON publicationDateId = indexed_publication_date.id - LEFT JOIN indexed_place_of_publication ON placeOfPublicationId = indexed_place_of_publication.id - LEFT JOIN indexed_physical_description ON physicalDescriptionId = indexed_physical_description.id - LEFT JOIN indexed_format on formatId = indexed_format.id - LEFT JOIN indexed_format_category on formatCategoryId = indexed_format_category.id - LEFT JOIN indexed_language on languageId = indexed_language.id - where grouped_work_records.id IN ($uniqueRecordIdsString)"; + LEFT JOIN indexed_record_source ON sourceId = indexed_record_source.id + LEFT JOIN indexed_edition ON editionId = indexed_edition.id + LEFT JOIN indexed_publisher ON publisherId = indexed_publisher.id + LEFT JOIN indexed_publication_date ON publicationDateId = indexed_publication_date.id + LEFT JOIN indexed_place_of_publication ON placeOfPublicationId = indexed_place_of_publication.id + LEFT JOIN indexed_physical_description ON physicalDescriptionId = indexed_physical_description.id + LEFT JOIN indexed_format on formatId = indexed_format.id + LEFT JOIN indexed_format_category on formatCategoryId = indexed_format_category.id + LEFT JOIN indexed_language on languageId = indexed_language.id + where grouped_work_records.id IN ($uniqueRecordIdsString)"; $results = $aspen_db->query($recordQuery, PDO::FETCH_ASSOC); $records = $results->fetchAll(); $results->closeCursor(); @@ -3130,16 +3130,20 @@ private function getRawItemDataFromDB($uniqueItemIds) { } else { $uniqueItemIdsString = implode(',', $uniqueItemIds); $scopeQuery = "SELECT grouped_work_record_items.id as groupedWorkItemId, available, holdable, inLibraryUseOnly, locationOwnedScopes, libraryOwnedScopes, groupedStatusTbl.status as groupedStatus, statusTbl.status as status, - grouped_work_record_items.groupedWorkRecordId, grouped_work_record_items.groupedWorkVariationId, grouped_work_record_items.itemId, indexed_call_number.callNumber, indexed_shelf_location.shelfLocation, numCopies, isOrderItem, dateAdded, - indexed_location_code.locationCode, indexed_sub_location_code.subLocationCode, lastCheckInDate, isVirtual - FROM grouped_work_record_items - LEFT JOIN indexed_status as groupedStatusTbl on groupedStatusId = groupedStatusTbl.id - LEFT JOIN indexed_status as statusTbl on statusId = statusTbl.id - LEFT JOIN indexed_call_number ON callNumberId = indexed_call_number.id - LEFT JOIN indexed_shelf_location ON shelfLocationId = indexed_shelf_location.id - LEFT JOIN indexed_location_code on locationCodeId = indexed_location_code.id - LEFT JOIN indexed_sub_location_code on subLocationCodeId = indexed_sub_location_code.id - where grouped_work_record_items.id IN ($uniqueItemIdsString)"; + grouped_work_record_items.groupedWorkRecordId, grouped_work_record_items.groupedWorkVariationId, grouped_work_record_items.itemId, indexed_call_number.callNumber, indexed_shelf_location.shelfLocation, numCopies, isOrderItem, dateAdded, + indexed_location_code.locationCode, indexed_sub_location_code.subLocationCode, lastCheckInDate, isVirtual, groupedWorkRecordEdition.edition as 'edition' + FROM grouped_work_record_items + LEFT JOIN indexed_status as groupedStatusTbl on groupedStatusId = groupedStatusTbl.id + LEFT JOIN indexed_status as statusTbl on statusId = statusTbl.id + LEFT JOIN indexed_call_number ON callNumberId = indexed_call_number.id + LEFT JOIN indexed_shelf_location ON shelfLocationId = indexed_shelf_location.id + LEFT JOIN indexed_location_code on locationCodeId = indexed_location_code.id + LEFT JOIN indexed_sub_location_code on subLocationCodeId = indexed_sub_location_code.id + LEFT JOIN ( + SELECT indexed_edition.edition, grouped_work_records.id, grouped_work_records.editionId from grouped_work_records + LEFT JOIN indexed_edition on grouped_work_records.editionId = indexed_edition.id + ) as groupedWorkRecordEdition on groupedWorkRecordId = groupedWorkRecordEdition.id + where grouped_work_record_items.id IN ($uniqueItemIdsString)"; $results = $aspen_db->query($scopeQuery, PDO::FETCH_ASSOC); $scopedItems = $results->fetchAll(); $results->closeCursor(); @@ -3189,8 +3193,8 @@ protected function setupRelatedRecordDetails($recordDetails, $groupedWork, $time /** GroupedWorkSubDriver $recordDriver */ require_once ROOT_DIR . '/RecordDrivers/RecordDriverFactory.php'; $recordDriver = RecordDriverFactory::initRecordDriverById($recordDetails[0], $groupedWork); - $timer->logTime("Loaded Record Driver for $recordDetails[0]"); - $memoryWatcher->logMemory("Loaded Record Driver for $recordDetails[0]"); + $timer->logTime("Loaded Record Driver for $recordDetails[0]"); + $memoryWatcher->logMemory("Loaded Record Driver for $recordDetails[0]"); require_once ROOT_DIR . '/sys/Grouping/Record.php'; $relatedRecord = new Grouping_Record($recordDetails[0], $recordDetails, $recordDriver, $volumeData, $source, null); @@ -3628,7 +3632,7 @@ public function formatGroupedWorkCitation() { break; } - $risFields[] = "TY - ".$format; + $risFields[] = "TY - ".$format; } //RIS Tag: AU - Author $authors = array(); @@ -3651,14 +3655,14 @@ public function formatGroupedWorkCitation() { // RIS Tag: TI - Title $title = $this->getTitle(); if (!empty($title)) { - $risFields[] = "TI - " . $title; + $risFields[] = "TI - " . $title; } // RIS Tag: PB - Publisher $publishers = $this->getPublishers(); if (is_array($publishers) && count($publishers) > 0) { $publishers = implode(', ', $publishers); - $risFields[] = "PB - " . $publishers; + $risFields[] = "PB - " . $publishers; } // RIS Tag: PY - Publication Year(s) @@ -3668,7 +3672,7 @@ public function formatGroupedWorkCitation() { } foreach ($publishDates as $publishDate) { if (!empty($publishDate)) { - $risFields[] = "PY - " . $publishDate; + $risFields[] = "PY - " . $publishDate; } } @@ -3676,11 +3680,11 @@ public function formatGroupedWorkCitation() { if(is_array($placesOfPublication) && count($placesOfPublication) > 0) { $placesOfPublicationClean = implode(', ', $placesOfPublication); $placesOfPublicationClean = str_replace([':', '; '], ' ', $placesOfPublication); - $risFields[] = "CY - ".$placesOfPublicationClean; + $risFields[] = "CY - ".$placesOfPublicationClean; } else { if(!empty($placesOfPublication)) { $placesOfPublicationClean = str_replace([':', '; '], ' ', $placesOfPublication); - $risFields[] = "CY - ".$placesOfPublicationClean; + $risFields[] = "CY - ".$placesOfPublicationClean; } } @@ -3688,10 +3692,10 @@ public function formatGroupedWorkCitation() { $editions = $this->getEdition(); if(is_array($editions) && count($editions) > 0) { $editions = implode(', ', $editions); - $risFields[] = "ET - ".$editions; + $risFields[] = "ET - ".$editions; } else { if(!empty($editions)) { - $risFields[] = "ET - ".$editions; + $risFields[] = "ET - ".$editions; } } @@ -3699,47 +3703,47 @@ public function formatGroupedWorkCitation() { $url = $this->getRecordUrl(); if(is_array($url) && count($url) > 0) { $url = implode(', ', $url); - $risFields[] = "UR - ".$url; + $risFields[] = "UR - ".$url; } //RIS Tag: N1 - Info $notes = $this->getTableOfContentsNotes(); if(is_array($notes) && count($notes) > 0) { $notes = implode(', ', $notes); - $risFields[] = "N1 - ".$notes; + $risFields[] = "N1 - ".$notes; }else{ if(!empty($notes)) { - $risFields[] = "N1 - ".$notes; + $risFields[] = "N1 - ".$notes; } } //RIS Tag: N2 - Notes $description = $this->getDescription(); if(!empty($description)) { - $risFields[] = "N2 - ".$description; + $risFields[] = "N2 - ".$description; } //RIS T2 - Series $series = $this->getSeries(); if(is_array($series) && count($series) >0){ $series = implode(', ', $series); - $risFields[] = "T2 - ".$series; + $risFields[] = "T2 - ".$series; } //RIS ST - Short Title $shortTilte = $this->getShortTitle(); if(!empty($shortTilte)) { - $risFields[] = "ST - ".$shortTilte; + $risFields[] = "ST - ".$shortTilte; } // RIS Tag: SN - ISBN $ISBN = $this->getPrimaryIsbn(); if(!empty($ISBN)){ - $risFields[] = "SN - ".$ISBN; + $risFields[] = "SN - ".$ISBN; } //RIS Tag: AV - $risFields[] = "ER -"; + $risFields[] = "ER -"; return implode("\n", $risFields); } else { diff --git a/code/web/bootstrap.php b/code/web/bootstrap.php index 2a9a2d6d82..0d89618537 100644 --- a/code/web/bootstrap.php +++ b/code/web/bootstrap.php @@ -81,6 +81,11 @@ if (strlen($userAgentString) > 512) { $userAgentString = substr($userAgentString, 0, 512); } + if (isSpammyUserAgent($userAgentString)) { + http_response_code(404); + echo("Page Not Found

404

We're sorry, but the page you are looking for can't be found.

"); + die(); + } $userAgent->userAgent = $userAgentString; if ($userAgent->find(true)) { $userAgentId = $userAgent->id; @@ -431,4 +436,52 @@ function getGitBranch() { } return $branchName; +} + +//Look for spammy user agents and kill them +function isSpammyUserAgent($userAgentString): bool { + if (stripos($userAgentString, 'DBMS_PIPE.RECEIVE_MESSAGE') !== false) { + return true; + } elseif (stripos($userAgentString, 'PG_SLEEP') !== false) { + return true; + } elseif (stripos($userAgentString, 'SELECT') !== false) { + return true; + } elseif (stripos($userAgentString, 'SLEEP') !== false) { + return true; + } elseif (stripos($userAgentString, 'ORDER BY') !== false) { + return true; + } elseif (stripos($userAgentString, 'WAITFOR') !== false) { + return true; + } elseif (stripos($userAgentString, 'nvOpzp') !== false) { + return true; + } elseif (stripos($userAgentString, 'window.location') !== false) { + return true; + } elseif (stripos($userAgentString, 'window.top') !== false) { + return true; + } elseif (stripos($userAgentString, 'nslookup') !== false) { + return true; + } elseif (stripos($userAgentString, 'if(') !== false) { + return true; + } elseif (stripos($userAgentString, 'now(') !== false) { + return true; + } elseif (stripos($userAgentString, 'sysdate()') !== false) { + return true; + } elseif (stripos($userAgentString, 'sleep(') !== false) { + return true; + } elseif (stripos($userAgentString, 'cast(') !== false) { + return true; + } elseif (stripos($userAgentString, 'current_database') !== false) { + return true; + } elseif (stripos($userAgentString, 'response.write') !== false) { + return true; + } elseif (stripos($userAgentString, 'CONVERT(') !== false) { + return true; + } elseif (stripos($userAgentString, 'EXTRACTVALUE(') !== false) { + return true; + } + $termWithoutTags = strip_tags($userAgentString); + if ($termWithoutTags != $userAgentString) { + return true; + } + return false; } \ No newline at end of file diff --git a/code/web/interface/themes/responsive/CloudLibrary/add-alternate-library-card.tpl b/code/web/interface/themes/responsive/CloudLibrary/add-alternate-library-card.tpl index bfab184b92..f8b75e7f18 100644 --- a/code/web/interface/themes/responsive/CloudLibrary/add-alternate-library-card.tpl +++ b/code/web/interface/themes/responsive/CloudLibrary/add-alternate-library-card.tpl @@ -9,28 +9,28 @@
{$alternateLibraryCardFormMessage}
{/if} -
-