diff --git a/.env b/.env index 25052e019b..83a24243dc 100644 --- a/.env +++ b/.env @@ -46,17 +46,9 @@ ACCOUNT_LESS_STRICT_PASSWORD_RULES=0 MAILER_FROM_ADDR='email@domain.null' MAILER_FROM_NAME='SenderName' MAILER_BCC_ADDR='email@domain.null' -PELAGOS_NAME=pelagos ISSUE_TRACKING_BASE_URL='https://griidc.atlassian.net/browse' DATABASE_NAME=pelagos DATA_STORE_DIRECTORY=/path/to/store/directory -DATA_DOWNLOAD_DIRECTORY=/path/to/download/directory -DATA_STORE_OWNER=user -DATA_STORE_GROUP=group -DATA_DOWNLOAD_BROWSER_GROUP=browser_group -WEB_SERVER_USER=apache -ANONYMOUS_FTP_USER=user -ANONYMOUS_FTP_PASS=pass DOWNLOAD_PATH="path/to/zip" INGEST_API_URL="https://ingest-server:port/api-name" GCMD_VERSION="16.9" @@ -77,7 +69,6 @@ DOWNLOAD_BASE_URL=https://server-name/path/file-download POSIX_STARTING_UID=10000 POSIX_GID=1001 REQUEST_CONTEXT_BASE_URL='/pelagos-symfony' -FILESYSTEM_TYPE='Linux' ###> DOI API Parameters ### DOI_API_USER_NAME="username" diff --git a/config/services.yaml b/config/services.yaml index d92511345b..7f0575947c 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -94,6 +94,7 @@ services: - { name: kernel.event_listener, event: pelagos.logactionitem.search_terms_log, method: onNewLogCreated } - { name: kernel.event_listener, event: pelagos.logactionitem.restrictions_log, method: onNewLogCreated } - { name: kernel.event_listener, event: pelagos.logactionitem.remotelyhosted_update_log, method: onNewLogCreated } + - { name: kernel.event_listener, event: pelagos.logactionitem.dataset_deletion, method: onNewLogCreated } App\Event\InformationProductListener: tags: diff --git a/src/Command/GetGoMRIStatisticsCommand.php b/src/Command/GetGoMRIStatisticsCommand.php index 723bc540e0..9739d283be 100644 --- a/src/Command/GetGoMRIStatisticsCommand.php +++ b/src/Command/GetGoMRIStatisticsCommand.php @@ -27,6 +27,8 @@ class GetGoMRIStatisticsCommand extends Command public const HARVEST2019COUNT = 7100; // count public const HARVEST2019DATA = 3600; // GB + public const NUMBEROFTOPDOWNLOADSTOSHOW = 10; + /** * Class constructor for dependency injection. */ @@ -102,6 +104,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int sort($years); $minYear = $years[0]; $maxYear = $years[sizeof($years) - 1]; + $io->writeln("\nGomri Uploads (submissions)\n"); for ($i = $minYear; $i <= $maxYear; $i++) { if (in_array($i, $years)) { $io->writeln("Number of GoMRI datasets submitted $i" @@ -112,18 +115,31 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - $io->writeln("Total GoMRI Downloads:"); - $downloadSizeByYear = []; - $downloadCountByYear = []; + $io->writeln("\nGoMRI Downloads:\n"); + $downloadSizeByYearAndQuarter = []; + $downloadCountByYearAndQuarter = []; foreach ($this->getDownloads() as $datasetDownload) { $id = $datasetDownload[0]; $timestamp = $datasetDownload[1]; - $year = substr($timestamp, 0, 4); - if (!array_key_exists($year, $downloadCountByYear)) { - $downloadCountByYear[$year] = 0; + + $yearQuarter = $this->determineQuarter($timestamp); + $year = $yearQuarter['year']; + $quarter = $yearQuarter['quarter']; + + if (!array_key_exists($year, $downloadCountByYearAndQuarter)) { + $downloadCountByYearAndQuarter[$year][0] = 0; + $downloadCountByYearAndQuarter[$year][1] = 0; + $downloadCountByYearAndQuarter[$year][2] = 0; + $downloadCountByYearAndQuarter[$year][3] = 0; + $downloadCountByYearAndQuarter[$year][4] = 0; } - if (!array_key_exists($year, $downloadSizeByYear)) { - $downloadSizeByYear[$year] = 0; + + if (!array_key_exists($year, $downloadSizeByYearAndQuarter)) { + $downloadSizeByYearAndQuarter[$year][0] = 0; + $downloadSizeByYearAndQuarter[$year][1] = 0; + $downloadSizeByYearAndQuarter[$year][2] = 0; + $downloadSizeByYearAndQuarter[$year][3] = 0; + $downloadSizeByYearAndQuarter[$year][4] = 0; } $dataset = $this->entityManager->find('\App\Entity\Dataset', $id); @@ -136,54 +152,102 @@ protected function execute(InputInterface $input, OutputInterface $output): int $skipCount++; } - - $downloadCountByYear[$year]++; - $downloadSizeByYear[$year] += $size / 1000000000; - //print "$timestamp,$id,$udi,$size\n"; + $downloadCountByYearAndQuarter[$year][$quarter]++; + $downloadSizeByYearAndQuarter[$year][$quarter] += $size / 1000000000; } - $firstYear = min(array_keys($downloadCountByYear)); - $lastYear = max(array_keys($downloadCountByYear)); - - // Deal with the data harvest of 2019. - if (array_key_exists(2019, $downloadCountByYear)) { - $downloadCountByYear[2019] -= self::HARVEST2019COUNT; - } - if (array_key_exists(2019, $downloadCountByYear)) { - $downloadSizeByYear[2019] -= self::HARVEST2019DATA; - } + // array_keys still onlys dump first level, years, for $array[year][quarter]. + $firstYear = min(array_keys($downloadCountByYearAndQuarter)); + $lastYear = max(array_keys($downloadCountByYearAndQuarter)); + + // Deal with the data harvest of 2019Q2. + $downloadCountByYearAndQuarter[2019][2] -= self::HARVEST2019COUNT; + $downloadSizeByYearAndQuarter[2019][2] -= self::HARVEST2019DATA; + + $totalDownloads = 0; + $totalDownloadSize = 0; + for ($year = $firstYear; $year <= $lastYear; $year++) { + $yearCountTotal = 0; + $yearSizeTotal = 0; + for ($quarter = 1; $quarter <= 4; $quarter++) { + $popularDownloads = $this->getTopDatasetsDownloadedByYearAndQuarter(self::NUMBEROFTOPDOWNLOADSTOSHOW, $year, $quarter); + $io->writeln($year . '/Q' . $quarter . ' Download Count: ' . $downloadCountByYearAndQuarter[$year][$quarter] + . ', ' . 'Total Size (GB): ' . round($downloadSizeByYearAndQuarter[$year][$quarter])); + $yearCountTotal += $downloadCountByYearAndQuarter[$year][$quarter]; + $totalDownloads += $downloadCountByYearAndQuarter[$year][$quarter]; + $yearSizeTotal += $downloadSizeByYearAndQuarter[$year][$quarter]; + $totalDownloadSize += $downloadSizeByYearAndQuarter[$year][$quarter]; + $popular = "Top: "; + foreach ($popularDownloads as $udi => $count) { + $popular .= "$udi:$count, "; + } + $popular = substr($popular, 0, strlen($popular) - 2); + $io->writeln($popular); + } + $io->newLine(); + $io->writeln('Totals for: ' . $year . ':'); + $io->writeln('Download count: ' . $yearCountTotal); + $io->writeln('Data Downloaded: ' . round($yearSizeTotal) . ' GB'); + $io->writeln('--------------------------------------------------------------------------------'); + $io->newLine(); + } - for ($i = $firstYear; $i <= $lastYear; $i++) { - $io->writeln($i . ' Download Count: ' . $downloadCountByYear[$i] . ', ' . 'Total Size (GB): ' . round($downloadSizeByYear[$i])); + // Total Download stats: + $io->writeln('All Time Stats:'); + $io->writeln('Download count: ' . $totalDownloads); + $io->writeln('Data Downloaded: ' . round($totalDownloadSize) . ' GB'); + + // Show most popular downloads of all time. + $popularDownloadsOfAllTime = $this->getTopDatasetsDownloadedByYearAndQuarter(self::NUMBEROFTOPDOWNLOADSTOSHOW); + $allTimePopular = ''; + $io->writeln('Top ' . self::NUMBEROFTOPDOWNLOADSTOSHOW . ' downloads of all time:'); + foreach ($popularDownloadsOfAllTime as $udi => $count) { + $allTimePopular .= "$udi:$count, "; } + $allTimePopular = substr($allTimePopular, 0, strlen($allTimePopular) - 2); + $io->writeln($allTimePopular); + + // Add disclaimer if any datasets had been deleted. (This doesn't apply to gomri currently, but other FOs) if ($skipCount > 0) { $io->warning("Skipped $skipCount entries as these datasets are no longer available."); } - $io->note('Removed 7100 / 3600GB from 2019 downloads - data harvest occurred'); + // Add disclaimer for data cleanup for big data harvest event. + $io->note('Removed ' . self::HARVEST2019COUNT . ' / ' . self::HARVEST2019DATA . 'GB from 2019Q2 downloads - data harvest occurred'); return 0; } /** - * Maintains array of quarter counts. + * Returns Year and Quarter given a timestamp. * * @param \DateTime $timestamp - * @param array $quarterCounts + * @return array $yearQuarter */ - protected function quarterize(\DateTime $timestamp, array &$quarterCounts): void + protected function determineQuarter(\DateTime $timestamp): array { - // Quarters are strict calendar quarters. - // Q1: Jan 1 - Mar 31 - // Q2: Apr 1 - Jun 30 - // Q3: Jul 1 - Sep 30 - // Q4: Oct 1 - Dec 31 + // Quarters are normal calendar quarters (Jan-Mar, Apr-Jun, Jul-Sep, Oct-Dec) $year = $timestamp->format('Y'); // returns 4 digit year $month = $timestamp->format('n'); // returns 1-12 $quarter = ceil($month / 3); + return array("year" => $year, "quarter" => $quarter); + } + + /** + * Maintains array of quarter counts. + * + * @param \DateTime $timestamp + * @param array $quarterCounts + */ + protected function quarterize(\DateTime $timestamp, array &$quarterCounts): void + { + $yearAndQuarter = $this->determineQuarter($timestamp); + $year = $yearAndQuarter['year']; + $quarter = $yearAndQuarter['quarter']; + // Initialize if (!array_key_exists($year, $quarterCounts)) { $quarterCounts[$year] = []; @@ -196,6 +260,88 @@ protected function quarterize(\DateTime $timestamp, array &$quarterCounts): void $quarterCounts[$year][$quarter - 1] += 1; } + /** + * Returns array of UDIs of top downloads in date range. + * + * @param int|null $year The year to get top downloads from. + * @param int|null $quarter The quarter to get top downloads from. + * @return array $topDownloadUdis An associative array of top UDIs with counts as value. + * + * @throws \Exception If quarter value used other than (1, 2, 3, 4) + */ + public function getTopDatasetsDownloadedByYearAndQuarter(int $count, int $year = null, int $quarter = null): array + { + if ($quarter !== null && !(in_array($quarter, array(1, 2, 3, 4)))) { + throw new \Exception("Bad quarter specified, use 1-4."); + } + + if ($year === null && $quarter !== null) { + throw new \Exception("If quarter is specified, year must be too."); + } + + // Create DB compatible strings from DateTime objects. + if ($year !== null && $quarter == 1) { + $from = "$year-01-01"; + $to = "$year-03-31"; + } elseif ($year !== null && $quarter == 2) { + $from = "$year-04-01"; + $to = "$year-06-30"; + } elseif ($year !== null && $quarter == 3) { + $from = "$year-07-01"; + $to = "$year-09-30"; + } elseif ($year !== null && $quarter == 4) { + $from = "$year-10-01"; + $to = "$year-12-31"; + } elseif ($year !== null && $quarter === null) { + // entire year + $from = "$year-01-01"; + $to = "$year-12-31"; + } + + $qb = $this->entityManager->getRepository(LogActionItem::class)->createQueryBuilder('log') + ->select('count(log.subjectEntityId), log.subjectEntityId') + ->where('log.subjectEntityName = :entityName') + ->andWhere('log.actionName = :actionName') + ->orderBy('count(log.subjectEntityId)', 'DESC') + ->groupBy('log.subjectEntityId') + ->setMaxResults($count) + ->setParameter('entityName', 'Pelagos\Entity\Dataset') + ->setParameter('actionName', 'File Download'); + + if ($year !== null) { + $qb + ->andWhere('log.creationTimeStamp >= :from') + ->andWhere('log.creationTimeStamp <= :to') + ->setParameter('from', $from) + ->setParameter('to', $to); + } + + if ($this->fundingOrgFilter->isActive()) { + $researchGroupIds = $this->fundingOrgFilter->getResearchGroupsIdArray(); + + $qb + ->join(Dataset::class, 'dataset', Query\Expr\Join::WITH, 'log.subjectEntityId = dataset.id') + ->innerJoin('dataset.researchGroup', 'rg') + ->andWhere('rg.id IN (:rgs)') + ->setParameter('rgs', $researchGroupIds); + } + + $query = $qb->getQuery(); + $results = $query->getResult(); + + $topDownloadUdis = []; + foreach ($results as $row) { + $count = $row[1]; + $id = $row['subjectEntityId']; + $dataset = $this->entityManager->find('\App\Entity\Dataset', $id); + if ($dataset instanceof Dataset) { + $udi = $dataset->getUdi(); + $topDownloadUdis[$udi] = $count; + } + } + return $topDownloadUdis; + } + /** * Generates array of funding-org filter-aware download events. * @@ -236,7 +382,7 @@ public function getDownloads(): array if (($displayTime === '2014-09-27') or $key === array_key_first($downloads) or ($epochTime - $currentTimeStamp) > 30 or $currentId != $id) { $currentTimeStamp = $epochTime; - $downloadArray[] = array($id, $displayTime); + $downloadArray[] = array($id, $dateTime); } $currentId = $id; } diff --git a/src/Controller/Admin/DashboardController.php b/src/Controller/Admin/DashboardController.php index 7e41b5f894..56532fed1e 100644 --- a/src/Controller/Admin/DashboardController.php +++ b/src/Controller/Admin/DashboardController.php @@ -5,6 +5,7 @@ use App\Entity\DigitalResourceTypeDescriptor; use App\Entity\Funder; use App\Entity\FundingOrganization; +use App\Entity\LogActionItem; use App\Entity\ProductTypeDescriptor; use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard; use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; @@ -45,6 +46,8 @@ public function configureDashboard(): Dashboard public function configureMenuItems(): iterable { yield MenuItem::linktoDashboard('Admin Links', 'fa fa-link'); + yield MenuItem::section('Viewers'); + yield MenuItem::linkToCrud('Logged Actions', 'fas fa-search', LogActionItem::class); yield MenuItem::section('Editors'); yield MenuItem::linkToCrud('IP Product Descriptor', 'fas fa-list-alt', ProductTypeDescriptor::class); yield MenuItem::linkToCrud('IP Digital Resource Descriptor', 'fas fa-list-alt', DigitalResourceTypeDescriptor::class); diff --git a/src/Controller/Admin/LogActionItemCrudController.php b/src/Controller/Admin/LogActionItemCrudController.php new file mode 100644 index 0000000000..69844c3660 --- /dev/null +++ b/src/Controller/Admin/LogActionItemCrudController.php @@ -0,0 +1,64 @@ +disable(Action::NEW); + $actions->disable(Action::EDIT); + $actions->disable(Action::DELETE); + + return $actions; + } + + /** + * Configure fields for EZAdmin CRUD Controller. + * + * @param string $pageName default param for parent method (not used) + */ + public function configureFields(string $pageName): iterable + { + return [ + IdField::new('id') + ->onlyOnIndex(), + TextField::new('actionName', 'What Happened'), + TextField::new('subjectEntityName', 'Happened To'), + IdField::new('subjectEntityId', 'Which One'), + DateTimeField::new('creationTimeStamp', 'Happened When'), + TextField::new('payloadDetails'), + ]; + } + + /** + * CRUD configuration function. + * + * @param Crud $crud instance for crud controller to add additional configuration + */ + public function configureCrud(Crud $crud): Crud + { + return parent::configureCrud($crud) + ->setPageTitle(Crud::PAGE_INDEX, 'Logged Actions') + ->setDefaultSort(['creationTimeStamp' => 'DESC']); + } +} diff --git a/src/Controller/Api/DatasetController.php b/src/Controller/Api/DatasetController.php index c362ce4a7c..81ae221ac9 100644 --- a/src/Controller/Api/DatasetController.php +++ b/src/Controller/Api/DatasetController.php @@ -10,6 +10,7 @@ use App\Entity\PersonDatasetSubmissionDatasetContact; use App\Entity\PersonDatasetSubmissionMetadataContact; use App\Event\EntityEventDispatcher; +use App\Event\LogActionItemEventDispatcher; use App\Form\DatasetType; use App\Message\DeleteFile; use App\Message\DeleteDir; @@ -124,7 +125,7 @@ public function patchAction(int $id, Request $request, MdappLogger $mdappLogger) $jiraLinkValue = $request->request->get('issueTrackingTicket'); if (null !== $jiraLinkValue) { $mdappLogger->writeLog( - $this->getUser()->getUserName() . + $this->getUser()->getUserIdentifier() . ' set Jira Link for udi: ' . $this->entityHandler->get(Dataset::class, $id)->getUdi() . ' to ' . @@ -139,17 +140,16 @@ public function patchAction(int $id, Request $request, MdappLogger $mdappLogger) /** * Delete a Dataset and associated Metadata and Difs. * - * @param integer $id The id of the Dataset to delete. - * @param EntityEventDispatcher $entityEventDispatcher The entity event dispatcher. - * @param MessageBusInterface $messageBus Symfony messenger message bus interface. - * - * + * @param integer $id The id of the Dataset to delete. + * @param EntityEventDispatcher $entityEventDispatcher The entity event dispatcher. + * @param MessageBusInterface $messageBus Symfony messenger message bus interface. + * @param LogActionItemEventDispatcher $logActionItemEventDistpatcher The Log action item event dispatcher. * * @Route("/api/datasets/{id}", name="pelagos_api_datasets_delete", methods={"DELETE"}, defaults={"_format"="json"}) * * @return Response A response object with an empty body and a "no content" status code. */ - public function deleteAction(int $id, EntityEventDispatcher $entityEventDispatcher, MessageBusInterface $messageBus) + public function deleteAction(int $id, EntityEventDispatcher $entityEventDispatcher, MessageBusInterface $messageBus, LogActionItemEventDispatcher $logActionItemEventDispatcher) { $dataset = $this->handleGetOne(Dataset::class, $id); @@ -182,6 +182,18 @@ public function deleteAction(int $id, EntityEventDispatcher $entityEventDispatch $entityEventDispatcher->dispatch($dataset, 'delete_doi'); + $udi = $dataset->getUdi(); + + $logActionItemEventDispatcher->dispatch( + array( + 'actionName' => 'Dataset Deletion', + 'subjectEntityName' => 'Pelagos\Entity\Dataset', + 'subjectEntityId' => $dataset->getId(), + 'payLoad' => array('UDI' => $udi, 'userId' => $this->getUser()->getUserIdentifier()), + ), + 'dataset_deletion' + ); + $this->handleDelete(Dataset::class, $id); if ($dif instanceof DIF) { @@ -241,7 +253,7 @@ public function getFileCountSize(DatasetRepository $datasetRepository): Response $data = []; foreach ($datasets as $dataset) { - $datasetArray = array ( + $datasetArray = array( "udi" => $dataset->getUdi(), "numberOfFiles" => $dataset->getNumberOfFiles(), "totalFileSize" => $dataset->getTotalFileSize(), diff --git a/src/Controller/DownloadController.php b/src/Controller/DownloadController.php index bef987de11..a4c4086421 100644 --- a/src/Controller/DownloadController.php +++ b/src/Controller/DownloadController.php @@ -188,7 +188,7 @@ public function httpAction(Dataset $dataset, Datastore $dataStore, LogActionItem $typeId = $this->getUser()->getUserId(); } else { $type = 'Non-GoMRI'; - $typeId = $this->getUser()->getUsername(); + $typeId = $this->getUser()->getUserIdentifier(); } } else { $type = 'Non-GoMRI'; diff --git a/src/Controller/UI/DataDiscoveryController.php b/src/Controller/UI/DataDiscoveryController.php index 1d58f24379..b306feab76 100644 --- a/src/Controller/UI/DataDiscoveryController.php +++ b/src/Controller/UI/DataDiscoveryController.php @@ -289,7 +289,7 @@ protected function dispatchSearchTermsLogEvent(Request $request, ResultSet $sear break; case 'HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUser': $clientInfo['userType'] = 'Non-GoMRI'; - $clientInfo['userId'] = $this->getUser()->getUsername(); + $clientInfo['userId'] = $this->getUser()->getUserIdentifier(); break; default: break; diff --git a/src/Controller/UI/MdAppController.php b/src/Controller/UI/MdAppController.php index 18c1108c4f..be700095b8 100644 --- a/src/Controller/UI/MdAppController.php +++ b/src/Controller/UI/MdAppController.php @@ -100,7 +100,7 @@ public function changeDatasetStatusAction(Request $request, MdappLogger $mdappLo $datasetSubmission->setDatasetStatus($to); $this->entityHandler->update($datasetSubmission); $this->entityHandler->update($dataset); - $mdappLogger->writeLog($this->getUser()->getUsername() . ' changed status for ' . + $mdappLogger->writeLog($this->getUser()->getUserIdentifier() . ' changed status for ' . $udi . '(' . $this->getFlashBagStatus($from) . ' >>> ' . $this->getFlashBagStatus($to) . ')'); $message = 'Status for ' . $udi . ' has been changed from ' . $this->getFlashBagStatus($from) . ' to ' . $this->getFlashBagStatus($to); diff --git a/src/Entity/LogActionItem.php b/src/Entity/LogActionItem.php index cd42208494..3144526331 100644 --- a/src/Entity/LogActionItem.php +++ b/src/Entity/LogActionItem.php @@ -196,4 +196,67 @@ public function getPayLoad() { return $this->payLoad; } + + /** + * Virtual function that returns a stringified payload, making sense per json type. + */ + public function getPayloadDetails(): string + { + $json = $this->payLoad; + $action = $this->getActionName(); + + if ($action === 'New Search') { + $userType = $json['clientInfo']['userType'] ?? ''; + $userId = $json['clientInfo']['userId'] ?? ''; + $terms = $json['searchQueryParams']['inputFormTerms']['searchTerms'] ?? ''; + $subsite = $json['subSite'] ?? ''; + $text = "The $userType user $userId searched for \"$terms\" on subsite $subsite."; + } elseif ($action === 'Search') { + $terms = $json['filters']['textFilter'] ?? ''; + $geo = $json['filters']['geoFilter'] ?? ''; + $text = "Data discovery search with text \"$terms\""; + if (!empty($geo)) { + $text .= " and used a map search"; + } + $text .= '.'; + } elseif ($action === 'Mark as Remotely Hosted') { + $userId = $json['userId'] ?? ''; + $submissionId = $json['datasetSubmissionId'] ?? ''; + $text = "User $userId set remotely hosted on submission id $submissionId"; + } elseif ($action === 'File Download') { + $userType = $json['userType'] ?? ''; + $userId = $json['userId'] ?? ''; + $udi = $json['udi'] ?? ''; + $text = "The $userType user $userId downloaded a complete zip"; + if (!empty($udi)) { + $text .= " of dataset $udi"; + } else { + $text .= '.'; + } + } elseif ($action === 'Single File Download') { + $userType = $json['userType'] ?? ''; + $userId = $json['userId'] ?? ''; + $filename = $json['filename'] ?? ''; + $udi = $json['udi'] ?? ''; + $text = "The $userType user $userId downloaded the single file $filename"; + if (!empty($udi)) { + $text .= " from dataset $udi"; + } else { + $text .= '.'; + } + } elseif ($action === 'Dataset Deletion') { + $udi = $json['UDI'] ?? ''; + $user = $json['userId'] ?? ''; + $text = "$user deleted dataset $udi."; + } elseif ($action === 'Restriction Change') { + $userId = $json['userId'] ?? ''; + $from = $json['previousRestriction'] ?? ''; + $to = $json['newRestriction'] ?? ''; + $text = "$userId changed dataset restriction flag from $from to $to."; + } else { + $text = 'Warning: Unknown JSON. Extend getPayloadDetails method in LogActionItemCrudController class.'; + } + + return $text; + } } diff --git a/src/Util/DatasetCitationUtil.php b/src/Util/DatasetCitationUtil.php index edf115e8bf..b9cd105c67 100644 --- a/src/Util/DatasetCitationUtil.php +++ b/src/Util/DatasetCitationUtil.php @@ -33,7 +33,7 @@ public static function getCitation(Dataset $dataset): string $citationString .= (!empty($author) ? "$author. " : ''); $citationString .= (!empty($year) ? "$year. " : ''); $citationString .= "$title. "; - $citationString .= 'Distributed by: Gulf of Mexico Research Initiative Information and Data Cooperative (GRIIDC), Harte Research Institute, Texas A&M University–Corpus Christi. '; + $citationString .= 'Distributed by: GRIIDC, Harte Research Institute, Texas A&M University–Corpus Christi. '; if ($doi instanceof DOI) { $citationString .= 'doi:' . $doi->getDoi(); diff --git a/templates/Default/hri-index.html.twig b/templates/Default/hri-index.html.twig index e67c99d5c5..a04f217db7 100644 --- a/templates/Default/hri-index.html.twig +++ b/templates/Default/hri-index.html.twig @@ -81,7 +81,7 @@ diff --git a/templates/Default/nas-grp-index.html.twig b/templates/Default/nas-grp-index.html.twig index bead767d52..80a9410714 100644 --- a/templates/Default/nas-grp-index.html.twig +++ b/templates/Default/nas-grp-index.html.twig @@ -84,7 +84,7 @@ diff --git a/yarn.lock b/yarn.lock index adcfe84511..29e3559a67 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2467,11 +2467,11 @@ brace-expansion@^2.0.1: balanced-match "^1.0.0" braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.9.1: version "4.21.0" @@ -2580,15 +2580,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001358, caniuse-lite@^1.0.30001400: - version "1.0.30001574" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001574.tgz" - integrity sha512-BtYEK4r/iHt/txm81KBudCUcTy7t+s9emrIaHqjYurQ10x71zJ5VQ9x1dYPcz/b+pKSp4y/v1xSI67A+LzpNyg== - -caniuse-lite@^1.0.30001565: - version "1.0.30001568" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001568.tgz#53fa9297273c9a977a560663f48cbea1767518b7" - integrity sha512-vSUkH84HontZJ88MiNrOau1EBrCqEQYgkC5gIySiDlpsm8sGVrhU7Kx4V6h0tnqaHzIHZv08HlJIwPbL4XL9+A== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001358, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001565: + version "1.0.30001651" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz" + integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== chainsaw@~0.1.0: version "0.1.0" @@ -3834,10 +3829,10 @@ file-saver@^2.0.5: resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38" integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA== -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -7409,9 +7404,9 @@ wrappy@1: integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@^8.13.0: - version "8.15.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.15.0.tgz#db080a279260c5f532fc668d461b8346efdfcf86" - integrity sha512-H/Z3H55mrcrgjFwI+5jKavgXvwQLtfPCUEp6pi35VhoB0pfcHnSoyuTzkBEZpzq49g1193CUEwIvmsjcotenYw== + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== xbytes@^1.7.0: version "1.8.0"