first commit
This commit is contained in:
@@ -0,0 +1,603 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/context/Context.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class Context
|
||||
*
|
||||
* @ingroup core
|
||||
*
|
||||
* @brief Basic class describing a context.
|
||||
*/
|
||||
|
||||
namespace PKP\context;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\core\Services;
|
||||
use APP\plugins\IDoiRegistrationAgency;
|
||||
use APP\statistics\StatisticsHelper;
|
||||
use Illuminate\Support\Arr;
|
||||
use PKP\config\Config;
|
||||
use PKP\facades\Locale;
|
||||
use PKP\i18n\LocaleMetadata;
|
||||
use PKP\plugins\Plugin;
|
||||
use PKP\plugins\PluginRegistry;
|
||||
use PKP\site\Site;
|
||||
|
||||
abstract class Context extends \PKP\core\DataObject
|
||||
{
|
||||
// Constants used to distinguish whether metadata is enabled and whether it should be requested or required during submission
|
||||
public const METADATA_DISABLE = 0;
|
||||
|
||||
public const METADATA_ENABLE = 'enable';
|
||||
|
||||
public const METADATA_REQUEST = 'request';
|
||||
|
||||
public const METADATA_REQUIRE = 'require';
|
||||
|
||||
public const SETTING_ENABLE_DOIS = 'enableDois';
|
||||
public const SETTING_ENABLED_DOI_TYPES = 'enabledDoiTypes';
|
||||
public const SETTING_DOI_PREFIX = 'doiPrefix';
|
||||
public const SETTING_DOI_SUFFIX_TYPE = 'doiSuffixType';
|
||||
public const SETTING_CONFIGURED_REGISTRATION_AGENCY = 'registrationAgency';
|
||||
public const SETTING_NO_REGISTRATION_AGENCY = null;
|
||||
public const SETTING_DOI_CREATION_TIME = 'doiCreationTime';
|
||||
public const SETTING_DOI_AUTOMATIC_DEPOSIT = 'automaticDoiDeposit';
|
||||
public const SETTING_DOI_VERSIONING = 'doiVersioning';
|
||||
|
||||
public const SUBMISSION_ACKNOWLEDGEMENT_OFF = null;
|
||||
public const SUBMISSION_ACKNOWLEDGEMENT_SUBMITTING_AUTHOR = 'submittingAuthor';
|
||||
public const SUBMISSION_ACKNOWLEDGEMENT_ALL_AUTHORS = 'allAuthors';
|
||||
|
||||
/**
|
||||
* Whether DOIs are enabled for this context
|
||||
*
|
||||
*/
|
||||
public function areDoisEnabled(): bool
|
||||
{
|
||||
return (bool) $this->getData(Context::SETTING_ENABLE_DOIS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if DOIs of a given type are enabled for the current context
|
||||
*
|
||||
* @param string $doiType One of Repo::doi()::TYPE_*
|
||||
*
|
||||
*/
|
||||
public function isDoiTypeEnabled(string $doiType): bool
|
||||
{
|
||||
if (!$this->areDoisEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array($doiType, $this->getData(Context::SETTING_ENABLED_DOI_TYPES) ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves array of enabled DOI types (items are one of Repo::doi()::TYPE_*).
|
||||
*/
|
||||
public function getEnabledDoiTypes(): array
|
||||
{
|
||||
return $this->getData(Context::SETTING_ENABLED_DOI_TYPES) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves configured DOI registration agency plugin, if any active
|
||||
*
|
||||
*/
|
||||
public function getConfiguredDoiAgency(): IDoiRegistrationAgency|Plugin|null
|
||||
{
|
||||
$configuredPluginName = $this->getData(Context::SETTING_CONFIGURED_REGISTRATION_AGENCY);
|
||||
|
||||
if (empty($configuredPluginName) || $configuredPluginName == Context::SETTING_NO_REGISTRATION_AGENCY) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$plugins = PluginRegistry::getAllPlugins();
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
if ($configuredPluginName == $name) {
|
||||
if ($plugin instanceof IDoiRegistrationAgency) {
|
||||
return $plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the localized name of the context
|
||||
*
|
||||
* @param string $preferredLocale
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLocalizedName($preferredLocale = null)
|
||||
{
|
||||
return $this->getLocalizedData('name', $preferredLocale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the context
|
||||
*
|
||||
* @param string $name
|
||||
* @param null|mixed $locale
|
||||
*/
|
||||
public function setName($name, $locale = null)
|
||||
{
|
||||
$this->setData('name', $name, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the name of the context
|
||||
*
|
||||
* @param null|mixed $locale
|
||||
*/
|
||||
public function getName($locale = null)
|
||||
{
|
||||
return $this->getData('name', $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contact name for this context
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContactName()
|
||||
{
|
||||
return $this->getData('contactName');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the contact name for this context
|
||||
*
|
||||
* @param string $contactName
|
||||
*/
|
||||
public function setContactName($contactName)
|
||||
{
|
||||
$this->setData('contactName', $contactName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contact email for this context
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContactEmail()
|
||||
{
|
||||
return $this->getData('contactEmail');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the contact email for this context
|
||||
*
|
||||
* @param string $contactEmail
|
||||
*/
|
||||
public function setContactEmail($contactEmail)
|
||||
{
|
||||
$this->setData('contactEmail', $contactEmail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get context description.
|
||||
*
|
||||
* @param null|mixed $locale
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription($locale = null)
|
||||
{
|
||||
return $this->getData('description', $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set context description.
|
||||
*
|
||||
* @param string $description
|
||||
* @param string $locale optional
|
||||
*/
|
||||
public function setDescription($description, $locale = null)
|
||||
{
|
||||
$this->setData('description', $description, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to context (in URL).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->getData('urlPath');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path to context (in URL).
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->setData('urlPath', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enabled flag of context
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getEnabled()
|
||||
{
|
||||
return $this->getData('enabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set enabled flag of context
|
||||
*
|
||||
* @param int $enabled
|
||||
*/
|
||||
public function setEnabled($enabled)
|
||||
{
|
||||
$this->setData('enabled', $enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary locale of this context.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPrimaryLocale()
|
||||
{
|
||||
return $this->getData('primaryLocale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the primary locale of this context.
|
||||
*/
|
||||
public function setPrimaryLocale($primaryLocale)
|
||||
{
|
||||
$this->setData('primaryLocale', $primaryLocale);
|
||||
}
|
||||
/**
|
||||
* Get sequence of context in site-wide list.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSequence()
|
||||
{
|
||||
return $this->getData('seq');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sequence of context in site table of contents.
|
||||
*
|
||||
* @param float $sequence
|
||||
*/
|
||||
public function setSequence($sequence)
|
||||
{
|
||||
$this->setData('seq', $sequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the localized description of the context.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLocalizedDescription()
|
||||
{
|
||||
return $this->getLocalizedData('description');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get localized acronym of context
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLocalizedAcronym()
|
||||
{
|
||||
return $this->getLocalizedData('acronym');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the acronym of the context.
|
||||
*
|
||||
* @param string $locale
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAcronym($locale)
|
||||
{
|
||||
return $this->getData('acronym', $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get localized favicon
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLocalizedFavicon()
|
||||
{
|
||||
$favicons = $this->getData('favicon');
|
||||
$locale = Arr::first([Locale::getLocale(), Locale::getPrimaryLocale()], fn (string $locale) => isset($favicons[$locale]));
|
||||
return $favicons[$locale] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the supported form locales.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportedFormLocales(): ?array
|
||||
{
|
||||
return $this->getData('supportedFormLocales');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return associative array of all locales supported by forms on the site.
|
||||
*
|
||||
* @param int $langLocaleStatus The const value of one of LocaleMetadata:LANGUAGE_LOCALE_*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportedFormLocaleNames(int $langLocaleStatus = LocaleMetadata::LANGUAGE_LOCALE_WITHOUT)
|
||||
{
|
||||
return $this->getData('supportedFormLocaleNames') ?? Locale::getFormattedDisplayNames($this->getSupportedFormLocales(), null, $langLocaleStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the supported submission locales.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportedSubmissionLocales()
|
||||
{
|
||||
return $this->getData('supportedSubmissionLocales');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return associative array of all locales supported by submissions on the
|
||||
* context.
|
||||
*
|
||||
* @param int $langLocaleStatus The const value of one of LocaleMetadata:LANGUAGE_LOCALE_*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportedSubmissionLocaleNames(int $langLocaleStatus = LocaleMetadata::LANGUAGE_LOCALE_WITHOUT)
|
||||
{
|
||||
return $this->getData('supportedSubmissionLocaleNames') ?? Locale::getFormattedDisplayNames($this->getSupportedSubmissionLocales(), null, $langLocaleStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the supported locales.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportedLocales()
|
||||
{
|
||||
return $this->getData('supportedLocales');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return associative array of all locales supported by the site.
|
||||
* These locales are used to provide a language toggle on the main site pages.
|
||||
*
|
||||
* @param int $langLocaleStatus The const value of one of LocaleMetadata:LANGUAGE_LOCALE_*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportedLocaleNames(int $langLocaleStatus = LocaleMetadata::LANGUAGE_LOCALE_WITHOUT)
|
||||
{
|
||||
return $this->getData('supportedLocaleNames') ?? Locale::getFormattedDisplayNames($this->getSupportedLocales(), null, $langLocaleStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return date or/and time formats available for forms, fallback to the default if not set
|
||||
*
|
||||
* @param string $format datetime property, e.g., dateFormatShort
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDateTimeFormats($format)
|
||||
{
|
||||
$data = $this->getData($format) ?? [];
|
||||
$fallbackConfigVar = strtolower(preg_replace('/([A-Z])/', '_$1', $format));
|
||||
foreach ($this->getSupportedFormLocales() as $supportedLocale) {
|
||||
if (!array_key_exists($supportedLocale, $data)) {
|
||||
$data[$supportedLocale] = Config::getVar('general', $fallbackConfigVar);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localized short date format, fallback to the default if not set
|
||||
*
|
||||
* @param null|mixed $locale
|
||||
*
|
||||
* @return string, see DateTime::format
|
||||
*/
|
||||
public function getLocalizedDateFormatShort($locale = null)
|
||||
{
|
||||
return $this->getData('dateFormatShort', $locale ?? Locale::getLocale()) ?: Config::getVar('general', 'date_format_short');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localized long date format, fallback to the default if not set
|
||||
*
|
||||
* @param null|mixed $locale
|
||||
*
|
||||
* @return string, see DateTime::format
|
||||
*/
|
||||
public function getLocalizedDateFormatLong($locale = null)
|
||||
{
|
||||
return $this->getData('dateFormatLong', $locale ?? Locale::getLocale()) ?: Config::getVar('general', 'date_format_long');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localized time format, fallback to the default if not set
|
||||
*
|
||||
* @param null|mixed $locale
|
||||
*
|
||||
* @return string, see DateTime::format
|
||||
*/
|
||||
public function getLocalizedTimeFormat($locale = null)
|
||||
{
|
||||
return $this->getData('timeFormat', $locale ?? Locale::getLocale()) ?: Config::getVar('general', 'time_format');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localized short date & time format, fallback to the default if not set
|
||||
*
|
||||
* @param null|mixed $locale
|
||||
*
|
||||
* @return string, see see DateTime::format
|
||||
*/
|
||||
public function getLocalizedDateTimeFormatShort($locale = null)
|
||||
{
|
||||
return $this->getData('datetimeFormatShort', $locale ?? Locale::getLocale()) ?: Config::getVar('general', 'datetime_format_short');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localized long date & time format, fallback to the default if not set
|
||||
*
|
||||
* @param null|mixed $locale
|
||||
*
|
||||
* @return string, see see DateTime::format
|
||||
*/
|
||||
public function getLocalizedDateTimeFormatLong($locale = null)
|
||||
{
|
||||
return $this->getData('datetimeFormatLong', $locale ?? Locale::getLocale()) ?: Config::getVar('general', 'datetime_format_long');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the association type for this context.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getAssocType();
|
||||
|
||||
/**
|
||||
* @deprecated Most settings should be available from self::getData(). In other cases, use the context settings DAO directly.
|
||||
* @param null|mixed $locale
|
||||
*/
|
||||
public function getSetting($name, $locale = null)
|
||||
{
|
||||
return $this->getData($name, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Most settings should be available from self::getData(). In other cases, use the context settings DAO directly.
|
||||
* @param null|mixed $locale
|
||||
*/
|
||||
public function getLocalizedSetting($name, $locale = null)
|
||||
{
|
||||
return $this->getLocalizedData($name, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a context setting value.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $type optional
|
||||
* @param bool $isLocalized optional
|
||||
*
|
||||
* @deprecated 3.3.0.0
|
||||
*/
|
||||
public function updateSetting($name, $value, $type = null, $isLocalized = false)
|
||||
{
|
||||
Services::get('context')->edit($this, [$name => $value], Application::get()->getRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get context main page views.
|
||||
*
|
||||
* @deprecated 3.4
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getViews()
|
||||
{
|
||||
$filters = [
|
||||
'dateStart' => StatisticsHelper::STATISTICS_EARLIEST_DATE,
|
||||
'dateEnd' => date('Y-m-d', strtotime('yesterday')),
|
||||
'contextIds' => [$this->getId()],
|
||||
];
|
||||
$metrics = Services::get('contextStats')
|
||||
->getQueryBuilder($filters)
|
||||
->getSum([])
|
||||
->value('metric');
|
||||
return $metrics ? $metrics : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to track usage statistics by institutions.
|
||||
* Consider context setting only if the site setting is enabled and context setting disabled (= false).
|
||||
*/
|
||||
public function isInstitutionStatsEnabled(Site $site): bool
|
||||
{
|
||||
$enableInstitutionUsageStats = $site->getData('enableInstitutionUsageStats');
|
||||
if ($enableInstitutionUsageStats &&
|
||||
($this->getData('enableInstitutionUsageStats') !== null) && !$this->getData('enableInstitutionUsageStats')) {
|
||||
$enableInstitutionUsageStats = $this->getData('enableInstitutionUsageStats');
|
||||
}
|
||||
return (bool) $enableInstitutionUsageStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* What Geo data to track for usage statistics.
|
||||
* Consider context setting only if the site setting is enabled and context setting considers less Geo data than site setting.
|
||||
*
|
||||
* @return ?string Possible return values: null, disabled, PKPStatisticsHelper::self::STATISTICS_SETTING_COUNTRY, PKPStatisticsHelper::self::STATISTICS_SETTING_REGION, PKPStatisticsHelper::self::STATISTICS_SETTING_CITY
|
||||
*/
|
||||
public function getEnableGeoUsageStats(Site $site): ?string
|
||||
{
|
||||
$siteSetting = $site->getData('enableGeoUsageStats');
|
||||
if ($siteSetting == null || $siteSetting === 'disabled') {
|
||||
return $siteSetting;
|
||||
}
|
||||
$contextSetting = $this->getData('enableGeoUsageStats');
|
||||
if ($contextSetting != null && str_starts_with($siteSetting, $contextSetting)) {
|
||||
return $contextSetting;
|
||||
}
|
||||
return $siteSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the required metadata for this context
|
||||
*
|
||||
* @return array List of metadata property names. Example: ['keywords']
|
||||
*/
|
||||
public function getRequiredMetadata(): array
|
||||
{
|
||||
return collect([
|
||||
'agencies',
|
||||
'citations',
|
||||
'coverage',
|
||||
'dataAvailability',
|
||||
'disciplines',
|
||||
'keywords',
|
||||
'languages',
|
||||
'rights',
|
||||
'source',
|
||||
'subjects',
|
||||
'type',
|
||||
])->filter(fn ($prop) => $this->getData($prop) === self::METADATA_REQUIRE)->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\context\Context', '\Context');
|
||||
foreach ([
|
||||
'METADATA_DISABLE',
|
||||
'METADATA_ENABLE',
|
||||
'METADATA_REQUEST',
|
||||
'METADATA_REQUIRE',
|
||||
] as $constantName) {
|
||||
define($constantName, constant('\Context::' . $constantName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/context/ContextDAO.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class ContextDAO
|
||||
*
|
||||
* @ingroup core
|
||||
*
|
||||
* @see DAO
|
||||
*
|
||||
* @brief Operations for retrieving and modifying context objects.
|
||||
*/
|
||||
|
||||
namespace PKP\context;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use PKP\db\DAOResultFactory;
|
||||
use PKP\db\SchemaDAO;
|
||||
use PKP\security\Role;
|
||||
|
||||
/**
|
||||
* @template T of Context
|
||||
* @extends SchemaDAO<T>
|
||||
*/
|
||||
abstract class ContextDAO extends SchemaDAO
|
||||
{
|
||||
/**
|
||||
* Retrieve the IDs and names of all contexts in an associative array.
|
||||
*
|
||||
* @param bool $enabledOnly true iff only enabled contexts are to be included
|
||||
*
|
||||
* @return array<int,string>
|
||||
*/
|
||||
public function getNames($enabledOnly = false)
|
||||
{
|
||||
$contexts = [];
|
||||
$iterator = $this->getAll($enabledOnly);
|
||||
while ($context = $iterator->next()) {
|
||||
$contexts[$context->getId()] = $context->getLocalizedName();
|
||||
}
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of localized settings.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getLocaleFieldNames()
|
||||
{
|
||||
return ['name', 'description'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a context exists
|
||||
*/
|
||||
public function exists(int $id): bool
|
||||
{
|
||||
return DB::table($this->tableName)
|
||||
->where($this->primaryKeyColumn, '=', $id)
|
||||
->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a context exists with a specified path.
|
||||
*
|
||||
* @param string $path the path for the context
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function existsByPath($path)
|
||||
{
|
||||
$result = $this->retrieve(
|
||||
'SELECT COUNT(*) AS row_count FROM ' . $this->tableName . ' WHERE path = ?',
|
||||
[(string) $path]
|
||||
);
|
||||
$row = $result->current();
|
||||
return $row ? (bool) $row->row_count : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a context by path.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return ?T
|
||||
*/
|
||||
public function getByPath($path)
|
||||
{
|
||||
$result = $this->retrieve(
|
||||
'SELECT * FROM ' . $this->tableName . ' WHERE path = ?',
|
||||
[(string) $path]
|
||||
);
|
||||
$row = (array) $result->current();
|
||||
return $row ? $this->_fromRow($row) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all contexts.
|
||||
*
|
||||
* @param bool $enabledOnly true iff only enabled contexts should be included
|
||||
* @param ?\PKP\db\DBResultRange $rangeInfo optional
|
||||
*
|
||||
* @return DAOResultFactory<T> containing matching Contexts
|
||||
*/
|
||||
public function getAll($enabledOnly = false, $rangeInfo = null)
|
||||
{
|
||||
$result = $this->retrieveRange(
|
||||
'SELECT * FROM ' . $this->tableName .
|
||||
($enabledOnly ? ' WHERE enabled = 1' : '') .
|
||||
' ORDER BY seq',
|
||||
[],
|
||||
$rangeInfo
|
||||
);
|
||||
|
||||
return new DAOResultFactory($result, $this, '_fromRow');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve available contexts.
|
||||
* If user-based contexts, retrieve all contexts assigned by user group
|
||||
* or all contexts for site admin
|
||||
* If not user-based, retrieve all enabled contexts.
|
||||
*
|
||||
* @param ?int $userId Optional user ID to find available contexts for
|
||||
* @param ?\PKP\db\DBResultRange $rangeInfo optional
|
||||
*
|
||||
* @return DAOResultFactory<T> containing matching Contexts
|
||||
*/
|
||||
public function getAvailable($userId = null, $rangeInfo = null)
|
||||
{
|
||||
$params = [];
|
||||
if ($userId) {
|
||||
$params = array_merge(
|
||||
$params,
|
||||
[(int) $userId, (int) $userId, (int) Role::ROLE_ID_SITE_ADMIN]
|
||||
);
|
||||
}
|
||||
|
||||
$result = $this->retrieveRange(
|
||||
'SELECT c.* FROM ' . $this->tableName . ' c
|
||||
WHERE ' .
|
||||
($userId ?
|
||||
'c.' . $this->primaryKeyColumn . ' IN (SELECT DISTINCT ug.context_id FROM user_groups ug JOIN user_user_groups uug ON (ug.user_group_id = uug.user_group_id) WHERE uug.user_id = ?)
|
||||
OR ? IN (SELECT user_id FROM user_groups ug JOIN user_user_groups uug ON (ug.user_group_id = uug.user_group_id) WHERE ug.role_id = ?)'
|
||||
: 'c.enabled = 1') .
|
||||
' ORDER BY seq',
|
||||
$params,
|
||||
$rangeInfo
|
||||
);
|
||||
|
||||
return new DAOResultFactory($result, $this, '_fromRow');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get journals by setting.
|
||||
*
|
||||
* @param string $settingName
|
||||
* @param ?int $contextId
|
||||
*
|
||||
* @return DAOResultFactory<T>
|
||||
*/
|
||||
public function getBySetting($settingName, $settingValue, $contextId = null)
|
||||
{
|
||||
$params = [$settingName, $settingValue];
|
||||
if ($contextId) {
|
||||
$params[] = $contextId;
|
||||
}
|
||||
|
||||
$result = $this->retrieve(
|
||||
'SELECT * FROM ' . $this->tableName . ' AS c
|
||||
LEFT JOIN ' . $this->settingsTableName . ' AS cs
|
||||
ON c.' . $this->primaryKeyColumn . ' = cs.' . $this->primaryKeyColumn .
|
||||
' WHERE cs.setting_name = ? AND cs.setting_value = ?' .
|
||||
($contextId ? ' AND c.' . $this->primaryKeyColumn . ' = ?' : ''),
|
||||
$params
|
||||
);
|
||||
|
||||
return new DAOResultFactory($result, $this, '_fromRow');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sequentially renumber each context according to their sequence order.
|
||||
*/
|
||||
public function resequence()
|
||||
{
|
||||
$result = $this->retrieve('SELECT ' . $this->primaryKeyColumn . ' AS context_id FROM ' . $this->tableName . ' ORDER BY seq');
|
||||
$i = 1;
|
||||
for ($i = 1; $row = (array) $result->current(); $i += 2 && $result->next()) {
|
||||
$this->update('UPDATE ' . $this->tableName . ' SET seq = ? WHERE ' . $this->primaryKeyColumn . ' = ?', [$i, $row['context_id']]);
|
||||
$result->next();
|
||||
$i += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\context\ContextDAO', '\ContextDAO');
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/context/LibraryFile.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class LibraryFile
|
||||
*
|
||||
* @ingroup context
|
||||
*
|
||||
* @see LibraryFileDAO
|
||||
*
|
||||
* @brief Library file class.
|
||||
*/
|
||||
|
||||
namespace PKP\context;
|
||||
|
||||
use PKP\config\Config;
|
||||
use PKP\file\FileManager;
|
||||
|
||||
class LibraryFile extends \PKP\core\DataObject
|
||||
{
|
||||
public const LIBRARY_FILE_TYPE_CONTRACT = 1;
|
||||
public const LIBRARY_FILE_TYPE_MARKETING = 2;
|
||||
public const LIBRARY_FILE_TYPE_PERMISSION = 3;
|
||||
public const LIBRARY_FILE_TYPE_REPORT = 4;
|
||||
public const LIBRARY_FILE_TYPE_OTHER = 5;
|
||||
|
||||
/**
|
||||
* Return absolute path to the file on the host filesystem.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFilePath()
|
||||
{
|
||||
$contextId = $this->getContextId();
|
||||
|
||||
return Config::getVar('files', 'files_dir') . '/contexts/' . $contextId . '/library/' . $this->getServerFileName();
|
||||
}
|
||||
|
||||
//
|
||||
// Get/set methods
|
||||
//
|
||||
/**
|
||||
* Get ID of context.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getContextId()
|
||||
{
|
||||
return $this->getData('contextId');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ID of context.
|
||||
*
|
||||
* @param int $contextId
|
||||
*/
|
||||
public function setContextId($contextId)
|
||||
{
|
||||
$this->setData('contextId', $contextId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ID of submission.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSubmissionId()
|
||||
{
|
||||
return $this->getData('submissionId');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ID of submission.
|
||||
*/
|
||||
public function setSubmissionId($submissionId)
|
||||
{
|
||||
$this->setData('submissionId', $submissionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server-side file name of the file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerFileName()
|
||||
{
|
||||
return $this->getData('fileName');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set server-side file name of the file.
|
||||
*
|
||||
* @param string $fileName
|
||||
*/
|
||||
public function setServerFileName($fileName)
|
||||
{
|
||||
$this->setData('fileName', $fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get original file name of the file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOriginalFileName()
|
||||
{
|
||||
return $this->getData('originalFileName');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set original file name of the file.
|
||||
*
|
||||
* @param string $originalFileName
|
||||
*/
|
||||
public function setOriginalFileName($originalFileName)
|
||||
{
|
||||
$this->setData('originalFileName', $originalFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the file
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $locale
|
||||
*/
|
||||
public function setName($name, $locale)
|
||||
{
|
||||
$this->setData('name', $name, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the file
|
||||
*
|
||||
* @param string $locale
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName($locale)
|
||||
{
|
||||
return $this->getData('name', $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the localized name of the file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLocalizedName()
|
||||
{
|
||||
return $this->getLocalizedData('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file type of the file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFileType()
|
||||
{
|
||||
return $this->getData('fileType');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file type of the file.
|
||||
*
|
||||
* @param string $fileType
|
||||
*/
|
||||
public function setFileType($fileType)
|
||||
{
|
||||
$this->setData('fileType', $fileType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type of the file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->getData('type');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set type of the file.
|
||||
*
|
||||
* @param string $type
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->setData('type', $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get uploaded date of file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDateUploaded()
|
||||
{
|
||||
return $this->getData('dateUploaded');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set uploaded date of file.
|
||||
*
|
||||
* @param string $dateUploaded
|
||||
*/
|
||||
public function setDateUploaded($dateUploaded)
|
||||
{
|
||||
return $this->SetData('dateUploaded', $dateUploaded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get modified date of file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDateModified()
|
||||
{
|
||||
return $this->getData('dateModified');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set modified date of file.
|
||||
*
|
||||
* @param string $dateModified
|
||||
*/
|
||||
public function setDateModified($dateModified)
|
||||
{
|
||||
return $this->SetData('dateModified', $dateModified);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file size of file.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getFileSize()
|
||||
{
|
||||
return $this->getData('fileSize');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set file size of file.
|
||||
*
|
||||
* @param int $fileSize
|
||||
*/
|
||||
public function setFileSize($fileSize)
|
||||
{
|
||||
return $this->SetData('fileSize', $fileSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get nice file size of file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNiceFileSize()
|
||||
{
|
||||
$fileManager = new FileManager();
|
||||
return $fileManager->getNiceFileSize($this->getData('fileSize'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file's document type (enumerated types)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDocumentType()
|
||||
{
|
||||
$fileManager = new FileManager();
|
||||
return $fileManager->getDocumentType($this->getFileType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get public access indication
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getPublicAccess()
|
||||
{
|
||||
return $this->getData('publicAccess');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set public access indication
|
||||
*
|
||||
* @param bool $publicAccess
|
||||
*/
|
||||
public function setPublicAccess($publicAccess)
|
||||
{
|
||||
$this->setData('publicAccess', $publicAccess);
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\context\LibraryFile', '\LibraryFile');
|
||||
foreach ([
|
||||
'LIBRARY_FILE_TYPE_CONTRACT',
|
||||
'LIBRARY_FILE_TYPE_MARKETING',
|
||||
'LIBRARY_FILE_TYPE_PERMISSION',
|
||||
'LIBRARY_FILE_TYPE_REPORT',
|
||||
'LIBRARY_FILE_TYPE_OTHER',
|
||||
] as $constantName) {
|
||||
if (!defined($constantName)) {
|
||||
define($constantName, constant('LibraryFile::' . $constantName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/context/LibraryFileDAO.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class LibraryFileDAO
|
||||
*
|
||||
* @ingroup context
|
||||
*
|
||||
* @see LibraryFile
|
||||
*
|
||||
* @brief Operations for retrieving and modifying LibraryFile objects.
|
||||
*/
|
||||
|
||||
namespace PKP\context;
|
||||
|
||||
use PKP\db\DAOResultFactory;
|
||||
use PKP\plugins\Hook;
|
||||
|
||||
class LibraryFileDAO extends \PKP\db\DAO
|
||||
{
|
||||
/**
|
||||
* Retrieve a library file by ID.
|
||||
*
|
||||
* @param int $fileId
|
||||
* @param int $contextId optional
|
||||
*
|
||||
* @return LibraryFile
|
||||
*/
|
||||
public function getById($fileId, $contextId = null)
|
||||
{
|
||||
$params = [(int) $fileId];
|
||||
if ($contextId) {
|
||||
$params[] = (int) $contextId;
|
||||
}
|
||||
|
||||
$result = $this->retrieve(
|
||||
'SELECT file_id, context_id, file_name, original_file_name, file_type, file_size, type, date_uploaded, submission_id, public_access FROM library_files WHERE file_id = ?'
|
||||
. ($contextId ? ' AND context_id = ?' : ''),
|
||||
$params
|
||||
);
|
||||
$row = $result->current();
|
||||
return $row ? $this->_fromRow((array) $row) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all library files for a context.
|
||||
*
|
||||
* @param int $contextId
|
||||
* @param string $type (optional)
|
||||
*
|
||||
* @return DAOResultFactory<LibraryFile> LibraryFiles
|
||||
*/
|
||||
public function getByContextId($contextId, $type = null)
|
||||
{
|
||||
$params = [(int) $contextId];
|
||||
if (isset($type)) {
|
||||
$params[] = (int) $type;
|
||||
}
|
||||
|
||||
$result = $this->retrieve(
|
||||
'SELECT *
|
||||
FROM library_files
|
||||
WHERE context_id = ? AND submission_id IS NULL ' . (isset($type) ? ' AND type = ?' : ''),
|
||||
$params
|
||||
);
|
||||
return new DAOResultFactory($result, $this, '_fromRow', ['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all library files for a submission.
|
||||
*
|
||||
* @param string $type (optional)
|
||||
* @param int $contextId (optional)
|
||||
*
|
||||
* @return DAOResultFactory<LibraryFile> LibraryFiles
|
||||
*/
|
||||
public function getBySubmissionId(int $submissionId, $type = null, $contextId = null)
|
||||
{
|
||||
$params = [(int) $submissionId];
|
||||
if (isset($type)) {
|
||||
$params[] = (int) $type;
|
||||
}
|
||||
if (isset($contextId)) {
|
||||
$params[] = (int) $contextId;
|
||||
}
|
||||
|
||||
$result = $this->retrieve(
|
||||
'SELECT *
|
||||
FROM library_files
|
||||
WHERE submission_id = ? ' . (isset($contextId) ? ' AND context_id = ?' : '') . (isset($type) ? ' AND type = ?' : ''),
|
||||
$params
|
||||
);
|
||||
return new DAOResultFactory($result, $this, '_fromRow', ['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new data object corresponding to this DAO.
|
||||
*
|
||||
* @return LibraryFile
|
||||
*/
|
||||
public function newDataObject()
|
||||
{
|
||||
return new LibraryFile();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the list of fields for which data is localized.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLocaleFieldNames()
|
||||
{
|
||||
return ['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the localized fields for this file.
|
||||
*
|
||||
* @param LibraryFile $libraryFile
|
||||
*/
|
||||
public function updateLocaleFields(&$libraryFile)
|
||||
{
|
||||
$this->updateDataObjectSettings(
|
||||
'library_file_settings',
|
||||
$libraryFile,
|
||||
['file_id' => $libraryFile->getId()]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to return a LibraryFile object from a row.
|
||||
*
|
||||
* @param array $row
|
||||
*
|
||||
* @return LibraryFile
|
||||
*/
|
||||
public function _fromRow($row)
|
||||
{
|
||||
$libraryFile = $this->newDataObject();
|
||||
|
||||
$libraryFile->setId($row['file_id']);
|
||||
$libraryFile->setContextId($row['context_id']);
|
||||
$libraryFile->setServerFileName($row['file_name']);
|
||||
$libraryFile->setOriginalFileName($row['original_file_name']);
|
||||
$libraryFile->setFileType($row['file_type']);
|
||||
$libraryFile->setFileSize($row['file_size']);
|
||||
$libraryFile->setType($row['type']);
|
||||
$libraryFile->setDateUploaded($this->datetimeFromDB($row['date_uploaded']));
|
||||
$libraryFile->setSubmissionId($row['submission_id']);
|
||||
$libraryFile->setPublicAccess($row['public_access']);
|
||||
|
||||
$this->getDataObjectSettings('library_file_settings', 'file_id', $row['file_id'], $libraryFile);
|
||||
|
||||
Hook::call('LibraryFileDAO::_fromRow', [&$libraryFile, &$row]);
|
||||
|
||||
return $libraryFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new LibraryFile.
|
||||
*
|
||||
* @param LibraryFile $libraryFile
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function insertObject($libraryFile)
|
||||
{
|
||||
$params = [
|
||||
(int) $libraryFile->getContextId(),
|
||||
$libraryFile->getServerFileName(),
|
||||
$libraryFile->getOriginalFileName(),
|
||||
$libraryFile->getFileType(),
|
||||
(int) $libraryFile->getFileSize(),
|
||||
(int) $libraryFile->getType(),
|
||||
$libraryFile->getSubmissionId() ? (int) $libraryFile->getSubmissionId() : null,
|
||||
(int) $libraryFile->getPublicAccess()
|
||||
];
|
||||
|
||||
if ($libraryFile->getId()) {
|
||||
$params[] = (int) $libraryFile->getId();
|
||||
}
|
||||
|
||||
$this->update(
|
||||
sprintf(
|
||||
'INSERT INTO library_files
|
||||
(context_id, file_name, original_file_name, file_type, file_size, type, submission_id, public_access, date_uploaded, date_modified' . ($libraryFile->getId() ? ', file_id' : '') . ')
|
||||
VALUES
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, %s, %s' . ($libraryFile->getId() ? ', ?' : '') . ')',
|
||||
$this->datetimeToDB($libraryFile->getDateUploaded()),
|
||||
$this->datetimeToDB($libraryFile->getDateModified())
|
||||
),
|
||||
$params
|
||||
);
|
||||
|
||||
if (!$libraryFile->getId()) {
|
||||
$libraryFile->setId($this->getInsertId());
|
||||
}
|
||||
|
||||
$this->updateLocaleFields($libraryFile);
|
||||
return $libraryFile->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a LibraryFile
|
||||
*
|
||||
* @param LibraryFile $libraryFile
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function updateObject($libraryFile)
|
||||
{
|
||||
$this->update(
|
||||
sprintf(
|
||||
'UPDATE library_files
|
||||
SET context_id = ?,
|
||||
file_name = ?,
|
||||
original_file_name = ?,
|
||||
file_type = ?,
|
||||
file_size = ?,
|
||||
type = ?,
|
||||
submission_id = ?,
|
||||
public_access = ?,
|
||||
date_uploaded = %s
|
||||
WHERE file_id = ?',
|
||||
$this->datetimeToDB($libraryFile->getDateUploaded())
|
||||
),
|
||||
[
|
||||
(int) $libraryFile->getContextId(),
|
||||
$libraryFile->getServerFileName(),
|
||||
$libraryFile->getOriginalFileName(),
|
||||
$libraryFile->getFileType(),
|
||||
(int) $libraryFile->getFileSize(),
|
||||
(int) $libraryFile->getType(),
|
||||
$libraryFile->getSubmissionId() ? (int) $libraryFile->getSubmissionId() : null,
|
||||
(int) $libraryFile->getPublicAccess(),
|
||||
(int) $libraryFile->getId()
|
||||
]
|
||||
);
|
||||
|
||||
$this->updateLocaleFields($libraryFile);
|
||||
return $libraryFile->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a library file by ID.
|
||||
*
|
||||
* @param int $revision
|
||||
*/
|
||||
public function deleteById($fileId, $revision = null)
|
||||
{
|
||||
$this->update('DELETE FROM library_files WHERE file_id = ?', [(int) $fileId]);
|
||||
$this->update('DELETE FROM library_file_settings WHERE file_id = ?', [(int) $fileId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file with this filename already exists
|
||||
*
|
||||
* @param int $contextId the context to check in.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function filenameExists($contextId, $fileName)
|
||||
{
|
||||
$result = $this->retrieve(
|
||||
'SELECT COUNT(*) AS row_count FROM library_files WHERE context_id = ? AND file_name = ?',
|
||||
[(int) $contextId, $fileName]
|
||||
);
|
||||
$row = $result->current();
|
||||
return $row ? (bool) $row->row_count : false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\context\LibraryFileDAO', '\LibraryFileDAO');
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/context/SubEditorsDAO.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class SubEditorsDAO
|
||||
*
|
||||
* @ingroup context
|
||||
*
|
||||
* @brief Base class associating sections, series and categories to sub editors.
|
||||
*/
|
||||
|
||||
namespace PKP\context;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\facades\Repo;
|
||||
use APP\notification\Notification;
|
||||
use APP\notification\NotificationManager;
|
||||
use APP\submission\Submission;
|
||||
use Exception;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use PKP\db\DAORegistry;
|
||||
use PKP\log\SubmissionEmailLogDAO;
|
||||
use PKP\log\SubmissionEmailLogEntry;
|
||||
use PKP\mail\mailables\EditorAssigned;
|
||||
use PKP\notification\NotificationSubscriptionSettingsDAO;
|
||||
use PKP\security\Role;
|
||||
use PKP\stageAssignment\StageAssignment;
|
||||
use PKP\stageAssignment\StageAssignmentDAO;
|
||||
use PKP\userGroup\UserGroup;
|
||||
|
||||
class SubEditorsDAO extends \PKP\db\DAO
|
||||
{
|
||||
/**
|
||||
* Insert a new sub editor.
|
||||
*
|
||||
* @param int $contextId
|
||||
* @param int $assocId
|
||||
* @param int $userId
|
||||
*/
|
||||
public function insertEditor($contextId, $assocId, $userId, $assocType, int $userGroupId)
|
||||
{
|
||||
return $this->update(
|
||||
'INSERT INTO subeditor_submission_group
|
||||
(context_id, assoc_id, user_id, assoc_type, user_group_id)
|
||||
VALUES
|
||||
(?, ?, ?, ?, ?)',
|
||||
[
|
||||
(int) $contextId,
|
||||
(int) $assocId,
|
||||
(int) $userId,
|
||||
(int) $assocType,
|
||||
$userGroupId,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a sub editor.
|
||||
*
|
||||
* @param int $contextId
|
||||
* @param int $assocId
|
||||
* @param int $userId
|
||||
* @param int $assocType Application::ASSOC_TYPE_SECTION or Application::ASSOC_TYPE_CATEGORY
|
||||
*/
|
||||
public function deleteEditor($contextId, $assocId, $userId, $assocType)
|
||||
{
|
||||
$this->update(
|
||||
'DELETE FROM subeditor_submission_group WHERE context_id = ? AND section_id = ? AND user_id = ? AND assoc_type = ?',
|
||||
[
|
||||
(int) $contextId,
|
||||
(int) $assocId,
|
||||
(int) $userId,
|
||||
(int) $assocType,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of all sub editors assigned to the specified submission group.
|
||||
*
|
||||
* @param int[] $assocIds Section or category ids
|
||||
* @param int $assocType Application::ASSOC_TYPE_SECTION or Application::ASSOC_TYPE_CATEGORY
|
||||
*
|
||||
* @return Collection result rows with userId and userGroupId columns
|
||||
*/
|
||||
public function getBySubmissionGroupIds(array $assocIds, int $assocType, int $contextId): Collection
|
||||
{
|
||||
return DB::table('subeditor_submission_group')
|
||||
->where('assoc_type', '=', $assocType)
|
||||
->where('context_id', '=', $contextId)
|
||||
->whereIn('assoc_id', $assocIds)
|
||||
->get(['user_id as userId', 'user_group_id as userGroupId']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all sub editors for a specified submission group in a context.
|
||||
*
|
||||
* @param int $assocId
|
||||
* @param int $assocType Application::ASSOC_TYPE_SECTION or Application::ASSOC_TYPE_CATEGORY
|
||||
* @param int $contextId
|
||||
*/
|
||||
public function deleteBySubmissionGroupId($assocId, $assocType, $contextId = null)
|
||||
{
|
||||
$params = [(int) $assocId, (int) $assocType];
|
||||
if ($contextId) {
|
||||
$params[] = (int) $contextId;
|
||||
}
|
||||
$this->update(
|
||||
'DELETE FROM subeditor_submission_group WHERE assoc_id = ? AND assoc_type = ?' .
|
||||
($contextId ? ' AND context_id = ?' : ''),
|
||||
$params
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all submission group assignments for the specified user.
|
||||
*/
|
||||
public function deleteByUserId(int $userId)
|
||||
{
|
||||
/**
|
||||
* This warning was added in 3.4 due to a change in the function signature.
|
||||
* It can be removed with the next LTS release.
|
||||
*
|
||||
* @deprecated 3.4
|
||||
*/
|
||||
if (func_num_args() !== 1) {
|
||||
throw new Exception('Invalid number of arguments passed to ' . self::class . '::' . __FUNCTION__);
|
||||
}
|
||||
|
||||
DB::table('subeditor_submission_group')
|
||||
->where('user_id', '=', $userId)
|
||||
->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all submission group assignments for a user group
|
||||
*/
|
||||
public function deleteByUserGroupId(int $userGroupId)
|
||||
{
|
||||
DB::table('subeditor_submission_group')
|
||||
->where('user_group_id', '=', $userGroupId)
|
||||
->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user is assigned to a specified submission group.
|
||||
*
|
||||
* @param int $contextId
|
||||
* @param int $assocId
|
||||
* @param int $userId
|
||||
* @param int $assocType optional Application::ASSOC_TYPE_SECTION or Application::ASSOC_TYPE_CATEGORY
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function editorExists($contextId, $assocId, $userId, $assocType)
|
||||
{
|
||||
$result = $this->retrieve(
|
||||
'SELECT COUNT(*) AS row_count FROM subeditor_submission_group WHERE context_id = ? AND section_id = ? AND user_id = ? AND assoc_id = ?',
|
||||
[(int) $contextId, (int) $assocId, (int) $userId, (int) $assocType]
|
||||
);
|
||||
$row = $result->current();
|
||||
return $row ? (bool) $row->row_count : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign editors to a submission
|
||||
*
|
||||
* Creates a stage assignment for each editorial user
|
||||
* configured in the section and category settings.
|
||||
*
|
||||
* @return Collection The user ids for editors that were assigned
|
||||
*/
|
||||
public function assignEditors(Submission $submission, Context $context): Collection
|
||||
{
|
||||
$publication = $submission->getCurrentPublication();
|
||||
$sectionIdPropName = Application::getSectionIdPropName();
|
||||
|
||||
$assignments = $this->getBySubmissionGroupIds(
|
||||
[$publication->getData($sectionIdPropName)],
|
||||
Application::ASSOC_TYPE_SECTION,
|
||||
$submission->getData('contextId')
|
||||
);
|
||||
|
||||
if (!empty($publication->getData('categoryIds'))) {
|
||||
$assignedToCategory = $this->getBySubmissionGroupIds(
|
||||
$publication->getData('categoryIds'),
|
||||
Application::ASSOC_TYPE_CATEGORY,
|
||||
$submission->getData('contextId')
|
||||
);
|
||||
$assignments = $assignments->merge($assignedToCategory);
|
||||
}
|
||||
|
||||
// Remove duplicate assignments for the same user in the
|
||||
// same user group by structuring the array with a key
|
||||
// that will cause duplicates to be overwritten
|
||||
$assignments = collect($assignments)->mapWithKeys(fn ($assignment, $key) => [$assignment->userId . '-' . $assignment->userGroupId => $assignment]);
|
||||
|
||||
$userGroups = Repo::userGroup()
|
||||
->getCollector()
|
||||
->filterByContextIds([$submission->getData('contextId')])
|
||||
->getMany();
|
||||
|
||||
$userGroupIds = $userGroups->keys();
|
||||
|
||||
$assignments = $assignments->filter(function ($assignment) use ($userGroupIds) {
|
||||
return Repo::userGroup()->userInGroup($assignment->userId, $assignment->userGroupId)
|
||||
&& $userGroupIds->contains($assignment->userGroupId);
|
||||
});
|
||||
|
||||
/** @var StageAssignmentDAO $stageAssignmentDao */
|
||||
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO');
|
||||
foreach ($assignments as $assignment) {
|
||||
$userGroup = $userGroups->first(fn (UserGroup $userGroup) => $userGroup->getId() == $assignment->userGroupId);
|
||||
$stageAssignmentDao->build($submission->getId(), $assignment->userGroupId, $assignment->userId, $userGroup->getRecommendOnly());
|
||||
}
|
||||
|
||||
// Update assignment notifications
|
||||
$notificationManager = new NotificationManager();
|
||||
$notificationManager->updateNotification(
|
||||
Application::get()->getRequest(),
|
||||
$notificationManager->getDecisionStageNotifications(),
|
||||
null,
|
||||
Application::ASSOC_TYPE_SUBMISSION,
|
||||
$submission->getId()
|
||||
);
|
||||
|
||||
// Send a notification to assigned users
|
||||
foreach ($assignments as $assignment) {
|
||||
$notificationManager->createNotification(
|
||||
Application::get()->getRequest(),
|
||||
$assignment->userId,
|
||||
Notification::NOTIFICATION_TYPE_SUBMISSION_SUBMITTED,
|
||||
$submission->getContextId(),
|
||||
Application::ASSOC_TYPE_SUBMISSION,
|
||||
$submission->getId()
|
||||
);
|
||||
}
|
||||
|
||||
// Send an email to assigned editors
|
||||
$editorAssignments = $stageAssignmentDao->getBySubmissionAndRoleIds(
|
||||
$submission->getId(),
|
||||
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR],
|
||||
WORKFLOW_STAGE_ID_SUBMISSION
|
||||
)->toArray();
|
||||
|
||||
$emailTemplate = Repo::emailTemplate()->getByKey($context->getId(), EditorAssigned::getEmailTemplateKey());
|
||||
if (count($editorAssignments) && $emailTemplate) {
|
||||
// Never notify the same user twice, even if they are assigned in multiple roles
|
||||
$notifiedEditors = [];
|
||||
|
||||
/** @var NotificationSubscriptionSettingsDAO $notificationSubscriptionSettingsDao */
|
||||
$notificationSubscriptionSettingsDao = DAORegistry::getDAO('NotificationSubscriptionSettingsDAO');
|
||||
$mailable = new EditorAssigned($context, $submission);
|
||||
$mailable
|
||||
->from($context->getData('contactEmail'), $context->getData('contactName'))
|
||||
->subject($emailTemplate->getLocalizedData('subject') ?? '')
|
||||
->body($emailTemplate->getLocalizedData('body') ?? '');
|
||||
|
||||
/** @var StageAssignment $editorAssignment */
|
||||
foreach ($editorAssignments as $editorAssignment) {
|
||||
$unsubscribed = in_array(
|
||||
Notification::NOTIFICATION_TYPE_SUBMISSION_SUBMITTED,
|
||||
$notificationSubscriptionSettingsDao->getNotificationSubscriptionSettings(
|
||||
NotificationSubscriptionSettingsDAO::BLOCKED_EMAIL_NOTIFICATION_KEY,
|
||||
$editorAssignment->getUserId(),
|
||||
$context->getId()
|
||||
)
|
||||
);
|
||||
|
||||
if ($unsubscribed || in_array($editorAssignment->getUserId(), $notifiedEditors)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$notifiedEditors[] = $editorAssignment->getUserId();
|
||||
|
||||
$recipient = Repo::user()->get($editorAssignment->getUserId());
|
||||
$mailable->recipients([$recipient]);
|
||||
|
||||
Mail::send($mailable);
|
||||
|
||||
/** @var SubmissionEmailLogDAO $logDao */
|
||||
$logDao = DAORegistry::getDAO('SubmissionEmailLogDAO');
|
||||
$logDao->logMailable(
|
||||
SubmissionEmailLogEntry::SUBMISSION_EMAIL_EDITOR_ASSIGN,
|
||||
$mailable,
|
||||
$submission
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $assignments->map(fn ($assignment) => $assignment->userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the section assigned sub editor's associated user groups ids for given section
|
||||
*
|
||||
* @return Collection Collection A list of user group IDs for each user, keyed by user ID.
|
||||
*/
|
||||
public function getAssignedUserGroupIds(int $contextId, int $assocType, int $assocId, int|array $userIds): Collection
|
||||
{
|
||||
return DB::table('subeditor_submission_group')
|
||||
->select(['user_id', 'user_group_id'])
|
||||
->where('assoc_type', $assocType)
|
||||
->where('context_id', $contextId)
|
||||
->where('assoc_id', $assocId)
|
||||
->whereIn('user_id', Arr::wrap($userIds))
|
||||
->get()
|
||||
->groupBy('user_id')
|
||||
->map(fn ($userGroups) => $userGroups->pluck('user_group_id'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\context\SubEditorsDAO', '\SubEditorsDAO');
|
||||
}
|
||||
Reference in New Issue
Block a user