Skip to content
This repository has been archived by the owner on Jun 7, 2024. It is now read-only.

Commit

Permalink
Merge pull request vanilla#11066 from vanilla/sync/2021-06-03-1622735316
Browse files Browse the repository at this point in the history
Syncing files from upstream.
  • Loading branch information
initvector authored Jun 3, 2021
2 parents d207ac1 + 0af480b commit 1ec76a2
Show file tree
Hide file tree
Showing 314 changed files with 8,862 additions and 2,826 deletions.
5 changes: 0 additions & 5 deletions .browserslistrc

This file was deleted.

13 changes: 0 additions & 13 deletions .circleci/scripts/generateRandomSiteId.php

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,4 @@ lerna-debug.log
git-diff.txt
phpcs-diff.json
.phpunit.result.cache
*.cookiejar
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ protected function fullSchema() {
'description' => 'An array of addons that are required to enable the addon.',
'items' => $requirementSchema,
],
'attributes:o' => [
'locale:s?',
],
'conflict:a?' => [
'type' => 'array',
'description' => 'An array of addons that conflict with this addon.',
Expand Down Expand Up @@ -109,6 +112,10 @@ protected function filterOutput(Addon $addon, $themeType = 'desktop') {
if (!empty($r['conflict'])) {
$r['conflict'] = $this->filterRequirements($r['conflict']);
}
$r['attributes'] = new \Vanilla\Attributes();
if ($addon->getType() === Addon::TYPE_LOCALE) {
$r['attributes']['locale'] = $r['locale'];
}

return $r;
}
Expand Down
68 changes: 68 additions & 0 deletions applications/dashboard/controllers/api/LocalesApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,57 @@ public function expandDisplayNames(array &$rows, array $locales) {
}
}

/**
* Get a single locale.
*
* @param string $id The locale to get.
* @return Data
* @throws \Garden\Web\Exception\HttpException Exception.
* @throws \Vanilla\Exception\PermissionException Exception.
*/
public function get(string $id): Data {
$this->permission('Garden.Settings.Manage');

$out = $this->schema($this->localeSchema(), ['LocaleConfig', 'out']);

$allLocales = $this->getEnabledLocales();
$this->checkLocaleExists($id, $allLocales);
$locale = array_column($allLocales, null, 'localeID')[$id];
$this->expandDisplayNames($locale, array_column($allLocales, 'localeKey'));

$locale = $this->getEventManager()->fireFilter('localesApiController_getOutput', $locale);
$locale = \Vanilla\ApiUtils::convertOutputKeys($locale);
$out->validate($locale);
return new Data($locale);
}

/**
* Patch a single locale.
*
* @param string $id The locale to patch.
* @param array $body The fields and values to patch.
* @return Data
* @throws \Garden\Schema\ValidationException Exception.
* @throws \Garden\Web\Exception\HttpException Exception.
* @throws \Vanilla\Exception\PermissionException Exception.
*/
public function patch(string $id, array $body): Data {
$this->permission('Garden.Settings.Manage');
$in = $this->schema(['type' => 'object'], ['LocaleConfigPatch', 'in']);
$out = $this->schema($this->localeSchema(), ['LocaleConfig', 'out']);
$body = $in->validate($body);

// Validate the locale exists.
$this->checkLocaleExists($id);

$this->getEventManager()->fire('localesApiController_patchData', $id, $body, $in);

$result = $this->get($id);
$validatedResult = $out->validate($result);

return new Data($validatedResult);
}

/**
* Get the translations for a locale.
*
Expand Down Expand Up @@ -195,4 +246,21 @@ public function validateLocale(string $locale, \Garden\Schema\ValidationField $v
}
return false;
}

/**
* Check that the given ID corresponds to an enabled locale.
*
* @param string $id
* @param array|null $enabledLocales
* @throws \Garden\Web\Exception\NotFoundException Throws an exception if the locale isn't found.
*/
private function checkLocaleExists(string $id, ?array $enabledLocales = null): void {
if (is_null($enabledLocales)) {
$enabledLocales = $this->getEnabledLocales();
}

if (!in_array($id, array_keys(array_column($enabledLocales, null, 'localeID')))) {
throw new \Garden\Web\Exception\NotFoundException("Locale");
}
}
}
14 changes: 12 additions & 2 deletions applications/dashboard/controllers/class.entrycontroller.php
Original file line number Diff line number Diff line change
Expand Up @@ -1150,8 +1150,18 @@ public function signIn($method = false, $arg1 = false) {

Gdn::userModel()->fireEvent('BeforeSignIn', ['UserID' => $user->UserID ?? false]);
Gdn::session()->start(val('UserID', $user), true, (bool)$this->Form->getFormValue('RememberMe'));
if (!Gdn::session()->checkPermission('Garden.SignIn.Allow')) {
$this->Form->addError('ErrorPermission');

if (BanModel::isBanned($user->Banned, BanModel::BAN_AUTOMATIC | BanModel::BAN_MANUAL)) {
// If account has been banned manually or by a ban rule.
$this->Form->addError('This account has been banned.');
Gdn::session()->end();
} else if (BanModel::isBanned($user->Banned, BanModel::BAN_WARNING)) {
// If account has been banned by the "Warnings and notes" plugin or similar.
$this->Form->addError('This account has been temporarily banned.');
Gdn::session()->end();
} else if (!Gdn::session()->checkPermission('Garden.SignIn.Allow')) {
// If account does not have the sign in permission
$this->Form->addError('Sorry, permission denied. This account cannot be accessed.');
Gdn::session()->end();
} else {
$clientHour = $this->Form->getFormValue('ClientHour');
Expand Down
8 changes: 7 additions & 1 deletion applications/dashboard/controllers/class.homecontroller.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,23 @@ private function clearNavigationPreferences() {
}

/**
* Present the user with a confirmation page that they are leaving the site.
*
* @param string $target
* @param bool $allowTrusted
*
* @throws Gdn_UserException Throw an exception if the domain is invalid.
*/
public function leaving($target = '') {
public function leaving($target = '', $allowTrusted = false) {
$target = str_replace("\xE2\x80\xAE", '', $target);
try {
$target = UrlUtils::domainAsAscii($target);
} catch (Exception $e) {
throw new Gdn_UserException(t('Url is invalid.'));
}
if ($allowTrusted && isTrustedDomain($target)) {
redirectTo($target, 302, false);
}
$this->setData('Target', anchor(htmlspecialchars($target), $target, '', ['rel' => 'nofollow']));
$this->title(t('Leaving'));
$this->removeCssFile('admin.css');
Expand Down
71 changes: 9 additions & 62 deletions applications/dashboard/controllers/class.settingscontroller.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ public function labs() {
$this->render('labs');
}

/**
* Render the language settings page.
*/
public function language() {
$this->permission('Garden.Settings.Manage');
$this->render('language');
}

/**
* Highlight menu path. Automatically run on every use.
*
Expand Down Expand Up @@ -743,67 +751,7 @@ public function bans($action = '', $search = '', $page = '', $iD = '') {
*/
public function layout() {
$this->permission('Garden.Settings.Manage');

// Page setup
$this->setHighlightRoute('dashboard/settings/layout');
$this->title(t('Homepage'));

$currentRoute = val('Destination', Gdn::router()->getRoute('DefaultController'), '');
$this->setData('CurrentTarget', $currentRoute);
if (!$this->Form->authenticatedPostBack()) {
$this->Form->setData([
'Target' => $currentRoute
]);
} else {
$newRoute = val('Target', $this->Form->formValues(), '');
Gdn::router()->deleteRoute('DefaultController');
Gdn::router()->setRoute('DefaultController', $newRoute, 'Internal');
$this->setData('CurrentTarget', $newRoute);

// Save the preferred layout setting
saveToConfig([
'Vanilla.Discussions.Layout' => val('DiscussionsLayout', $this->Form->formValues(), ''),
'Vanilla.Categories.Layout' => val('CategoriesLayout', $this->Form->formValues(), '')
]);

$this->informMessage(t("Your changes were saved successfully."));
}

/** @var \Vanilla\Site\SiteSectionModel $siteSectionModel */
$siteSectionModel = Gdn::getContainer()->get(\Vanilla\Site\SiteSectionModel::class);
$this->setData('defaultRouteOptions', $siteSectionModel->getDefaultRoutes());

// Add warnings for layouts that have been specified by the theme.
$themeManager = Gdn::themeManager();
$theme = $themeManager->enabledThemeInfo();
$layout = val('Layout', $theme);

$warningText = t('Your theme has specified the layout selected below. Changing the layout may make your theme look broken.');
$warningAlert = wrap($warningText, 'div', ['class' => 'alert alert-warning padded']);
$dangerText = t('Your theme recommends the %s layout, but you\'ve selected the %s layout. This may make your theme look broken.');
$dangerAlert = wrap($dangerText, 'div', ['class' => 'alert alert-danger padded']);

if (val('Discussions', $layout)) {
$dicussionsLayout = strtolower(val('Discussions', $layout));
if ($dicussionsLayout != c('Vanilla.Discussions.Layout')) {
$discussionsAlert = sprintf($dangerAlert, $dicussionsLayout, c('Vanilla.Discussions.Layout'));
} else {
$discussionsAlert = $warningAlert;
}
$this->setData('DiscussionsAlert', $discussionsAlert);
}

if (val('Categories', $layout)) {
$categoriesLayout = strtolower(val('Categories', $layout));
if ($categoriesLayout != c('Vanilla.Categories.Layout')) {
$categoriesAlert = sprintf($dangerAlert, $categoriesLayout, c('Vanilla.Categories.Layout'));
} else {
$categoriesAlert = $warningAlert;
}
$this->setData('CategoriesAlert', $categoriesAlert);
}

$this->render();
$this->render('layout');
}

/**
Expand Down Expand Up @@ -831,7 +779,6 @@ public function security() {
$configurationModel->setField([
self::CONFIG_TRUSTED_DOMAINS,
self::CONFIG_CSP_DOMAINS,
'Garden.Format.WarnLeaving',
HstsModel::MAX_AGE_KEY,
HstsModel::INCLUDE_SUBDOMAINS_KEY,
HstsModel::PRELOAD_KEY,
Expand Down
1 change: 1 addition & 0 deletions applications/dashboard/design/style-compat.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion applications/dashboard/design/style.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion applications/dashboard/models/BannerImageModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Vanilla\AliasLoader;
use Vanilla\Formatting\Formats\HtmlFormat;
use Vanilla\Formatting\FormatService;
use Vanilla\Site\SiteSectionModel;

/**
* Banner Image Model.
Expand Down Expand Up @@ -121,10 +122,16 @@ private static function getCategoryField($categoryID, string $field, $default =
*/
public static function getCurrentBannerImageLink(): string {
$controller = \Gdn::controller();
/** @var SiteSectionModel $siteSectionModel */
$siteSectionModel = Gdn::getContainer()->get(SiteSectionModel::class);
$currentSection = $siteSectionModel->getCurrentSiteSection();
$siteSectionBanner = $currentSection->getBannerImageLink();
$categoryID = $controller
? $controller->data('Category.CategoryID', $controller->data('ContextualCategoryID'))
: null;
$field = self::getCategoryField($categoryID, 'BannerImage', c(self::DEFAULT_CONFIG_KEY));
$isRootSiteSection = $categoryID === $currentSection->getCategoryID();
$defaultBanner = $siteSectionBanner ?: Gdn::config(BannerImageModel::DEFAULT_CONFIG_KEY);
$field = !$isRootSiteSection ? self::getCategoryField($categoryID, 'BannerImage', $defaultBanner) : $siteSectionBanner;
return $field ? \Gdn_Upload::url($field) : $field;
}

Expand Down
2 changes: 2 additions & 0 deletions applications/dashboard/models/UserPointsModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ public function queryLeaders(
'up.SlotType' => $slotType,
'up.Source' => 'Total',
'up.CategoryID' => $categoryID,
'up.Points > ' => 0,

])
->orderBy('up.Points', 'desc')
->limit($limit)
Expand Down
1 change: 1 addition & 0 deletions applications/dashboard/models/UserVisitUpdater.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public function updateVisit(int $userID, $clientHour = null) {
if ($userID == $this->session->UserID) {
$ip = \Gdn::request()->getIP();
$fields['LastIPAddress'] = ipEncode($ip);
$this->userModel->saveIP($userID, $ip);

if ($this->session->newVisit()) {
$fields['CountVisits'] = val('CountVisits', $user, 0) + 1;
Expand Down
4 changes: 2 additions & 2 deletions applications/dashboard/models/class.tagmodel.php
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ public function getPostTagSchema(): Schema {
$schema = Schema::parse([
'name:s',
'urlcode:s?',
'parentTagID:i?',
'type:s?'
'parentTagID:i|n?',
'type:s|n?',
]);
return $schema;
}
Expand Down
13 changes: 5 additions & 8 deletions applications/dashboard/models/class.usermodel.php
Original file line number Diff line number Diff line change
Expand Up @@ -3435,15 +3435,13 @@ public function searchByName($name, $sortField = 'name', $sortDirection = 'asc',

// Preserve existing % by escaping.
$name = trim($name);
$name = $this->escapeField($name);
if ($wildcardSearch) {
$name = rtrim($name, '*');
}

// Avoid potential pollution by resetting.
$this->SQL->reset();
$this->SQL->from('User');
if ($wildcardSearch) {
$name = $this->escapeField($name);
$name = rtrim($name, '*');
$this->SQL->like('Name', $name, 'right');
} else {
$this->SQL->where('Name', $name);
Expand Down Expand Up @@ -5635,7 +5633,7 @@ public function getPermissions($userID) {
$permissions = Gdn::permissionModel()->createPermissionInstance();
$permissionsKey = '';
$user = $this->getID($userID, DATASET_TYPE_ARRAY);

$isAdmin = $user && $user['Admin'] > 0;
if (Gdn::cache()->activeEnabled()) {
$permissionsIncrement = $this->getPermissionsIncrement();
$permissionsKey = formatString(self::USERPERMISSIONS_KEY, [
Expand All @@ -5646,15 +5644,14 @@ public function getPermissions($userID) {
$cachedPermissions = Gdn::cache()->get($permissionsKey);
if ($cachedPermissions !== Gdn_Cache::CACHEOP_FAILURE) {
$permissions->setPermissions($cachedPermissions);
$permissions->setAdmin($user['Admin'] > 0);
$permissions->setAdmin($isAdmin);
return $permissions;
}
}

$data = Gdn::permissionModel()->getPermissionsByUser($userID);
$permissions->setPermissions($data);
$admin = $user['Admin'] ?? null;
$permissions->setAdmin($admin > 0);
$permissions->setAdmin($isAdmin);

$this->EventArguments['UserID'] = $userID;
$this->EventArguments['Permissions'] = $permissions;
Expand Down
5 changes: 5 additions & 0 deletions applications/dashboard/openapi/addons.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ components:
- constraint
type: object
type: array
attributes:
type: object
properties:
locale:
type: string
description:
description: The addon's description
type: string
Expand Down
Loading

0 comments on commit 1ec76a2

Please sign in to comment.