mirror of
https://github.com/flarum/core.git
synced 2025-08-24 00:53:27 +02:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a94bf44072 | ||
|
ce82834a58 | ||
|
397642ab5a | ||
|
79e17b3bde | ||
|
c6ba2cd0d5 | ||
|
5d6795c353 | ||
|
d61c3cf277 | ||
|
a0b9add2d8 | ||
|
88abe63a8f | ||
|
9d00490591 | ||
|
7c1f55d985 | ||
|
345023242b | ||
|
00329eaee0 | ||
|
6c89f8161e | ||
|
8eb56b16cf | ||
|
634132e06e |
4
.github/workflows/REUSABLE_backend.yml
vendored
4
.github/workflows/REUSABLE_backend.yml
vendored
@@ -105,6 +105,8 @@ jobs:
|
|||||||
php_ini_values: error_reporting=E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED
|
php_ini_values: error_reporting=E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED
|
||||||
- php: 8.3
|
- php: 8.3
|
||||||
php_ini_values: error_reporting=E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED
|
php_ini_values: error_reporting=E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED
|
||||||
|
# - php: 8.4
|
||||||
|
# php_ini_values: error_reporting=E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED
|
||||||
|
|
||||||
# To reduce number of actions, we exclude some PHP versions from running with some DB versions.
|
# To reduce number of actions, we exclude some PHP versions from running with some DB versions.
|
||||||
exclude:
|
exclude:
|
||||||
@@ -177,6 +179,8 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
php: ${{ fromJSON(inputs.php_versions) }}
|
php: ${{ fromJSON(inputs.php_versions) }}
|
||||||
|
# exclude:
|
||||||
|
# - php: 8.4
|
||||||
|
|
||||||
name: 'PHPStan PHP ${{ matrix.php }}'
|
name: 'PHPStan PHP ${{ matrix.php }}'
|
||||||
|
|
||||||
|
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,5 +1,24 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [v1.8.9](https://github.com/flarum/framework/compare/v1.8.8...v1.8.9)
|
||||||
|
### Fixed
|
||||||
|
* change condition when unread label is shown in Scrubber (https://github.com/flarum/framework/pull/4116)
|
||||||
|
* resolve a11y warnings in Admin Frontend (https://github.com/flarum/framework/pull/4114)
|
||||||
|
* return empty object if selected mail driver is unavailable (https://github.com/flarum/framework/pull/4113)
|
||||||
|
### Changed
|
||||||
|
* change private to protected, allowing extensibility (https://github.com/flarum/framework/pull/4119)
|
||||||
|
* change length of email field (https://github.com/flarum/framework/pull/4117)
|
||||||
|
### Added
|
||||||
|
* Implement Support for Translatable Validation Attribute Errors (https://github.com/flarum/framework/pull/4070)
|
||||||
|
* PHP 8.4 support (https://github.com/flarum/framework/pull/4105)
|
||||||
|
* conditional extend whenExtensionDisabled (https://github.com/flarum/framework/pull/4107)
|
||||||
|
|
||||||
|
## [v1.8.8](https://github.com/flarum/framework/compare/v1.8.7...v1.8.8)
|
||||||
|
### Fixed
|
||||||
|
* previously suspended admin users cannot remove their avatar after suspension (https://github.com/flarum/framework/pull/4071)
|
||||||
|
* new search term not being passed (https://github.com/flarum/framework/pull/4083)
|
||||||
|
* postfooter did not apply the empty subclass (https://github.com/flarum/framework/pull/4085)
|
||||||
|
|
||||||
## [v1.8.7](https://github.com/flarum/framework/compare/v1.8.6...v1.8.7)
|
## [v1.8.7](https://github.com/flarum/framework/compare/v1.8.6...v1.8.7)
|
||||||
### Fixed
|
### Fixed
|
||||||
* BasicsPage not viewable if only one language pack enabled, and/or `flarum/nicknames` not enabled (https://github.com/flarum/framework/pull/4062)
|
* BasicsPage not viewable if only one language pack enabled, and/or `flarum/nicknames` not enabled (https://github.com/flarum/framework/pull/4062)
|
||||||
|
@@ -112,9 +112,9 @@
|
|||||||
"illuminate/view": "^8.0",
|
"illuminate/view": "^8.0",
|
||||||
"intervention/image": "2.5.* || ^2.6.1",
|
"intervention/image": "2.5.* || ^2.6.1",
|
||||||
"jenssegers/agent": "^2.6",
|
"jenssegers/agent": "^2.6",
|
||||||
"laminas/laminas-diactoros": "^2.4.1",
|
"laminas/laminas-diactoros": "^2.4.1 || ^3.0.0",
|
||||||
"laminas/laminas-httphandlerrunner": "^1.2.0 || ^2.3.0",
|
"laminas/laminas-httphandlerrunner": "^1.2.0 || ^2.3.0 || ^3.0.0",
|
||||||
"laminas/laminas-stratigility": "^3.2.2",
|
"laminas/laminas-stratigility": "^3.2.2 || ^4.0.0",
|
||||||
"league/flysystem": "^1.0.11",
|
"league/flysystem": "^1.0.11",
|
||||||
"matthiasmullie/minify": "^1.3",
|
"matthiasmullie/minify": "^1.3",
|
||||||
"middlewares/base-path": "^2.0.1",
|
"middlewares/base-path": "^2.0.1",
|
||||||
|
@@ -51,8 +51,7 @@ return [
|
|||||||
->belongsToMany('mentionedBy', Post::class, 'post_mentions_post', 'mentions_post_id', 'post_id')
|
->belongsToMany('mentionedBy', Post::class, 'post_mentions_post', 'mentions_post_id', 'post_id')
|
||||||
->belongsToMany('mentionsPosts', Post::class, 'post_mentions_post', 'post_id', 'mentions_post_id')
|
->belongsToMany('mentionsPosts', Post::class, 'post_mentions_post', 'post_id', 'mentions_post_id')
|
||||||
->belongsToMany('mentionsUsers', User::class, 'post_mentions_user', 'post_id', 'mentions_user_id')
|
->belongsToMany('mentionsUsers', User::class, 'post_mentions_user', 'post_id', 'mentions_user_id')
|
||||||
->belongsToMany('mentionsGroups', Group::class, 'post_mentions_group', 'post_id', 'mentions_group_id')
|
->belongsToMany('mentionsGroups', Group::class, 'post_mentions_group', 'post_id', 'mentions_group_id'),
|
||||||
->belongsToMany('mentionsUsers', User::class, 'post_mentions_user', 'post_id', 'mentions_user_id'),
|
|
||||||
|
|
||||||
new Extend\Locales(__DIR__.'/locale'),
|
new Extend\Locales(__DIR__.'/locale'),
|
||||||
|
|
||||||
|
@@ -161,3 +161,23 @@ flarum-extension-manager:
|
|||||||
|
|
||||||
why_not_modal:
|
why_not_modal:
|
||||||
title: Why Won't it Update
|
title: Why Won't it Update
|
||||||
|
|
||||||
|
validation:
|
||||||
|
attributes:
|
||||||
|
minimum_stability: minimum stability
|
||||||
|
repositories: repositories
|
||||||
|
repositories.*: repositories
|
||||||
|
repositories.*.type: repository type
|
||||||
|
repositories.*.url: repository URL
|
||||||
|
extension_id: extension ID
|
||||||
|
update_mode: update mode
|
||||||
|
package: package
|
||||||
|
version: version
|
||||||
|
github_oauth: GitHub OAuth
|
||||||
|
github_oauth.*: GitHub OAuth
|
||||||
|
gitlab_oauth: GitLab OAuth
|
||||||
|
gitlab_oauth.*: GitLab OAuth
|
||||||
|
gitlab_token: GitLab Token
|
||||||
|
gitlab_token.*: GitLab Token
|
||||||
|
bearer: HTTP Bearer
|
||||||
|
bearer.*: HTTP Bearer
|
||||||
|
@@ -69,3 +69,7 @@ flarum-suspend:
|
|||||||
You have been unsuspended. You can head back to the forum by clicking on the following link:
|
You have been unsuspended. You can head back to the forum by clicking on the following link:
|
||||||
|
|
||||||
{forum_url}
|
{forum_url}
|
||||||
|
|
||||||
|
validation:
|
||||||
|
attributes:
|
||||||
|
suspendedUntil: suspended until
|
||||||
|
2
extensions/tags/js/dist/admin.js
generated
vendored
2
extensions/tags/js/dist/admin.js
generated
vendored
File diff suppressed because one or more lines are too long
2
extensions/tags/js/dist/admin.js.map
generated
vendored
2
extensions/tags/js/dist/admin.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -16,7 +16,12 @@ function tagItem(tag) {
|
|||||||
<div className="TagListItem-info">
|
<div className="TagListItem-info">
|
||||||
{tagIcon(tag)}
|
{tagIcon(tag)}
|
||||||
<span className="TagListItem-name">{tag.name()}</span>
|
<span className="TagListItem-name">{tag.name()}</span>
|
||||||
<Button className="Button Button--link" icon="fas fa-pencil-alt" onclick={() => app.modal.show(EditTagModal, { model: tag })} />
|
<Button
|
||||||
|
className="Button Button--link"
|
||||||
|
icon="fas fa-pencil-alt"
|
||||||
|
aria-label={app.translator.trans('flarum-tags.admin.tags.edit_tag_label', { tag: tag.name() })}
|
||||||
|
onclick={() => app.modal.show(EditTagModal, { model: tag })}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!tag.isChild() && tag.position() !== null && (
|
{!tag.isChild() && tag.position() !== null && (
|
||||||
<ol className="TagListItem-children TagList">
|
<ol className="TagListItem-children TagList">
|
||||||
|
@@ -56,6 +56,7 @@ flarum-tags:
|
|||||||
about_tags_text: "Tags are used to categorize discussions. Primary tags are like traditional forum categories: they can be arranged in a two-level hierarchy. Secondary tags do not have hierarchy or order, and are useful for micro-categorization."
|
about_tags_text: "Tags are used to categorize discussions. Primary tags are like traditional forum categories: they can be arranged in a two-level hierarchy. Secondary tags do not have hierarchy or order, and are useful for micro-categorization."
|
||||||
create_primary_tag_button: Create Primary Tag
|
create_primary_tag_button: Create Primary Tag
|
||||||
create_secondary_tag_button: Create Secondary Tag
|
create_secondary_tag_button: Create Secondary Tag
|
||||||
|
edit_tag_label: Edit Tag {tag}
|
||||||
primary_heading: Primary Tags
|
primary_heading: Primary Tags
|
||||||
secondary_heading: Secondary Tags
|
secondary_heading: Secondary Tags
|
||||||
settings_heading: Settings
|
settings_heading: Settings
|
||||||
@@ -126,3 +127,13 @@ flarum-tags:
|
|||||||
choose_tags_placeholder: "{count, plural, one {Choose 1 more tag} other {Choose # more tags}}"
|
choose_tags_placeholder: "{count, plural, one {Choose 1 more tag} other {Choose # more tags}}"
|
||||||
name: Name
|
name: Name
|
||||||
tags: Tags
|
tags: Tags
|
||||||
|
|
||||||
|
validation:
|
||||||
|
attributes:
|
||||||
|
name: name
|
||||||
|
slug: slug
|
||||||
|
is_hidden: hidden
|
||||||
|
description: description
|
||||||
|
color: color
|
||||||
|
tag_count_primary: => validation.attributes.tag_count_primary
|
||||||
|
tag_count_secondary: => validation.attributes.tag_count_secondary
|
||||||
|
@@ -61,9 +61,9 @@
|
|||||||
"illuminate/view": "^8.0",
|
"illuminate/view": "^8.0",
|
||||||
"intervention/image": "2.5.* || ^2.6.1",
|
"intervention/image": "2.5.* || ^2.6.1",
|
||||||
"jenssegers/agent": "^2.6",
|
"jenssegers/agent": "^2.6",
|
||||||
"laminas/laminas-diactoros": "^2.4.1",
|
"laminas/laminas-diactoros": "^2.4.1 || ^3.0.0",
|
||||||
"laminas/laminas-httphandlerrunner": "^1.2.0 || ^2.3.0",
|
"laminas/laminas-httphandlerrunner": "^1.2.0 || ^2.3.0 || ^3.0.0",
|
||||||
"laminas/laminas-stratigility": "^3.2.2",
|
"laminas/laminas-stratigility": "^3.2.2 || ^4.0.0",
|
||||||
"league/flysystem": "^1.0.11",
|
"league/flysystem": "^1.0.11",
|
||||||
"matthiasmullie/minify": "^1.3",
|
"matthiasmullie/minify": "^1.3",
|
||||||
"middlewares/base-path": "^2.0.1",
|
"middlewares/base-path": "^2.0.1",
|
||||||
|
2
framework/core/js/dist/admin.js
generated
vendored
2
framework/core/js/dist/admin.js
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/admin.js.map
generated
vendored
2
framework/core/js/dist/admin.js.map
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/forum.js
generated
vendored
2
framework/core/js/dist/forum.js
generated
vendored
File diff suppressed because one or more lines are too long
2
framework/core/js/dist/forum.js.map
generated
vendored
2
framework/core/js/dist/forum.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -98,7 +98,7 @@ export default class MailPage<CustomAttrs extends IPageAttrs = IPageAttrs> exten
|
|||||||
|
|
||||||
contentItems(): ItemList<Mithril.Children> {
|
contentItems(): ItemList<Mithril.Children> {
|
||||||
const items = new ItemList<Mithril.Children>();
|
const items = new ItemList<Mithril.Children>();
|
||||||
const fields = this.driverFields![this.setting('mail_driver')()];
|
const fields = this.driverFields![this.setting('mail_driver')()] || {};
|
||||||
const fieldKeys = Object.keys(fields);
|
const fieldKeys = Object.keys(fields);
|
||||||
|
|
||||||
items.add(
|
items.add(
|
||||||
|
@@ -57,7 +57,12 @@ export default class PermissionGrid<CustomAttrs extends IPermissionGridAttrs = I
|
|||||||
<th>
|
<th>
|
||||||
{scope.label}{' '}
|
{scope.label}{' '}
|
||||||
{!!scope.onremove && (
|
{!!scope.onremove && (
|
||||||
<Button icon="fas fa-times" className="Button Button--text PermissionGrid-removeScope" onclick={scope.onremove} />
|
<Button
|
||||||
|
icon="fas fa-times"
|
||||||
|
className="Button Button--text PermissionGrid-removeScope"
|
||||||
|
aria-label={app.translator.trans('core.admin.permissions.remove_scope_label', { scope: scope.label })}
|
||||||
|
onclick={scope.onremove}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
|
@@ -41,7 +41,7 @@ export default class PostStreamScrubber extends Component {
|
|||||||
const newStyle = {
|
const newStyle = {
|
||||||
top: 100 - unreadPercent * 100 + '%',
|
top: 100 - unreadPercent * 100 + '%',
|
||||||
height: unreadPercent * 100 + '%',
|
height: unreadPercent * 100 + '%',
|
||||||
opacity: unreadPercent ? 1 : 0,
|
opacity: unreadPercent > 0 ? 1 : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (vnode.state.oldStyle) {
|
if (vnode.state.oldStyle) {
|
||||||
|
@@ -226,6 +226,7 @@ core:
|
|||||||
participate_heading: Participate
|
participate_heading: Participate
|
||||||
post_without_throttle_label: Reply multiple times without waiting
|
post_without_throttle_label: Reply multiple times without waiting
|
||||||
read_heading: Read
|
read_heading: Read
|
||||||
|
remove_scope_label: Remove scope of {scope}
|
||||||
rename_discussions_label: Rename discussions
|
rename_discussions_label: Rename discussions
|
||||||
reply_to_discussions_label: Reply to discussions
|
reply_to_discussions_label: Reply to discussions
|
||||||
search_users_label: => core.ref.search_users
|
search_users_label: => core.ref.search_users
|
||||||
|
@@ -79,6 +79,7 @@ validation:
|
|||||||
present: "The :attribute field must be present."
|
present: "The :attribute field must be present."
|
||||||
regex: "The :attribute format is invalid."
|
regex: "The :attribute format is invalid."
|
||||||
required: "The :attribute field is required."
|
required: "The :attribute field is required."
|
||||||
|
required_array_keys: "The :attribute array must contain entries for: :values."
|
||||||
required_if: "The :attribute field is required when :other is :value."
|
required_if: "The :attribute field is required when :other is :value."
|
||||||
required_unless: "The :attribute field is required unless :other is in :values."
|
required_unless: "The :attribute field is required unless :other is in :values."
|
||||||
required_with: "The :attribute field is required when :values is present."
|
required_with: "The :attribute field is required when :values is present."
|
||||||
|
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* For detailed copyright and license information, please view the
|
||||||
|
* LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Schema\Builder;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'up' => function (Builder $schema) {
|
||||||
|
$schema->table('users', function (Blueprint $table) {
|
||||||
|
$table->string('email', 254)->change();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
'down' => function (Builder $schema) {
|
||||||
|
$schema->table('users', function (Blueprint $table) {
|
||||||
|
$table->string('email', 150)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
];
|
@@ -47,6 +47,20 @@ class Conditional implements ExtenderInterface
|
|||||||
}, $extenders);
|
}, $extenders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply extenders only if a specific extension is disabled/not installed.
|
||||||
|
*
|
||||||
|
* @param string $extensionId The ID of the extension.
|
||||||
|
* @param ExtenderInterface[]|callable|string $extenders A callable returning an array of extenders, or an invokable class string.
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function whenExtensionDisabled(string $extensionId, $extenders): self
|
||||||
|
{
|
||||||
|
return $this->when(function (ExtensionManager $extensions) use ($extensionId) {
|
||||||
|
return ! $extensions->isEnabled($extensionId);
|
||||||
|
}, $extenders);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply extenders based on a condition.
|
* Apply extenders based on a condition.
|
||||||
*
|
*
|
||||||
|
@@ -333,6 +333,19 @@ class Extension implements Arrayable
|
|||||||
return $this->composerJsonAttribute('extra.flarum-extension.title');
|
return $this->composerJsonAttribute('extra.flarum-extension.title');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getNamespace(): ?string
|
||||||
|
{
|
||||||
|
return Collection::make($this->composerJsonAttribute('autoload.psr-4'))
|
||||||
|
->filter(function ($source) {
|
||||||
|
return $source === 'src/';
|
||||||
|
})
|
||||||
|
->keys()
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@@ -62,7 +62,7 @@ class ResponseFactory
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function makeResponse(array $payload): HtmlResponse
|
protected function makeResponse(array $payload): ResponseInterface
|
||||||
{
|
{
|
||||||
$content = sprintf(
|
$content = sprintf(
|
||||||
'<script>window.close(); window.opener.app.authenticationComplete(%s);</script>',
|
'<script>window.close(); window.opener.app.authenticationComplete(%s);</script>',
|
||||||
@@ -72,7 +72,7 @@ class ResponseFactory
|
|||||||
return new HtmlResponse($content);
|
return new HtmlResponse($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function makeLoggedInResponse(User $user)
|
protected function makeLoggedInResponse(User $user)
|
||||||
{
|
{
|
||||||
$response = $this->makeResponse(['loggedIn' => true]);
|
$response = $this->makeResponse(['loggedIn' => true]);
|
||||||
|
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
namespace Flarum\Foundation;
|
namespace Flarum\Foundation;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Cache\Store as Cache;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Validation\Factory;
|
use Illuminate\Validation\Factory;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
@@ -16,6 +17,13 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||||||
|
|
||||||
abstract class AbstractValidator
|
abstract class AbstractValidator
|
||||||
{
|
{
|
||||||
|
use ExtensionIdTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public static $CORE_VALIDATION_CACHE_KEY = 'core.validation.extension_id_class_names';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@@ -81,6 +89,30 @@ abstract class AbstractValidator
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getAttributeNames()
|
||||||
|
{
|
||||||
|
$cache = resolve(Cache::class);
|
||||||
|
|
||||||
|
if ($cache->get(self::$CORE_VALIDATION_CACHE_KEY) !== null) {
|
||||||
|
return $cache->get(self::$CORE_VALIDATION_CACHE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
$extId = $this->getClassExtensionId();
|
||||||
|
$attributeNames = [];
|
||||||
|
|
||||||
|
foreach (array_keys($this->rules) as $attribute) {
|
||||||
|
$key = $extId ? "$extId.validation.attributes.$attribute" : "validation.attributes.$attribute";
|
||||||
|
$attributeNames[$attribute] = $this->translator->trans($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache->forever(self::$CORE_VALIDATION_CACHE_KEY, $attributeNames);
|
||||||
|
|
||||||
|
return $attributeNames;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a new validator instance for this model.
|
* Make a new validator instance for this model.
|
||||||
*
|
*
|
||||||
@@ -92,6 +124,7 @@ abstract class AbstractValidator
|
|||||||
$rules = Arr::only($this->getRules(), array_keys($attributes));
|
$rules = Arr::only($this->getRules(), array_keys($attributes));
|
||||||
|
|
||||||
$validator = $this->validator->make($attributes, $rules, $this->getMessages());
|
$validator = $this->validator->make($attributes, $rules, $this->getMessages());
|
||||||
|
$validator->setAttributeNames($this->getAttributeNames());
|
||||||
|
|
||||||
foreach ($this->configuration as $callable) {
|
foreach ($this->configuration as $callable) {
|
||||||
$callable($this, $validator);
|
$callable($this, $validator);
|
||||||
|
@@ -21,7 +21,7 @@ class Application
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const VERSION = '1.8.8';
|
const VERSION = '1.8.9';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IoC container for the Flarum application.
|
* The IoC container for the Flarum application.
|
||||||
|
31
framework/core/src/Foundation/ExtensionIdTrait.php
Normal file
31
framework/core/src/Foundation/ExtensionIdTrait.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* For detailed copyright and license information, please view the
|
||||||
|
* LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Flarum\Foundation;
|
||||||
|
|
||||||
|
use Flarum\Extension\Extension;
|
||||||
|
use Flarum\Extension\ExtensionManager;
|
||||||
|
|
||||||
|
trait ExtensionIdTrait
|
||||||
|
{
|
||||||
|
protected function getClassExtensionId(): ?string
|
||||||
|
{
|
||||||
|
$extensions = resolve(ExtensionManager::class);
|
||||||
|
|
||||||
|
return $extensions->getExtensions()
|
||||||
|
->mapWithKeys(function (Extension $extension) {
|
||||||
|
return [$extension->getId() => $extension->getNamespace()];
|
||||||
|
})
|
||||||
|
->filter(function ($namespace) {
|
||||||
|
return $namespace && str_starts_with(static::class, $namespace);
|
||||||
|
})
|
||||||
|
->keys()
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
}
|
@@ -139,6 +139,71 @@ class CreateTest extends TestCase
|
|||||||
$this->assertEquals(1, $user->is_email_confirmed);
|
$this->assertEquals(1, $user->is_email_confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function admin_can_create_user_with_longest_valid_email()
|
||||||
|
{
|
||||||
|
$localPart = str_repeat('a', 64);
|
||||||
|
$domain = str_repeat('a', 61).'.'.str_repeat('a', 60).'.'.str_repeat('a', 60).'.local';
|
||||||
|
$email = $localPart.'@'.$domain;
|
||||||
|
|
||||||
|
$response = $this->send(
|
||||||
|
$this->request(
|
||||||
|
'POST',
|
||||||
|
'/api/users',
|
||||||
|
[
|
||||||
|
'authenticatedAs' => 1,
|
||||||
|
'json' => [
|
||||||
|
'data' => [
|
||||||
|
'attributes' => [
|
||||||
|
'username' => 'test',
|
||||||
|
'password' => 'too-obscure',
|
||||||
|
'email' => $email,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(201, $response->getStatusCode());
|
||||||
|
|
||||||
|
/** @var User $user */
|
||||||
|
$user = User::where('username', 'test')->firstOrFail();
|
||||||
|
|
||||||
|
$this->assertEquals($email, $user->email);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function admin_cannot_create_user_with_invalid_email_length()
|
||||||
|
{
|
||||||
|
$email = str_repeat('a', 65).'@'.str_repeat('a', 256).'.local';
|
||||||
|
|
||||||
|
$response = $this->send(
|
||||||
|
$this->request(
|
||||||
|
'POST',
|
||||||
|
'/api/users',
|
||||||
|
[
|
||||||
|
'authenticatedAs' => 1,
|
||||||
|
'json' => [
|
||||||
|
'data' => [
|
||||||
|
'attributes' => [
|
||||||
|
'username' => 'test',
|
||||||
|
'password' => 'too-obscure',
|
||||||
|
'email' => $email,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(422, $response->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
|
@@ -160,6 +160,27 @@ class ConditionalTest extends TestCase
|
|||||||
$this->app();
|
$this->app();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function conditional_disabled_extension_not_enabled_applies_extender()
|
||||||
|
{
|
||||||
|
$this->extend(
|
||||||
|
(new Extend\Conditional())
|
||||||
|
->whenExtensionDisabled('flarum-dummy-extension', TestExtender::class)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->app();
|
||||||
|
|
||||||
|
$response = $this->send(
|
||||||
|
$this->request('GET', '/api', [
|
||||||
|
'authenticatedAs' => 1,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
$payload = json_decode($response->getBody()->getContents(), true);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('customConditionalAttribute', $payload['data']['attributes']);
|
||||||
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
public function conditional_does_not_instantiate_extender_if_condition_is_false_using_callable()
|
public function conditional_does_not_instantiate_extender_if_condition_is_false_using_callable()
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user