1
0
mirror of https://github.com/flarum/core.git synced 2025-08-16 05:14:20 +02:00

Compare commits

..

18 Commits

Author SHA1 Message Date
Daniël Klabbers
535052e3dc v1.3.1 release changelog 2022-06-07 10:53:23 +02:00
Sami Mazouz
c2ba3bb7d5 fix(subscriptions): reply notifications not working (#3445)
* chore: subscriptions backend test infrastructure

* test: reply notification

* fix: fix reply notifications not working
2022-06-03 21:06:30 +02:00
flarum-bot
b7332895db Bundled output for commit 0a3f449f9e
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-06-02 12:44:15 +00:00
Sami Mazouz
0a3f449f9e fix: post mentions with deleted author not rendering (#3432) 2022-06-02 13:38:24 +01:00
naxvog
df1bdd2ad8 chore: point Font Awesome icons link to v5 (#3447)
Update Font Awesome link to represent to currently used major version in order to avoid confusion when choosing icons
2022-06-02 13:34:42 +01:00
flarum-bot
8e2a99c1eb Bundled output for commit e45547c649
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-06-02 01:47:22 +00:00
David Wheatley
e45547c649 docs: ItemList set methods throw errors when keys are not present 2022-06-02 02:43:15 +01:00
Sami Mazouz
29362ed924 fix: empty suspension message uses email template expecting one (#3433) 2022-05-26 18:52:19 +01:00
Sami Mazouz
eb4bac3b8f fix: settings extender working only with first instances (#3439)
* test: settings extender works not only with first extender instance
* fix: settings extender working only with first instances
2022-05-24 17:55:05 +01:00
flarum-bot
584884a3c9 Bundled output for commit 96ead2a4df
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-05-20 19:36:54 +00:00
Ian Morland
96ead2a4df Add priorities to UserCard (#3436) 2022-05-20 20:32:25 +01:00
flarum-bot
556f10ddd8 Bundled output for commit a79e2c20fe
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-05-20 19:06:33 +00:00
Sami Mazouz
a79e2c20fe fix: dropdown show results search button hidden while loading results (#3431) 2022-05-20 20:02:04 +01:00
Sami Mazouz
89b194034b fix: nickname regex validation not working (#3430)
* test: regex validation for nickname on registration
* fix: nickname regex validation not working
* test: regex validation works with valid inputs
2022-05-20 14:04:14 +01:00
flarum-bot
01c54b13c8 Bundled output for commit 24c8c65aa5
Includes transpiled JS/TS, and Typescript declaration files (typings).

[skip ci]
2022-05-19 23:53:18 +00:00
David Wheatley
24c8c65aa5 fix(typings): treat ColorPreview settings component type as specific string, not generic 2022-05-20 00:48:44 +01:00
David Wheatley
17de76f326 docs: add 1.2.1 to changelog and fix 1.3.0 diff link 2022-05-16 19:44:17 +01:00
Ngô Quốc Đạt
d3008d1e62 docs: correct links to documentation (#3426) 2022-05-16 18:49:59 +01:00
30 changed files with 341 additions and 31 deletions

View File

@@ -1,8 +1,24 @@
# Changelog
## [1.3.0](https://github.com/flarum/framework/compare/v1.2.0...v1.3.0)
## [1.3.1](https://github.com/flarum/framework/compare/v1.3.0...v1.3.1)
From v1.2.1 on all bundled Flarum extensions and flarum/core are merged into one mono repo.
### Changed
- UserCard now has ItemList for easier extending (https://github.com/flarum/framework/pull/3436)
### Fixed
- Button to go directly to all results page is hidden while API request for search hasn't completed (https://github.com/flarum/framework/pull/3431)
- Setting extender does not register modifications beyond first fluent call (https://github.com/flarum/framework/pull/3439)
- Link to font awesome icons list no longer works (https://github.com/flarum/framework/commit/df1bdd2ad84e992414c0e1e7be576558b4b0fe29)
- Mentions: mentions with deleted authors not showing (https://github.com/flarum/framework/pull/3432)
- Nicknames: regex validation isn't functional (https://github.com/flarum/framework/pull/3430)
- Subscriptions: reply notifications not working (https://github.com/flarum/framework/pull/3445)
- Suspend: not providing suspension reason breaks mail (https://github.com/flarum/framework/pull/3433)
<!-- One-time commit-based diff due to monorepo rework. Diffing against the 1.2.1 tag doesn't work due to unrelated histories. -->
## [1.3.0](https://github.com/flarum/framework/compare/33d939cb012716ed6309ea02236737ad4f25a75b...v1.3.0)
From v1.2.1 on all bundled Flarum extensions and `flarum/core` are merged into one monorepo. As a result of this, the full code diff linked above
looks rather complex and messy compared to the full list of changes made for this release.
### Added
- [A11Y] Added role feed to DiscussionList (https://github.com/flarum/framework/pull/3359)
@@ -30,6 +46,10 @@ From v1.2.1 on all bundled Flarum extensions and flarum/core are merged into one
- [A11Y] Tags: focus to input and layout of tag selection modal are off (https://github.com/flarum/framework/pull/3412)
- Subscriptions: searching inside the following page will search in all discussions (https://github.com/flarum/framework/pull/3376)
## [1.2.1](https://github.com/flarum/framework/compare/v1.2.0...v1.2.1)
### Fixed
- Don't escape single quotes in discussion title meta tags (60600f4d2b8f0c5dac94c329041427a0a08fad42)
## [1.2.0](https://github.com/flarum/framework/compare/v1.1.1...v1.2.0)

View File

@@ -125,10 +125,13 @@ class ConfigureMentions
{
$post = CommentPost::find($tag->getAttribute('id'));
if ($post && $post->user) {
if ($post) {
$tag->setAttribute('discussionid', (int) $post->discussion_id);
$tag->setAttribute('number', (int) $post->number);
$tag->setAttribute('displayname', $post->user->display_name);
if ($post->user) {
$tag->setAttribute('displayname', $post->user->display_name);
}
return true;
}

View File

@@ -40,7 +40,7 @@ class AddNicknameValidation
function ($attribute, $value, $fail) {
$regex = $this->settings->get('flarum-nicknames.regex');
if ($regex && ! preg_match_all("/$regex/", $value)) {
$this->translator->trans('flarum-nicknames.api.invalid_nickname_message');
$fail($this->translator->trans('flarum-nicknames.api.invalid_nickname_message'));
}
},
'min:'.$this->settings->get('flarum-nicknames.min'),

View File

@@ -74,4 +74,48 @@ class RegisterTest extends TestCase
$this->assertEquals(403, $response->getStatusCode());
}
/**
* @test
*/
public function cant_register_with_nickname_if_invalid_regex()
{
$this->setting('flarum-nicknames.set_on_registration', true);
$this->setting('flarum-nicknames.regex', '^[A-z]+$');
$response = $this->send(
$this->request('POST', '/register', [
'json' => [
'nickname' => '007',
'username' => 'test',
'password' => 'too-obscure',
'email' => 'test@machine.local',
]
])
);
$this->assertEquals(422, $response->getStatusCode());
}
/**
* @test
*/
public function can_register_with_nickname_if_valid_regex()
{
$this->setting('flarum-nicknames.set_on_registration', true);
$this->setting('flarum-nicknames.regex', '^[A-z]+$');
$response = $this->send(
$this->request('POST', '/register', [
'json' => [
'nickname' => 'Acme',
'username' => 'test',
'password' => 'too-obscure',
'email' => 'test@machine.local',
]
])
);
$this->assertEquals(201, $response->getStatusCode());
}
}

View File

@@ -51,7 +51,7 @@
"prettier": true,
"typescript": false,
"bundlewatch": false,
"backendTesting": false,
"backendTesting": true,
"editorConfig": true,
"styleci": true
}
@@ -64,5 +64,28 @@
}
],
"minimum-stability": "dev",
"prefer-stable": true
"prefer-stable": true,
"autoload-dev": {
"psr-4": {
"Flarum\\Subscriptions\\Tests\\": "tests/"
}
},
"scripts": {
"test": [
"@test:unit",
"@test:integration"
],
"test:unit": "phpunit -c tests/phpunit.unit.xml",
"test:integration": "phpunit -c tests/phpunit.integration.xml",
"test:setup": "@php tests/integration/setup.php"
},
"scripts-descriptions": {
"test": "Runs all tests.",
"test:unit": "Runs all unit tests.",
"test:integration": "Runs all integration tests.",
"test:setup": "Sets up a database for use with integration tests. Execute this only once."
},
"require-dev": {
"flarum/testing": "^1.0.0"
}
}

View File

@@ -49,7 +49,7 @@ class SendReplyNotification implements ShouldQueue
$notify = $discussion->readers()
->where('users.id', '!=', $post->user_id)
->where('discussion_user.subscription', 'follow')
->where('discussion_user.last_read_post_number', $this->lastPostNumber)
->where('discussion_user.last_read_post_number', $this->lastPostNumber - 1)
->get();
$notifications->sync(

View File

View File

@@ -0,0 +1,142 @@
<?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\Subscriptions\tests\integration\api\discussions;
use Carbon\Carbon;
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
use Flarum\User\User;
class ReplyNotificationTest extends TestCase
{
use RetrievesAuthorizedUsers;
protected function setUp(): void
{
parent::setUp();
$this->extension('flarum-subscriptions');
$this->prepareDatabase([
'users' => [
$this->normalUser(),
],
'discussions' => [
['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1, 'last_post_number' => 1, 'last_post_id' => 1],
['id' => 2, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 2, 'comment_count' => 1, 'last_post_number' => 1, 'last_post_id' => 2],
],
'posts' => [
['id' => 1, 'discussion_id' => 1, 'created_at' => Carbon::createFromDate(1975, 5, 21)->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>foo bar</p></t>', 'number' => 1],
['id' => 2, 'discussion_id' => 2, 'created_at' => Carbon::createFromDate(1975, 5, 21)->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '<t><p>foo bar</p></t>', 'number' => 1],
],
'discussion_user' => [
['discussion_id' => 1, 'user_id' => 1, 'last_read_post_number' => 1, 'subscription' => 'follow'],
['discussion_id' => 2, 'user_id' => 1, 'last_read_post_number' => 1, 'subscription' => 'follow'],
]
]);
}
/** @test */
public function replying_to_a_discussion_with_comment_post_as_last_post_sends_reply_notification()
{
$this->app();
/** @var User $mainUser */
$mainUser = User::query()->find(1);
$this->assertEquals(0, $this->getUnreadNotificationCount($mainUser));
$this->send(
$this->request('POST', '/api/posts', [
'authenticatedAs' => 2,
'json' => [
'data' => [
'attributes' => [
'content' => 'reply with predetermined content for automated testing - too-obscure',
],
'relationships' => [
'discussion' => ['data' => ['id' => 1]],
],
],
],
])
);
$this->assertEquals(1, $this->getUnreadNotificationCount($mainUser));
}
/** @test */
public function replying_to_a_discussion_with_event_post_as_last_post_sends_reply_notification()
{
$this->app();
/** @var User $mainUser */
$mainUser = User::query()->find(1);
// Rename the discussion to trigger an event post.
$this->send(
$this->request('POST', '/api/discussions/2', [
'authenticatedAs' => 1,
'json' => [
'data' => [
'attributes' => [
'title' => 'ACME',
],
],
],
])
);
// Mark as read
$this->send(
$this->request('POST', '/api/discussions/2', [
'authenticatedAs' => 1,
'json' => [
'data' => [
'attributes' => [
'lastReadPostNumber' => 2,
],
],
],
])
);
$this->assertEquals(0, $this->getUnreadNotificationCount($mainUser));
$this->send(
$this->request('POST', '/api/posts', [
'authenticatedAs' => 2,
'json' => [
'data' => [
'attributes' => [
'content' => 'reply with predetermined content for automated testing - too-obscure',
],
'relationships' => [
'discussion' => ['data' => ['id' => 2]],
],
],
],
])
);
$this->assertEquals(1, $this->getUnreadNotificationCount($mainUser));
}
/** @todo change after core no longer statically caches unread notification in the User class */
protected function getUnreadNotificationCount(User $user)
{
return $user->notifications()
->where('type', 'newPost')
->whereNull('read_at')
->where('is_deleted', false)
->whereSubjectVisibleTo($user)
->count();
}
}

View File

@@ -0,0 +1,16 @@
<?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 Flarum\Testing\integration\Setup\SetupScript;
require __DIR__.'/../../vendor/autoload.php';
$setup = new SetupScript();
$setup->run();

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="true"
stopOnFailure="false"
>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">../src/</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Flarum Integration Tests">
<directory suffix="Test.php">./integration</directory>
<exclude>./integration/tmp</exclude>
</testsuite>
</testsuites>
</phpunit>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">../src/</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Flarum Unit Tests">
<directory suffix="Test.php">./unit</directory>
</testsuite>
</testsuites>
<listeners>
<listener class="\Mockery\Adapter\Phpunit\TestListener" />
</listeners>
</phpunit>

View File

@@ -49,6 +49,7 @@ flarum-suspend:
# Translations in this namespace are used by suspension email notifications
email:
no_reason_given: No reason was given for this suspension.
suspended:
subject: Your account has been suspended
body: |

View File

@@ -1,4 +1,4 @@
{!! $translator->trans('flarum-suspend.email.suspended.body', [
'{recipient_display_name}' => $user->display_name,
'{suspension_message}' => $blueprint->user->suspend_message,
'{suspension_message}' => $blueprint->user->suspend_message ?? $translator->trans('flarum-suspend.email.no_reason_given'),
]) !!}

View File

@@ -40,7 +40,7 @@ export interface HTMLInputSettingsComponentOptions extends CommonSettingsItemOpt
declare const BooleanSettingTypes: readonly ["bool", "checkbox", "switch", "boolean"];
declare const SelectSettingTypes: readonly ["select", "dropdown", "selectdropdown"];
declare const TextareaSettingTypes: readonly ["textarea"];
declare const ColorPreviewSettingType = "color-preview";
declare const ColorPreviewSettingType: "color-preview";
/**
* Valid options for the setting component builder to generate a Switch.
*/

View File

@@ -78,7 +78,7 @@ export default class ItemList<T> {
/**
* Replaces an item's content, if the provided item key exists.
*
* If the provided `key` is not present, nothing will happen.
* If the provided `key` is not present, an error will be thrown.
*
* @param key The key of the item in the list
* @param content The item's new content
@@ -97,7 +97,7 @@ export default class ItemList<T> {
/**
* Replaces an item's priority, if the provided item key exists.
*
* If the provided `key` is not present, nothing will happen.
* If the provided `key` is not present, an error will be thrown.
*
* @param key The key of the item in the list
* @param priority The item's new priority
@@ -115,6 +115,8 @@ export default class ItemList<T> {
setPriority(key: string, priority: number): this;
/**
* Remove an item from the list.
*
* If the provided `key` is not present, nothing will happen.
*/
remove(key: string): this;
/**

2
framework/core/js/dist/admin.js generated vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
framework/core/js/dist/forum.js generated vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -77,7 +77,7 @@ export interface HTMLInputSettingsComponentOptions extends CommonSettingsItemOpt
const BooleanSettingTypes = ['bool', 'checkbox', 'switch', 'boolean'] as const;
const SelectSettingTypes = ['select', 'dropdown', 'selectdropdown'] as const;
const TextareaSettingTypes = ['textarea'] as const;
const ColorPreviewSettingType = 'color-preview';
const ColorPreviewSettingType = 'color-preview' as const;
/**
* Valid options for the setting component builder to generate a Switch.

View File

@@ -78,7 +78,7 @@ export default class EditGroupModal extends Modal {
<div className="Form-group">
<label>{app.translator.trans('core.admin.edit_group.icon_label')}</label>
<div className="helpText">
{app.translator.trans('core.admin.edit_group.icon_text', { a: <a href="https://fontawesome.com/icons?m=free" tabindex="-1" /> })}
{app.translator.trans('core.admin.edit_group.icon_text', { a: <a href="https://fontawesome.com/v5/search?m=free" tabindex="-1" /> })}
</div>
<input className="FormControl" placeholder="fas fa-bolt" bidi={this.icon} />
</div>,

View File

@@ -127,7 +127,7 @@ export default class ItemList<T> {
/**
* Replaces an item's content, if the provided item key exists.
*
* If the provided `key` is not present, nothing will happen.
* If the provided `key` is not present, an error will be thrown.
*
* @param key The key of the item in the list
* @param content The item's new content
@@ -154,7 +154,7 @@ export default class ItemList<T> {
/**
* Replaces an item's priority, if the provided item key exists.
*
* If the provided `key` is not present, nothing will happen.
* If the provided `key` is not present, an error will be thrown.
*
* @param key The key of the item in the list
* @param priority The item's new priority
@@ -181,6 +181,8 @@ export default class ItemList<T> {
/**
* Remove an item from the list.
*
* If the provided `key` is not present, nothing will happen.
*/
remove(key: string): this {
delete this._items[key];

View File

@@ -130,7 +130,7 @@ export default class Search<T extends SearchAttrs = SearchAttrs> extends Compone
const searchLabel = extractText(app.translator.trans('core.forum.header.search_placeholder'));
const isActive = !!currentSearch;
const shouldShowResults = !!(!this.loadingSources && this.searchState.getValue() && this.hasFocus);
const shouldShowResults = !!(this.searchState.getValue() && this.hasFocus);
const shouldShowClearButton = !!(!this.loadingSources && this.searchState.getValue());
return (

View File

@@ -89,11 +89,12 @@ export default class UserCard extends Component {
{online
? [icon('fas fa-circle'), ' ', app.translator.trans('core.forum.user.online_text')]
: [icon('far fa-clock'), ' ', humanTime(lastSeenAt)]}
</span>
</span>,
100
);
}
items.add('joined', app.translator.trans('core.forum.user.joined_date_text', { ago: humanTime(user.joinTime()) }));
items.add('joined', app.translator.trans('core.forum.user.joined_date_text', { ago: humanTime(user.joinTime()) }), 90);
return items;
}

View File

@@ -95,6 +95,8 @@ class Settings implements ExtenderInterface
$defaults->put($key, $value);
}
return $defaults;
});
}

View File

@@ -173,14 +173,16 @@ class SettingsTest extends TestCase
(new Extend\Settings())
->serializeToForum('customPrefix.unavailableCustomSetting3', 'custom-prefix.unavailable_custom_setting3')
->default('custom-prefix.unavailable_custom_setting3', 'extenderDefault')
->default('custom-prefix.unavailable_custom_setting100', 'extenderDefault100'),
(new Extend\Settings())
->default('custom-prefix.unavailable_custom_setting200', 'extenderDefault200')
);
$value = $this->app()
->getContainer()
->make('flarum.settings')
->get('custom-prefix.unavailable_custom_setting3', 'defaultParameterValue');
$settings = $this->app()->getContainer()->make('flarum.settings');
$this->assertEquals('extenderDefault', $value);
$this->assertEquals('extenderDefault', $settings->get('custom-prefix.unavailable_custom_setting3'));
$this->assertEquals('extenderDefault100', $settings->get('custom-prefix.unavailable_custom_setting100'));
$this->assertEquals('extenderDefault200', $settings->get('custom-prefix.unavailable_custom_setting200'));
}
/**

View File

@@ -1,6 +1,6 @@
<h2>Install Flarum</h2>
<p>Set up your forum by filling out your details below. If you have any trouble, get help on the <a href="https://flarum.org/docs/install.html" target="_blank">Flarum website</a>.</p>
<p>Set up your forum by filling out your details below. If you have any trouble, get help on the <a href="https://docs.flarum.org/install" target="_blank">Flarum website</a>.</p>
<form method="post">
<div id="error" style="display:none"></div>

View File

@@ -1,6 +1,6 @@
<h2>Hold Up!</h2>
<p>These problems must be resolved before you can continue the installation. If you're having trouble, get help on the <a href="https://flarum.org/docs/install.html" target="_blank">Flarum website</a>.</p>
<p>These problems must be resolved before you can continue the installation. If you're having trouble, get help on the <a href="https://docs.flarum.org/install" target="_blank">Flarum website</a>.</p>
<div class="Problems">
<?php foreach ($problems as $problem) { ?>

View File

@@ -1,6 +1,6 @@
<h2>Update Flarum</h2>
<p>Enter your database password to update Flarum. Before you proceed, you should <strong>back up your database</strong>. If you have any trouble, get help on the <a href="http://flarum.org/docs/update.html" target="_blank">Flarum website</a>.</p>
<p>Enter your database password to update Flarum. Before you proceed, you should <strong>back up your database</strong>. If you have any trouble, get help on the <a href="https://docs.flarum.org/update" target="_blank">Flarum website</a>.</p>
<form method="post">
<div id="error" style="display:none"></div>