mirror of
https://github.com/flarum/core.git
synced 2025-08-27 10:05:47 +02:00
Compare commits
201 Commits
v0.1.0-bet
...
1236-user-
Author | SHA1 | Date | |
---|---|---|---|
|
4eaf9ae23f | ||
|
4d80700e97 | ||
|
8ad95a4dfb | ||
|
03faaaedef | ||
|
5c3a0e3e6e | ||
|
588f7498e1 | ||
|
8d1240559b | ||
|
7ad8eb7544 | ||
|
ebd2c69c8d | ||
|
637ae1624c | ||
|
0c9bcba3a6 | ||
|
5b3acfc0d9 | ||
|
7adfb5bd7e | ||
|
6b916065e9 | ||
|
f99f48b155 | ||
|
d2c345c834 | ||
|
966a093911 | ||
|
0560238945 | ||
|
63801484fa | ||
|
f8d92edc9a | ||
|
e1dbfa7d68 | ||
|
ef7623e4ff | ||
|
d7fd076220 | ||
|
30a2421749 | ||
|
1bf6e79b32 | ||
|
8aaa39bd4e | ||
|
b1e11830d1 | ||
|
3375f283eb | ||
|
df4c193ab7 | ||
|
5a8326f442 | ||
|
d8dd870efe | ||
|
60572b93fb | ||
|
810bfdc28f | ||
|
9c4a24b258 | ||
|
18462c079f | ||
|
10d6e653cb | ||
|
4e1f753f59 | ||
|
3c2dd23765 | ||
|
aebc23cba2 | ||
|
f6d03771cb | ||
|
54be9573ac | ||
|
bf46ea3840 | ||
|
bab49650e6 | ||
|
a789c6b4e9 | ||
|
3b3459ad3d | ||
|
223f4d93d4 | ||
|
5d1fe9b815 | ||
|
521834f5da | ||
|
622e2a6644 | ||
|
c5e38a5b1f | ||
|
9d2595d531 | ||
|
3526083320 | ||
|
82562294b7 | ||
|
51ae92f841 | ||
|
6448babaa5 | ||
|
f7feea496d | ||
|
75e624d7ca | ||
|
5a01b63c99 | ||
|
cae4a6eb45 | ||
|
36d6d79011 | ||
|
22c599b283 | ||
|
456f5095da | ||
|
0b3ce2e7d0 | ||
|
607eeb530d | ||
|
5f4efe3c66 | ||
|
fac61b5bce | ||
|
ea64de5952 | ||
|
ff6c407e53 | ||
|
c4ba13f608 | ||
|
cef46ec357 | ||
|
5788c7373e | ||
|
8fdd8a1089 | ||
|
dc31a0a076 | ||
|
29eb233dd1 | ||
|
f6e48fa054 | ||
|
1b5e8f221a | ||
|
f903487ef3 | ||
|
1da4b72eac | ||
|
55bdad55fc | ||
|
b603c7b336 | ||
|
a530c52fb4 | ||
|
f7dc716042 | ||
|
a72f87d7ee | ||
|
5dbe97630c | ||
|
23709a77a2 | ||
|
29a2c247a1 | ||
|
a7f97c14ec | ||
|
8fcd62955b | ||
|
618e91805f | ||
|
431ab9f3e8 | ||
|
4f06133d75 | ||
|
bf79f2474c | ||
|
1b74e43cb9 | ||
|
3643e2010b | ||
|
58299edc20 | ||
|
18774e0b10 | ||
|
86d890d043 | ||
|
ab0ba707e7 | ||
|
04b2cf4462 | ||
|
28e3ec4014 | ||
|
a6decb2350 | ||
|
1e55361539 | ||
|
e80f5429d0 | ||
|
108a23c1eb | ||
|
1dd329982a | ||
|
e0c2ef5e64 | ||
|
d654517c91 | ||
|
0232d949e9 | ||
|
6363753d0f | ||
|
0918b04fe2 | ||
|
929d7b87c1 | ||
|
544f687cf4 | ||
|
a7ed625d16 | ||
|
a67eca0c9e | ||
|
855dd2445a | ||
|
1a3d955b4f | ||
|
8db91e3395 | ||
|
d725012a84 | ||
|
5a03cd865a | ||
|
0a32a96207 | ||
|
1587d48e59 | ||
|
b750554011 | ||
|
db7e28d316 | ||
|
14e89546ca | ||
|
92642519d4 | ||
|
f779f4d092 | ||
|
7b73036441 | ||
|
8b628be507 | ||
|
51f4bcdcb0 | ||
|
47a528305b | ||
|
6121229c6f | ||
|
df7f1291a7 | ||
|
52e73b2481 | ||
|
d08f851c0b | ||
|
22b32bd601 | ||
|
6797770c75 | ||
|
4cab48c0fd | ||
|
f7222d7e20 | ||
|
53c728b184 | ||
|
1d525d0a78 | ||
|
301e571772 | ||
|
e7c12ce928 | ||
|
5d5ebc088e | ||
|
6e62240153 | ||
|
17d1942c5c | ||
|
e786e297ef | ||
|
2829618814 | ||
|
5875b31fd5 | ||
|
ae59bf549f | ||
|
d45bf04341 | ||
|
7f9588af62 | ||
|
17dfb58590 | ||
|
c5e3e26d07 | ||
|
5d768db6d2 | ||
|
6e089c12d4 | ||
|
5ddb843eb2 | ||
|
bbeacc0299 | ||
|
82480457ce | ||
|
685459c0bc | ||
|
347edcf2cd | ||
|
731a038f29 | ||
|
af5113eb7b | ||
|
ddfb2c1ec1 | ||
|
6cf3c1088d | ||
|
2f174edfd0 | ||
|
2c231aa475 | ||
|
1e5c7e54ee | ||
|
408043a203 | ||
|
9b449386d6 | ||
|
f1d9753aee | ||
|
54f733ca80 | ||
|
a737b98e7f | ||
|
80546b9ed7 | ||
|
9758dfac47 | ||
|
970c0f5604 | ||
|
42a7f2f586 | ||
|
3611fa1bb9 | ||
|
c881f9f633 | ||
|
0a22a66189 | ||
|
64b53fb0ac | ||
|
627724839d | ||
|
fa3915fa53 | ||
|
1948b7e6f4 | ||
|
4465e7648b | ||
|
aef56c055a | ||
|
dd3a4173a1 | ||
|
7c204c82ab | ||
|
12fff33763 | ||
|
603367a41a | ||
|
6bdebfbf3c | ||
|
58ab6052ad | ||
|
3737ce8146 | ||
|
ca5404db76 | ||
|
d6fc3a91a6 | ||
|
31134ca16d | ||
|
6cfc9182f4 | ||
|
caa63107ad | ||
|
0acab8f1c7 | ||
|
c19b2e99bd | ||
|
e7a5e1e5e2 | ||
|
209c4c6143 |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
github: flarum
|
||||
open_collective: flarum
|
||||
tidelift: packagist/flarum/core
|
26
.github/stale.yml
vendored
Normal file
26
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
daysUntilStale: 90
|
||||
daysUntilClose: 30
|
||||
|
||||
staleLabel: stale
|
||||
|
||||
exemptLabels:
|
||||
- org/keep
|
||||
- type/bug
|
||||
- type/regression
|
||||
- critical
|
||||
- security
|
||||
exemptAssignees: true
|
||||
exemptMilestones: true
|
||||
exemptProjects: true
|
||||
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. We do this
|
||||
to keep the amount of open issues to a manageable minimum.
|
||||
|
||||
In any case, thanks for taking an interest in this software and contributing
|
||||
by opening the issue in the first place!
|
||||
|
||||
closeComment: >
|
||||
We are closing this issue as it seems to have grown stale. If you still
|
||||
encounter this problem with the latest version, feel free to re-open it.
|
@@ -1,6 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## [0.1.0-beta.11](https://github.com/flarum/core/compare/v0.1.0-beta.11...v0.1.0-beta.11.1)
|
||||
## [0.1.0-beta.11.1](https://github.com/flarum/core/compare/v0.1.0-beta.11...v0.1.0-beta.11.1)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Stichting Flarum (Flarum Foundation)
|
||||
Copyright (c) 2019-2020 Stichting Flarum (Flarum Foundation)
|
||||
Copyright (c) 2014-2019 Toby Zerner (toby.zerner@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
@@ -27,7 +27,7 @@ Thank you for considering contributing to Flarum! Please read the **[Contributin
|
||||
|
||||
## Security Vulnerabilities
|
||||
|
||||
If you discover a security vulnerability within Flarum, please send an e-mail to [security@flarum.org](mailto:security@flarum.org). All security vulnerabilities will be promptly addressed.
|
||||
If you discover a security vulnerability within Flarum, please send an e-mail to [security@flarum.org](mailto:security@flarum.org). All security vulnerabilities will be promptly addressed. More details can be found in our [security policy](https://github.com/flarum/core/security/policy).
|
||||
|
||||
## License
|
||||
|
||||
|
@@ -46,6 +46,10 @@
|
||||
"illuminate/validation": "5.7.*",
|
||||
"illuminate/view": "5.7.*",
|
||||
"intervention/image": "^2.3.0",
|
||||
"laminas/laminas-diactoros": "^1.8.4",
|
||||
"laminas/laminas-httphandlerrunner": "^1.0",
|
||||
"laminas/laminas-stratigility": "^3.0",
|
||||
"laminas/laminas-zendframework-bridge": "^1.0",
|
||||
"league/flysystem": "^1.0.11",
|
||||
"matthiasmullie/minify": "^1.3",
|
||||
"middlewares/base-path": "^1.1",
|
||||
@@ -63,10 +67,7 @@
|
||||
"symfony/event-dispatcher": "^4.3.2",
|
||||
"symfony/translation": "^3.3",
|
||||
"symfony/yaml": "^3.3",
|
||||
"tobscure/json-api": "^0.3.0",
|
||||
"zendframework/zend-diactoros": "^1.8.4",
|
||||
"zendframework/zend-httphandlerrunner": "^1.0",
|
||||
"zendframework/zend-stratigility": "^3.0"
|
||||
"tobscure/json-api": "^0.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.0",
|
||||
|
20
js/dist/admin.js
vendored
20
js/dist/admin.js
vendored
File diff suppressed because one or more lines are too long
2
js/dist/admin.js.map
vendored
2
js/dist/admin.js.map
vendored
File diff suppressed because one or more lines are too long
22
js/dist/forum.js
vendored
22
js/dist/forum.js
vendored
File diff suppressed because one or more lines are too long
2
js/dist/forum.js.map
vendored
2
js/dist/forum.js.map
vendored
File diff suppressed because one or more lines are too long
777
js/package-lock.json
generated
777
js/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@
|
||||
"moment": "^2.22.2",
|
||||
"punycode": "^2.1.1",
|
||||
"spin.js": "^3.1.0",
|
||||
"webpack": "^4.26.0",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-cli": "^3.1.2",
|
||||
"webpack-merge": "^4.1.4"
|
||||
},
|
||||
|
@@ -29,12 +29,13 @@ export default class MailPage extends Page {
|
||||
{}
|
||||
);
|
||||
|
||||
Object.keys(this.driverFields).flatMap(key => this.driverFields[key]).forEach(
|
||||
key => {
|
||||
this.fields.push(key);
|
||||
this.values[key] = m.prop(settings[key]);
|
||||
for (const driver in this.driverFields) {
|
||||
for (const field in this.driverFields[driver]) {
|
||||
this.fields.push(field);
|
||||
this.values[field] = m.prop(settings[field]);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
m.redraw();
|
||||
});
|
||||
@@ -87,9 +88,9 @@ export default class MailPage extends Page {
|
||||
className: 'MailPage-MailSettings',
|
||||
children: [
|
||||
<div className="MailPage-MailSettings-input">
|
||||
{this.driverFields[this.values.mail_driver()].flatMap(field => [
|
||||
{Object.keys(this.driverFields[this.values.mail_driver()]).map(field => [
|
||||
<label>{app.translator.trans(`core.admin.email.${field}_label`)}</label>,
|
||||
<input className="FormControl" value={this.values[field]() || ''} oninput={m.withAttr('value', this.values[field])} />
|
||||
this.renderField(field),
|
||||
])}
|
||||
</div>
|
||||
]
|
||||
@@ -108,6 +109,18 @@ export default class MailPage extends Page {
|
||||
);
|
||||
}
|
||||
|
||||
renderField(name) {
|
||||
const driver = this.values.mail_driver();
|
||||
const field = this.driverFields[driver][name];
|
||||
const prop = this.values[name];
|
||||
|
||||
if (typeof field === 'string') {
|
||||
return <input className="FormControl" value={prop() || ''} oninput={m.withAttr('value', prop)}/>;
|
||||
} else {
|
||||
return <Select value={prop()} options={field} onchange={prop} />;
|
||||
}
|
||||
}
|
||||
|
||||
changed() {
|
||||
return this.fields.some(key => this.values[key]() !== app.data.settings[key]);
|
||||
}
|
||||
|
@@ -16,6 +16,10 @@ export function truncate(string, length, start = 0) {
|
||||
* Create a slug out of the given string. Non-alphanumeric characters are
|
||||
* converted to hyphens.
|
||||
*
|
||||
* NOTE: This method does not use the comparably sophisticated transliteration
|
||||
* mechanism that is employed in the backend. Therefore, it should only be used
|
||||
* to *suggest* slugs that can be overridden by the user.
|
||||
*
|
||||
* @param {String} string
|
||||
* @return {String}
|
||||
*/
|
||||
|
@@ -102,7 +102,7 @@ export default class ReplyComposer extends ComposerBody {
|
||||
app.alerts.show(
|
||||
alert = new Alert({
|
||||
type: 'success',
|
||||
message: app.translator.trans('core.forum.composer_reply.posted_message'),
|
||||
children: app.translator.trans('core.forum.composer_reply.posted_message'),
|
||||
controls: [viewButton]
|
||||
})
|
||||
);
|
||||
|
@@ -88,8 +88,13 @@ export default class UserPage extends Page {
|
||||
loadUser(username) {
|
||||
const lowercaseUsername = username.toLowerCase();
|
||||
|
||||
// Load the preloaded user object, if any, into the global app store
|
||||
// We don't use the output of the method because it returns raw JSON
|
||||
// instead of the parsed models
|
||||
app.preloadedApiDocument();
|
||||
|
||||
app.store.all('users').some(user => {
|
||||
if (user.username().toLowerCase() === lowercaseUsername && user.joinTime()) {
|
||||
if ((user.username().toLowerCase() === lowercaseUsername || user.id() === username) && user.joinTime()) {
|
||||
this.show(user);
|
||||
return true;
|
||||
}
|
||||
|
@@ -7,9 +7,9 @@
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Flarum\Util\Str;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Schema\Builder;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
'up' => function (Builder $schema) {
|
||||
|
@@ -0,0 +1,28 @@
|
||||
<?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->create('notification_preferences', function (Blueprint $table) {
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->string('type');
|
||||
$table->string('channel');
|
||||
$table->boolean('enabled')->default(false);
|
||||
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
});
|
||||
},
|
||||
|
||||
'down' => function (Builder $schema) {
|
||||
$schema->drop('notification_preferences');
|
||||
}
|
||||
];
|
@@ -0,0 +1,27 @@
|
||||
<?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->boolean('disclose_online')->default(false);
|
||||
$table->string('locale')->nullable();
|
||||
});
|
||||
},
|
||||
|
||||
'down' => function (Builder $schema) {
|
||||
$schema->table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('disclose_online');
|
||||
$table->dropColumn('locale');
|
||||
});
|
||||
}
|
||||
];
|
@@ -0,0 +1,52 @@
|
||||
<?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\Builder;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
'up' => function (Builder $builder) {
|
||||
$db = $builder->getConnection();
|
||||
|
||||
$db->table('users')
|
||||
->select(['id', 'preferences'])
|
||||
->whereNotNull('preferences')
|
||||
->orderBy('id')
|
||||
->each(function ($user) use ($db) {
|
||||
collect(json_decode($user->preferences ?? '{}'))
|
||||
->each(function ($value, $key) use ($user, $db) {
|
||||
if (in_array($key, ['discloseOnline', 'followAfterReply'])) {
|
||||
$db->table('users')
|
||||
->where('id', $user->id)
|
||||
->update([Str::snake($key) => (bool) $value]);
|
||||
}
|
||||
if ($key === 'locale') {
|
||||
$db->table('users')
|
||||
->where('id', $user->id)
|
||||
->update(['locale' => $value]);
|
||||
}
|
||||
if (preg_match('/^notify_(?<type>[^_]+)_(?<channel>.*)$/', $key, $matches)) {
|
||||
$db->table('notification_preferences')
|
||||
->insert([
|
||||
'user_id' => $user->id,
|
||||
'type' => $matches['type'],
|
||||
'channel' => $matches['channel'],
|
||||
'enabled' => (bool) $value
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
'down' => function (Builder $builder) {
|
||||
$db = $builder->getConnection();
|
||||
|
||||
$db->table('notification_preferences')->truncate();
|
||||
}
|
||||
];
|
@@ -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->dropColumn('preferences');
|
||||
});
|
||||
},
|
||||
|
||||
'down' => function (Builder $schema) {
|
||||
$schema->table('users', function (Blueprint $table) {
|
||||
$table->binary('preferences')->nullable();
|
||||
});
|
||||
}
|
||||
];
|
@@ -29,7 +29,7 @@ use Flarum\Http\RouteHandlerFactory;
|
||||
use Flarum\Http\UrlGenerator;
|
||||
use Flarum\Locale\LocaleManager;
|
||||
use Flarum\Settings\Event\Saved;
|
||||
use Zend\Stratigility\MiddlewarePipe;
|
||||
use Laminas\Stratigility\MiddlewarePipe;
|
||||
|
||||
class AdminServiceProvider extends AbstractServiceProvider
|
||||
{
|
||||
@@ -49,7 +49,19 @@ class AdminServiceProvider extends AbstractServiceProvider
|
||||
return $routes;
|
||||
});
|
||||
|
||||
$this->app->singleton('flarum.admin.middleware', function (Application $app) {
|
||||
$this->app->singleton('flarum.admin.middleware', function () {
|
||||
return [
|
||||
HttpMiddleware\ParseJsonBody::class,
|
||||
HttpMiddleware\StartSession::class,
|
||||
HttpMiddleware\RememberFromCookie::class,
|
||||
HttpMiddleware\AuthenticateWithSession::class,
|
||||
HttpMiddleware\CheckCsrfToken::class,
|
||||
HttpMiddleware\SetLocale::class,
|
||||
Middleware\RequireAdministrateAbility::class,
|
||||
];
|
||||
});
|
||||
|
||||
$this->app->singleton('flarum.admin.handler', function (Application $app) {
|
||||
$pipe = new MiddlewarePipe;
|
||||
|
||||
// All requests should first be piped through our global error handler
|
||||
@@ -59,21 +71,15 @@ class AdminServiceProvider extends AbstractServiceProvider
|
||||
$app->tagged(Reporter::class)
|
||||
));
|
||||
|
||||
$pipe->pipe($app->make(HttpMiddleware\ParseJsonBody::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\StartSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\RememberFromCookie::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\CheckCsrfToken::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\SetLocale::class));
|
||||
$pipe->pipe($app->make(Middleware\RequireAdministrateAbility::class));
|
||||
foreach ($this->app->make('flarum.admin.middleware') as $middleware) {
|
||||
$pipe->pipe($this->app->make($middleware));
|
||||
}
|
||||
|
||||
event(new ConfigureMiddleware($pipe, 'admin'));
|
||||
|
||||
return $pipe;
|
||||
});
|
||||
|
||||
$this->app->afterResolving('flarum.admin.middleware', function (MiddlewarePipe $pipe) {
|
||||
$pipe->pipe(new HttpMiddleware\DispatchRoute($this->app->make('flarum.admin.routes')));
|
||||
|
||||
return $pipe;
|
||||
});
|
||||
|
||||
$this->app->bind('flarum.assets.admin', function () {
|
||||
|
@@ -25,7 +25,7 @@ use Flarum\Http\Middleware as HttpMiddleware;
|
||||
use Flarum\Http\RouteCollection;
|
||||
use Flarum\Http\RouteHandlerFactory;
|
||||
use Flarum\Http\UrlGenerator;
|
||||
use Zend\Stratigility\MiddlewarePipe;
|
||||
use Laminas\Stratigility\MiddlewarePipe;
|
||||
|
||||
class ApiServiceProvider extends AbstractServiceProvider
|
||||
{
|
||||
@@ -45,7 +45,20 @@ class ApiServiceProvider extends AbstractServiceProvider
|
||||
return $routes;
|
||||
});
|
||||
|
||||
$this->app->singleton('flarum.api.middleware', function (Application $app) {
|
||||
$this->app->singleton('flarum.api.middleware', function () {
|
||||
return [
|
||||
HttpMiddleware\ParseJsonBody::class,
|
||||
Middleware\FakeHttpMethods::class,
|
||||
HttpMiddleware\StartSession::class,
|
||||
HttpMiddleware\RememberFromCookie::class,
|
||||
HttpMiddleware\AuthenticateWithSession::class,
|
||||
HttpMiddleware\AuthenticateWithHeader::class,
|
||||
HttpMiddleware\CheckCsrfToken::class,
|
||||
HttpMiddleware\SetLocale::class,
|
||||
];
|
||||
});
|
||||
|
||||
$this->app->singleton('flarum.api.handler', function (Application $app) {
|
||||
$pipe = new MiddlewarePipe;
|
||||
|
||||
$pipe->pipe(new HttpMiddleware\HandleErrors(
|
||||
@@ -54,22 +67,15 @@ class ApiServiceProvider extends AbstractServiceProvider
|
||||
$app->tagged(Reporter::class)
|
||||
));
|
||||
|
||||
$pipe->pipe($app->make(HttpMiddleware\ParseJsonBody::class));
|
||||
$pipe->pipe($app->make(Middleware\FakeHttpMethods::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\StartSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\RememberFromCookie::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithHeader::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\CheckCsrfToken::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\SetLocale::class));
|
||||
foreach ($this->app->make('flarum.api.middleware') as $middleware) {
|
||||
$pipe->pipe($this->app->make($middleware));
|
||||
}
|
||||
|
||||
event(new ConfigureMiddleware($pipe, 'api'));
|
||||
|
||||
return $pipe;
|
||||
});
|
||||
|
||||
$this->app->afterResolving('flarum.api.middleware', function (MiddlewarePipe $pipe) {
|
||||
$pipe->pipe(new HttpMiddleware\DispatchRoute($this->app->make('flarum.api.routes')));
|
||||
|
||||
return $pipe;
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -15,10 +15,10 @@ use Flarum\Foundation\ErrorHandling\Registry;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use InvalidArgumentException;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Throwable;
|
||||
use Zend\Diactoros\ServerRequestFactory;
|
||||
|
||||
class Client
|
||||
{
|
||||
|
@@ -9,10 +9,10 @@
|
||||
|
||||
namespace Flarum\Api\Controller;
|
||||
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
|
||||
abstract class AbstractDeleteController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -11,10 +11,10 @@ namespace Flarum\Api\Controller;
|
||||
|
||||
use Flarum\Foundation\Console\CacheClearCommand;
|
||||
use Flarum\User\AssertPermissionTrait;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
|
||||
class ClearCacheController extends AbstractDeleteController
|
||||
{
|
||||
|
@@ -15,10 +15,10 @@ use Flarum\User\UserRepository;
|
||||
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcher;
|
||||
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\JsonResponse;
|
||||
|
||||
class CreateTokenController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -12,10 +12,10 @@ namespace Flarum\Api\Controller;
|
||||
use Flarum\Foundation\Application;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Flarum\User\AssertPermissionTrait;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use League\Flysystem\Adapter\Local;
|
||||
use League\Flysystem\Filesystem;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
|
||||
class DeleteFaviconController extends AbstractDeleteController
|
||||
{
|
||||
|
@@ -12,10 +12,10 @@ namespace Flarum\Api\Controller;
|
||||
use Flarum\Foundation\Application;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Flarum\User\AssertPermissionTrait;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use League\Flysystem\Adapter\Local;
|
||||
use League\Flysystem\Filesystem;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
|
||||
class DeleteLogoController extends AbstractDeleteController
|
||||
{
|
||||
|
@@ -13,10 +13,10 @@ use Flarum\User\Command\RequestPasswordReset;
|
||||
use Flarum\User\UserRepository;
|
||||
use Illuminate\Contracts\Bus\Dispatcher;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
|
||||
class ForgotPasswordController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -17,11 +17,11 @@ use Flarum\User\Exception\PermissionDeniedException;
|
||||
use Illuminate\Contracts\Mail\Mailer;
|
||||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
|
||||
class SendConfirmationEmailController implements RequestHandlerInterface
|
||||
{
|
||||
@@ -86,9 +86,9 @@ class SendConfirmationEmailController implements RequestHandlerInterface
|
||||
|
||||
$body = $this->translator->trans('core.email.activate_account.body', $data);
|
||||
|
||||
$this->mailer->raw($body, function (Message $message) use ($actor, $data) {
|
||||
$this->mailer->raw($body, function (Message $message) use ($actor) {
|
||||
$message->to($actor->email);
|
||||
$message->subject('['.$data['{forum}'].'] '.$this->translator->trans('core.email.activate_account.subject'));
|
||||
$message->subject($this->translator->trans('core.email.activate_account.subject'));
|
||||
});
|
||||
|
||||
return new EmptyResponse;
|
||||
|
@@ -12,10 +12,10 @@ namespace Flarum\Api\Controller;
|
||||
use Flarum\Group\Permission;
|
||||
use Flarum\User\AssertPermissionTrait;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
|
||||
class SetPermissionController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -13,10 +13,10 @@ use Flarum\Settings\Event;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Flarum\User\AssertPermissionTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
|
||||
class SetSettingsController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -12,10 +12,10 @@ namespace Flarum\Api\Controller;
|
||||
use Flarum\Extension\ExtensionManager;
|
||||
use Flarum\User\AssertPermissionTrait;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\EmptyResponse;
|
||||
|
||||
class UpdateExtensionController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -9,8 +9,8 @@
|
||||
|
||||
namespace Flarum\Api;
|
||||
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Tobscure\JsonApi\Document;
|
||||
use Zend\Diactoros\Response\JsonResponse;
|
||||
|
||||
class JsonApiResponse extends JsonResponse
|
||||
{
|
||||
|
@@ -33,10 +33,20 @@ class MailDriverSerializer extends AbstractSerializer
|
||||
);
|
||||
}
|
||||
|
||||
$driver = $driver['driver'];
|
||||
$settings = $driver['driver']->availableSettings();
|
||||
|
||||
if (key($settings) === 0) {
|
||||
// BACKWARDS COMPATIBILITY: Support a simple list of fields (without
|
||||
// type or additional metadata).
|
||||
// Turns ["f1", "f2"] into {"f1": "", "f2": ""}
|
||||
// @deprecated since 0.1.0-beta.12
|
||||
$settings = array_reduce($settings, function ($memo, $key) {
|
||||
return [$key => ''] + $memo;
|
||||
}, []);
|
||||
}
|
||||
|
||||
return [
|
||||
'fields' => $driver->availableSettings(),
|
||||
'fields' => $settings,
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -23,7 +23,7 @@ use Flarum\Notification\Notification;
|
||||
use Flarum\Post\MergeableInterface;
|
||||
use Flarum\Post\Post;
|
||||
use Flarum\User\User;
|
||||
use Flarum\Util\Str;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace Flarum\Event;
|
||||
|
||||
use Zend\Stratigility\MiddlewarePipe;
|
||||
use Laminas\Stratigility\MiddlewarePipe;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
|
120
src/Extend/ErrorHandling.php
Normal file
120
src/Extend/ErrorHandling.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?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\Extend;
|
||||
|
||||
use Flarum\Extension\Extension;
|
||||
use Flarum\Foundation\ErrorHandling\Reporter;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
|
||||
class ErrorHandling implements ExtenderInterface
|
||||
{
|
||||
private $statuses = [];
|
||||
private $types = [];
|
||||
private $handlers = [];
|
||||
private $reporters = [];
|
||||
|
||||
/**
|
||||
* Define the corresponding HTTP status code for a well-known error type.
|
||||
*
|
||||
* This can be used to configure the status code (second parameter) to be
|
||||
* used for the error response when encountering an exception with a certain
|
||||
* type (first parameter). This type can be provided by the exception class
|
||||
* itself (if it implements {@see \Flarum\Foundation\KnownError}), or
|
||||
* explicitly defined by using the {@see type} method (useful for exception
|
||||
* classes not under your control).
|
||||
*/
|
||||
public function status(string $errorType, int $httpStatus)
|
||||
{
|
||||
$this->statuses[$errorType] = $httpStatus;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the internal error type for a specific exception class.
|
||||
*
|
||||
* If the exception class is under your control, you should prefer having
|
||||
* the exception implement our {@see \Flarum\Fondation\KnownError} interface
|
||||
* and define the type there. This method should only be used for third-
|
||||
* party exceptions, e.g. when integrating another package that already
|
||||
* defines its own exception classes.
|
||||
*/
|
||||
public function type(string $exceptionClass, string $errorType)
|
||||
{
|
||||
$this->types[$exceptionClass] = $errorType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a handler with custom error handling logic.
|
||||
*
|
||||
* When Flarum's default error handling is not enough for you, and the other
|
||||
* methods of this extender don't help, this is the place where you can go
|
||||
* wild! Using this method, you can define a handler class (second
|
||||
* parameter) that will be responsible for exceptions of a certain type
|
||||
* (first parameter).
|
||||
*
|
||||
* The handler class must implement a handle() method (surprise!), which
|
||||
* returns a {@see \Flarum\Foundation\ErrorHandling\HandledError} instance.
|
||||
* Besides the usual type and HTTP status code, such an object can also
|
||||
* contain "details" - arbitrary data with more context for to the error.
|
||||
*/
|
||||
public function handler(string $exceptionClass, string $handlerClass)
|
||||
{
|
||||
$this->handlers[$exceptionClass] = $handlerClass;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an error reporter.
|
||||
*
|
||||
* Reporters will be called whenever Flarum encounters an exception that it
|
||||
* does not know how to handle (i.e. none of the well-known exceptions that
|
||||
* have an associated error type). They can then e.g. write the exception to
|
||||
* a log, or send it to some external service, so that developers and/or
|
||||
* administrators are notified about the error.
|
||||
*
|
||||
* When passing in a reporter class, make sure that it implements the
|
||||
* {@see \Flarum\Foundation\ErrorHandling\Reporter} interface.
|
||||
*/
|
||||
public function reporter(string $reporterClass)
|
||||
{
|
||||
$this->reporters[] = $reporterClass;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function extend(Container $container, Extension $extension = null)
|
||||
{
|
||||
if (count($this->statuses)) {
|
||||
$container->extend('flarum.error.statuses', function ($statuses) {
|
||||
return array_merge($statuses, $this->statuses);
|
||||
});
|
||||
}
|
||||
|
||||
if (count($this->types)) {
|
||||
$container->extend('flarum.error.classes', function ($types) {
|
||||
return array_merge($types, $this->types);
|
||||
});
|
||||
}
|
||||
|
||||
if (count($this->handlers)) {
|
||||
$container->extend('flarum.error.handlers', function ($handlers) {
|
||||
return array_merge($handlers, $this->handlers);
|
||||
});
|
||||
}
|
||||
|
||||
foreach ($this->reporters as $reporterClass) {
|
||||
$container->tag($reporterClass, Reporter::class);
|
||||
}
|
||||
}
|
||||
}
|
101
src/Extend/Middleware.php
Normal file
101
src/Extend/Middleware.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?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\Extend;
|
||||
|
||||
use Flarum\Extension\Extension;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
|
||||
class Middleware implements ExtenderInterface
|
||||
{
|
||||
protected $addMiddlewares = [];
|
||||
protected $removeMiddlewares = [];
|
||||
protected $replaceMiddlewares = [];
|
||||
protected $insertBeforeMiddlewares = [];
|
||||
protected $insertAfterMiddlewares = [];
|
||||
protected $frontend;
|
||||
|
||||
public function __construct(string $frontend)
|
||||
{
|
||||
$this->frontend = $frontend;
|
||||
}
|
||||
|
||||
public function add($middleware)
|
||||
{
|
||||
$this->addMiddlewares[] = $middleware;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function replace($originalMiddleware, $newMiddleware)
|
||||
{
|
||||
$this->replaceMiddlewares[$originalMiddleware] = $newMiddleware;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function remove($middleware)
|
||||
{
|
||||
$this->removeMiddlewares[] = $middleware;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function insertBefore($originalMiddleware, $newMiddleware)
|
||||
{
|
||||
$this->replaceMiddlewares[$originalMiddleware] = $newMiddleware;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function insertAfter($originalMiddleware, $newMiddleware)
|
||||
{
|
||||
$this->replaceMiddlewares[$originalMiddleware] = $newMiddleware;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function extend(Container $container, Extension $extension = null)
|
||||
{
|
||||
$container->extend("flarum.{$this->frontend}.middleware", function ($existingMiddleware) {
|
||||
foreach ($this->addMiddlewares as $addMiddleware) {
|
||||
$existingMiddleware[] = $addMiddleware;
|
||||
}
|
||||
|
||||
foreach ($this->replaceMiddlewares as $originalMiddleware => $newMiddleware) {
|
||||
$existingMiddleware = array_replace($existingMiddleware,
|
||||
array_fill_keys(
|
||||
array_keys($existingMiddleware, $originalMiddleware),
|
||||
$newMiddleware
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($this->insertBeforeMiddlewares as $originalMiddleware => $newMiddleware) {
|
||||
array_splice($existingMiddleware,
|
||||
array_search($originalMiddleware, $existingMiddleware),
|
||||
0,
|
||||
$newMiddleware
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($this->insertAfterMiddlewares as $originalMiddleware => $newMiddleware) {
|
||||
array_splice($existingMiddleware,
|
||||
array_search($originalMiddleware, $existingMiddleware) + 1,
|
||||
0,
|
||||
$newMiddleware
|
||||
);
|
||||
}
|
||||
|
||||
$existingMiddleware = array_diff($existingMiddleware, $this->removeMiddlewares);
|
||||
|
||||
return $existingMiddleware;
|
||||
});
|
||||
}
|
||||
}
|
@@ -14,8 +14,8 @@ use Flarum\User\LoginProvider;
|
||||
use Flarum\User\RegistrationToken;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Zend\Diactoros\Response\HtmlResponse;
|
||||
|
||||
class ResponseFactory
|
||||
{
|
||||
|
@@ -50,7 +50,7 @@ class Discussion
|
||||
public function __invoke(Document $document, Request $request)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
$page = max(1, Arr::get($queryParams, 'page'));
|
||||
$page = max(1, intval(Arr::get($queryParams, 'page')));
|
||||
|
||||
$params = [
|
||||
'id' => (int) Arr::get($queryParams, 'id'),
|
||||
|
@@ -61,7 +61,7 @@ class Index
|
||||
|
||||
$sort = Arr::pull($queryParams, 'sort');
|
||||
$q = Arr::pull($queryParams, 'q');
|
||||
$page = Arr::pull($queryParams, 'page', 1);
|
||||
$page = max(1, intval(Arr::pull($queryParams, 'page')));
|
||||
|
||||
$sortMap = $this->getSortMap();
|
||||
|
||||
|
82
src/Forum/Content/User.php
Normal file
82
src/Forum/Content/User.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?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\Forum\Content;
|
||||
|
||||
use Flarum\Api\Client;
|
||||
use Flarum\Api\Controller\ShowUserController;
|
||||
use Flarum\Frontend\Document;
|
||||
use Flarum\Http\UrlGenerator;
|
||||
use Flarum\User\User as FlarumUser;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
protected $api;
|
||||
|
||||
/**
|
||||
* @var UrlGenerator
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* @param Client $api
|
||||
* @param UrlGenerator $url
|
||||
*/
|
||||
public function __construct(Client $api, UrlGenerator $url)
|
||||
{
|
||||
$this->api = $api;
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function __invoke(Document $document, Request $request)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
$actor = $request->getAttribute('actor');
|
||||
$userId = Arr::get($queryParams, 'username');
|
||||
|
||||
$params = [
|
||||
'id' => $userId,
|
||||
];
|
||||
|
||||
$apiDocument = $this->getApiDocument($actor, $params);
|
||||
$user = $apiDocument->data->attributes;
|
||||
|
||||
$document->title = $user->displayName;
|
||||
$document->canonicalUrl = $this->url->to('forum')->route('user', ['username' => $user->username]);
|
||||
$document->payload['apiDocument'] = $apiDocument;
|
||||
|
||||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of an API request to show a user.
|
||||
*
|
||||
* @param FlarumUser $actor
|
||||
* @param array $params
|
||||
* @return object
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
protected function getApiDocument(FlarumUser $actor, array $params)
|
||||
{
|
||||
$response = $this->api->send(ShowUserController::class, $actor, $params);
|
||||
$statusCode = $response->getStatusCode();
|
||||
|
||||
if ($statusCode === 404) {
|
||||
throw new ModelNotFoundException;
|
||||
}
|
||||
|
||||
return json_decode($response->getBody());
|
||||
}
|
||||
}
|
@@ -14,10 +14,10 @@ use Flarum\Http\SessionAuthenticator;
|
||||
use Flarum\User\Command\ConfirmEmail;
|
||||
use Illuminate\Contracts\Bus\Dispatcher;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response\RedirectResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\RedirectResponse;
|
||||
|
||||
class ConfirmEmailController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -19,11 +19,11 @@ use Flarum\User\Event\LoggedOut;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Laminas\Diactoros\Response\RedirectResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\HtmlResponse;
|
||||
use Zend\Diactoros\Response\RedirectResponse;
|
||||
|
||||
class LogOutController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -19,10 +19,10 @@ use Illuminate\Contracts\Validation\Factory;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Laminas\Diactoros\Response\RedirectResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\RedirectResponse;
|
||||
|
||||
class SavePasswordController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -34,8 +34,8 @@ use Flarum\Locale\LocaleManager;
|
||||
use Flarum\Settings\Event\Saved;
|
||||
use Flarum\Settings\Event\Saving;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Laminas\Stratigility\MiddlewarePipe;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Zend\Stratigility\MiddlewarePipe;
|
||||
|
||||
class ForumServiceProvider extends AbstractServiceProvider
|
||||
{
|
||||
@@ -59,7 +59,20 @@ class ForumServiceProvider extends AbstractServiceProvider
|
||||
$this->setDefaultRoute($routes);
|
||||
});
|
||||
|
||||
$this->app->singleton('flarum.forum.middleware', function (Application $app) {
|
||||
$this->app->singleton('flarum.forum.middleware', function () {
|
||||
return [
|
||||
HttpMiddleware\ParseJsonBody::class,
|
||||
HttpMiddleware\CollectGarbage::class,
|
||||
HttpMiddleware\StartSession::class,
|
||||
HttpMiddleware\RememberFromCookie::class,
|
||||
HttpMiddleware\AuthenticateWithSession::class,
|
||||
HttpMiddleware\CheckCsrfToken::class,
|
||||
HttpMiddleware\SetLocale::class,
|
||||
HttpMiddleware\ShareErrorsFromSession::class
|
||||
];
|
||||
});
|
||||
|
||||
$this->app->singleton('flarum.forum.handler', function (Application $app) {
|
||||
$pipe = new MiddlewarePipe;
|
||||
|
||||
// All requests should first be piped through our global error handler
|
||||
@@ -69,22 +82,15 @@ class ForumServiceProvider extends AbstractServiceProvider
|
||||
$app->tagged(Reporter::class)
|
||||
));
|
||||
|
||||
$pipe->pipe($app->make(HttpMiddleware\ParseJsonBody::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\CollectGarbage::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\StartSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\RememberFromCookie::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\CheckCsrfToken::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\SetLocale::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\ShareErrorsFromSession::class));
|
||||
foreach ($this->app->make('flarum.forum.middleware') as $middleware) {
|
||||
$pipe->pipe($this->app->make($middleware));
|
||||
}
|
||||
|
||||
event(new ConfigureMiddleware($pipe, 'forum'));
|
||||
|
||||
return $pipe;
|
||||
});
|
||||
|
||||
$this->app->afterResolving('flarum.forum.middleware', function (MiddlewarePipe $pipe) {
|
||||
$pipe->pipe(new HttpMiddleware\DispatchRoute($this->app->make('flarum.forum.routes')));
|
||||
|
||||
return $pipe;
|
||||
});
|
||||
|
||||
$this->app->bind('flarum.assets.forum', function () {
|
||||
|
@@ -28,7 +28,7 @@ return function (RouteCollection $map, RouteHandlerFactory $route) {
|
||||
$map->get(
|
||||
'/u/{username}[/{filter:[^/]*}]',
|
||||
'user',
|
||||
$route->toForum()
|
||||
$route->toForum(Content\User::class)
|
||||
);
|
||||
|
||||
$map->get(
|
||||
|
@@ -11,10 +11,10 @@ namespace Flarum\Foundation\ErrorHandling;
|
||||
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Illuminate\Contracts\View\Factory as ViewFactory;
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Zend\Diactoros\Response\HtmlResponse;
|
||||
|
||||
/**
|
||||
* A formatter for turning caught exceptions into "pretty" HTML error pages.
|
||||
|
@@ -17,11 +17,11 @@ use Flarum\Foundation\Console\InfoCommand;
|
||||
use Flarum\Http\Middleware\DispatchRoute;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Laminas\Stratigility\Middleware\OriginalMessages;
|
||||
use Laminas\Stratigility\MiddlewarePipe;
|
||||
use Middlewares\BasePath;
|
||||
use Middlewares\BasePathRouter;
|
||||
use Middlewares\RequestHandler;
|
||||
use Zend\Stratigility\Middleware\OriginalMessages;
|
||||
use Zend\Stratigility\MiddlewarePipe;
|
||||
|
||||
class InstalledApp implements AppInterface
|
||||
{
|
||||
@@ -63,9 +63,9 @@ class InstalledApp implements AppInterface
|
||||
$pipe->pipe(new OriginalMessages);
|
||||
$pipe->pipe(
|
||||
new BasePathRouter([
|
||||
$this->subPath('api') => 'flarum.api.middleware',
|
||||
$this->subPath('admin') => 'flarum.admin.middleware',
|
||||
'/' => 'flarum.forum.middleware',
|
||||
$this->subPath('api') => 'flarum.api.handler',
|
||||
$this->subPath('admin') => 'flarum.admin.handler',
|
||||
'/' => 'flarum.forum.handler',
|
||||
])
|
||||
);
|
||||
$pipe->pipe(new RequestHandler($this->container));
|
||||
@@ -92,6 +92,7 @@ class InstalledApp implements AppInterface
|
||||
private function getUpdaterHandler()
|
||||
{
|
||||
$pipe = new MiddlewarePipe;
|
||||
$pipe->pipe(new BasePath($this->basePath()));
|
||||
$pipe->pipe(
|
||||
new DispatchRoute($this->container->make('flarum.update.routes'))
|
||||
);
|
||||
|
@@ -10,12 +10,12 @@
|
||||
namespace Flarum\Foundation;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Tobscure\JsonApi\Document;
|
||||
use Zend\Diactoros\Response\HtmlResponse;
|
||||
use Zend\Diactoros\Response\JsonResponse;
|
||||
|
||||
class MaintenanceModeHandler implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -53,7 +53,12 @@ class AddTranslations
|
||||
|
||||
private function getTranslations(string $locale)
|
||||
{
|
||||
$translations = $this->locales->getTranslator()->getCatalogue($locale)->all('messages');
|
||||
$catalogue = $this->locales->getTranslator()->getCatalogue($locale);
|
||||
$translations = $catalogue->all('messages');
|
||||
|
||||
while ($catalogue = $catalogue->getFallbackCatalogue()) {
|
||||
$translations = array_replace($catalogue->all('messages'), $translations);
|
||||
}
|
||||
|
||||
return Arr::only(
|
||||
$translations,
|
||||
|
@@ -9,10 +9,10 @@
|
||||
|
||||
namespace Flarum\Frontend;
|
||||
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\HtmlResponse;
|
||||
|
||||
class Controller implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -10,10 +10,10 @@
|
||||
namespace Flarum\Http\Controller;
|
||||
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response\HtmlResponse;
|
||||
|
||||
abstract class AbstractHtmlController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -10,13 +10,13 @@
|
||||
namespace Flarum\Http;
|
||||
|
||||
use Flarum\Foundation\SiteInterface;
|
||||
use Laminas\Diactoros\Response;
|
||||
use Laminas\Diactoros\ServerRequest;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
|
||||
use Laminas\HttpHandlerRunner\RequestHandlerRunner;
|
||||
use Laminas\Stratigility\Middleware\ErrorResponseGenerator;
|
||||
use Throwable;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\ServerRequest;
|
||||
use Zend\Diactoros\ServerRequestFactory;
|
||||
use Zend\HttpHandlerRunner\Emitter\SapiEmitter;
|
||||
use Zend\HttpHandlerRunner\RequestHandlerRunner;
|
||||
use Zend\Stratigility\Middleware\ErrorResponseGenerator;
|
||||
|
||||
class Server
|
||||
{
|
||||
@@ -29,10 +29,8 @@ class Server
|
||||
|
||||
public function listen()
|
||||
{
|
||||
$app = $this->safelyBootApp();
|
||||
|
||||
$runner = new RequestHandlerRunner(
|
||||
$app->getRequestHandler(),
|
||||
$this->safelyBootAndGetHandler(),
|
||||
new SapiEmitter,
|
||||
[ServerRequestFactory::class, 'fromGlobals'],
|
||||
function (Throwable $e) {
|
||||
@@ -45,14 +43,17 @@ class Server
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to boot Flarum, and prevent exceptions from exposing sensitive info.
|
||||
* Try to boot Flarum, and retrieve the app's HTTP request handler.
|
||||
*
|
||||
* @return \Flarum\Foundation\AppInterface
|
||||
* We catch all exceptions happening during this process and format them to
|
||||
* prevent exposure of sensitive information.
|
||||
*
|
||||
* @return \Psr\Http\Server\RequestHandlerInterface
|
||||
*/
|
||||
private function safelyBootApp()
|
||||
private function safelyBootAndGetHandler()
|
||||
{
|
||||
try {
|
||||
return $this->site->bootApp();
|
||||
return $this->site->bootApp()->getRequestHandler();
|
||||
} catch (Throwable $e) {
|
||||
exit($this->formatBootException($e));
|
||||
}
|
||||
|
@@ -18,10 +18,10 @@ use Flarum\Install\StepFailed;
|
||||
use Flarum\Install\ValidationFailed;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Laminas\Diactoros\Response;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response;
|
||||
|
||||
class InstallController implements RequestHandlerInterface
|
||||
{
|
||||
|
@@ -18,7 +18,7 @@ use Flarum\Http\Middleware\HandleErrors;
|
||||
use Flarum\Http\Middleware\StartSession;
|
||||
use Flarum\Install\Console\InstallCommand;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Zend\Stratigility\MiddlewarePipe;
|
||||
use Laminas\Stratigility\MiddlewarePipe;
|
||||
|
||||
class Installer implements AppInterface
|
||||
{
|
||||
|
@@ -24,6 +24,10 @@ interface DriverInterface
|
||||
{
|
||||
/**
|
||||
* Provide a list of settings for this driver.
|
||||
*
|
||||
* The list must be an array of field names (keys) mapping to their type
|
||||
* (the empty string "" for a text field; or an array of possible values for
|
||||
* a dropdown field).
|
||||
*/
|
||||
public function availableSettings(): array;
|
||||
|
||||
|
@@ -19,8 +19,12 @@ class MailgunDriver implements DriverInterface
|
||||
public function availableSettings(): array
|
||||
{
|
||||
return [
|
||||
'mail_mailgun_secret', // the secret key
|
||||
'mail_mailgun_domain', // the API base URL
|
||||
'mail_mailgun_secret' => '', // the secret key
|
||||
'mail_mailgun_domain' => '', // the API base URL
|
||||
'mail_mailgun_region' => [ // region's endpoint
|
||||
'api.mailgun.net' => 'US',
|
||||
'api.eu.mailgun.net' => 'EU',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -29,7 +33,8 @@ class MailgunDriver implements DriverInterface
|
||||
return new MailgunTransport(
|
||||
new Client(['connect_timeout' => 60]),
|
||||
$settings->get('mail_mailgun_secret'),
|
||||
$settings->get('mail_mailgun_domain')
|
||||
$settings->get('mail_mailgun_domain'),
|
||||
$settings->get('mail_mailgun_region')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ class MandrillDriver implements DriverInterface
|
||||
public function availableSettings(): array
|
||||
{
|
||||
return [
|
||||
'mail_mandrill_secret',
|
||||
'mail_mandrill_secret' => '',
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -19,9 +19,9 @@ class SesDriver implements DriverInterface
|
||||
public function availableSettings(): array
|
||||
{
|
||||
return [
|
||||
'mail_ses_key',
|
||||
'mail_ses_secret',
|
||||
'mail_ses_region',
|
||||
'mail_ses_key' => '',
|
||||
'mail_ses_secret' => '',
|
||||
'mail_ses_region' => '',
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -18,11 +18,11 @@ class SmtpDriver implements DriverInterface
|
||||
public function availableSettings(): array
|
||||
{
|
||||
return [
|
||||
'mail_host', // a hostname, IPv4 address or IPv6 wrapped in []
|
||||
'mail_port', // a number, defaults to 25
|
||||
'mail_encryption', // "tls" or "ssl"
|
||||
'mail_username', // required
|
||||
'mail_password', // required
|
||||
'mail_host' => '', // a hostname, IPv4 address or IPv6 wrapped in []
|
||||
'mail_port' => '', // a number, defaults to 25
|
||||
'mail_encryption' => '', // "tls" or "ssl"
|
||||
'mail_username' => '', // required
|
||||
'mail_password' => '', // required
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -13,13 +13,13 @@ use Exception;
|
||||
use Flarum\Database\Console\MigrateCommand;
|
||||
use Flarum\Foundation\Application;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laminas\Diactoros\Response;
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\StreamOutput;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\Response\HtmlResponse;
|
||||
|
||||
class UpdateController implements RequestHandlerInterface
|
||||
{
|
||||
|
83
src/User/Concerns/DeprecatedUserPreferences.php
Normal file
83
src/User/Concerns/DeprecatedUserPreferences.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?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\User\Concerns;
|
||||
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait DeprecatedUserPreferences
|
||||
{
|
||||
/**
|
||||
* Get the values of all registered preferences for this user, by
|
||||
* transforming their stored preferences and merging them with the defaults.
|
||||
*
|
||||
* @param string $value
|
||||
* @return array
|
||||
* @deprecated 0.1.0-beta.11: `users.preferences` is no longer used.
|
||||
*/
|
||||
public function getPreferencesAttribute($value)
|
||||
{
|
||||
$defaults = array_map(function ($value) {
|
||||
return $value['default'];
|
||||
}, static::$preferences);
|
||||
|
||||
$user = Arr::only($this->notificationPreferences->toArray(), array_keys(static::$preferences));
|
||||
|
||||
return array_merge($defaults, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an array of preferences for storage in the database.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @deprecated 0.1.0-beta.11: `users.preferences` is no longer used.
|
||||
*/
|
||||
public function setPreferencesAttribute($value)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a preference for this user.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
* @deprecated 0.1.0-beta.11: `users.preferences` is no longer used.
|
||||
*/
|
||||
public function getPreference($key, $default = null)
|
||||
{
|
||||
return Arr::get($this->preferences, $key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a preference for this user.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
* @deprecated 0.1.0-beta.11: `users.preferences` is no longer used.
|
||||
*/
|
||||
public function setPreference($key, $value)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key for a preference which flags whether or not the user will
|
||||
* receive a notification for $type via $method.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $method
|
||||
* @return string
|
||||
* @deprecated 0.1.0-beta.11: `users.preferences` is no longer used, use NotificationPreference::getPreferenceKey.
|
||||
*/
|
||||
public static function getNotificationPreferenceKey($type, $method)
|
||||
{
|
||||
}
|
||||
}
|
59
src/User/NotificationPreference.php
Normal file
59
src/User/NotificationPreference.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?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\User;
|
||||
|
||||
use Flarum\Database\AbstractModel;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @property int $user_id
|
||||
* @property string $type
|
||||
* @property string $channel
|
||||
* @property bool $enabled
|
||||
*/
|
||||
class NotificationPreference extends AbstractModel
|
||||
{
|
||||
protected static $channels = [];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public static function addChannel(string $channel)
|
||||
{
|
||||
static::$channels[] = $channel;
|
||||
}
|
||||
|
||||
public static function setNotificationPreference(User $user, string $type, string $channel, bool $enabled = true)
|
||||
{
|
||||
if (in_array($channel, static::$channels)) {
|
||||
$attributes = [
|
||||
'channel' => $channel,
|
||||
'type' => $type
|
||||
];
|
||||
|
||||
$user->notificationPreferences()->updateOrInsert($attributes, ['enabled' => $enabled]);
|
||||
} else {
|
||||
throw new InvalidArgumentException("Channel '$channel' is not registered.");
|
||||
}
|
||||
}
|
||||
|
||||
public function scopeShouldBeNotified(Builder $query, string $type, string $channel = null)
|
||||
{
|
||||
return $query
|
||||
->where('enabled', true)
|
||||
->where('type', $type)
|
||||
->when($channel, function ($query, $channel) {
|
||||
$query->where('channel', $channel);
|
||||
});
|
||||
}
|
||||
}
|
@@ -35,7 +35,6 @@ use Flarum\User\Event\Registered;
|
||||
use Flarum\User\Event\Renamed;
|
||||
use Illuminate\Contracts\Hashing\Hasher;
|
||||
use Illuminate\Contracts\Session\Session;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
@@ -55,6 +54,7 @@ use Illuminate\Support\Arr;
|
||||
*/
|
||||
class User extends AbstractModel
|
||||
{
|
||||
use Concerns\DeprecatedUserPreferences;
|
||||
use EventGeneratorTrait;
|
||||
use ScopeVisibilityTrait;
|
||||
|
||||
@@ -446,32 +446,9 @@ class User extends AbstractModel
|
||||
})->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the values of all registered preferences for this user, by
|
||||
* transforming their stored preferences and merging them with the defaults.
|
||||
*
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
public function getPreferencesAttribute($value)
|
||||
public function notificationPreferences()
|
||||
{
|
||||
$defaults = array_map(function ($value) {
|
||||
return $value['default'];
|
||||
}, static::$preferences);
|
||||
|
||||
$user = Arr::only((array) json_decode($value, true), array_keys(static::$preferences));
|
||||
|
||||
return array_merge($defaults, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an array of preferences for storage in the database.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setPreferencesAttribute($value)
|
||||
{
|
||||
$this->attributes['preferences'] = json_encode($value);
|
||||
return $this->hasMany(NotificationPreference::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,9 +458,11 @@ class User extends AbstractModel
|
||||
* @param string $type
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldAlert($type)
|
||||
public function shouldAlert(string $type): bool
|
||||
{
|
||||
return (bool) $this->getPreference(static::getNotificationPreferenceKey($type, 'alert'));
|
||||
return $this->notificationPreferences()
|
||||
->shouldBeNotified($type, 'email')
|
||||
->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,45 +472,11 @@ class User extends AbstractModel
|
||||
* @param string $type
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldEmail($type)
|
||||
public function shouldEmail(string $type): bool
|
||||
{
|
||||
return (bool) $this->getPreference(static::getNotificationPreferenceKey($type, 'email'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a preference for this user.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPreference($key, $default = null)
|
||||
{
|
||||
return Arr::get($this->preferences, $key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a preference for this user.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
*/
|
||||
public function setPreference($key, $value)
|
||||
{
|
||||
if (isset(static::$preferences[$key])) {
|
||||
$preferences = $this->preferences;
|
||||
|
||||
if (! is_null($transformer = static::$preferences[$key]['transformer'])) {
|
||||
$preferences[$key] = call_user_func($transformer, $value);
|
||||
} else {
|
||||
$preferences[$key] = $value;
|
||||
}
|
||||
|
||||
$this->preferences = $preferences;
|
||||
}
|
||||
|
||||
return $this;
|
||||
return $this->notificationPreferences()
|
||||
->shouldBeNotified($type, 'email')
|
||||
->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -735,19 +680,6 @@ class User extends AbstractModel
|
||||
static::$preferences[$key] = compact('transformer', 'default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key for a preference which flags whether or not the user will
|
||||
* receive a notification for $type via $method.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $method
|
||||
* @return string
|
||||
*/
|
||||
public static function getNotificationPreferenceKey($type, $method)
|
||||
{
|
||||
return 'notify_'.$type.'_'.$method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the user's comments count.
|
||||
*
|
||||
|
@@ -1,31 +0,0 @@
|
||||
<?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\Util;
|
||||
|
||||
class Str
|
||||
{
|
||||
/**
|
||||
* Create a slug out of the given string.
|
||||
*
|
||||
* Non-alphanumeric characters are converted to hyphens.
|
||||
*
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
public static function slug($str)
|
||||
{
|
||||
$str = strtolower($str);
|
||||
$str = preg_replace('/[^a-z0-9]/i', '-', $str);
|
||||
$str = preg_replace('/-+/', '-', $str);
|
||||
$str = preg_replace('/-$|^-/', '', $str);
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
@@ -12,10 +12,10 @@ namespace Flarum\Tests\integration;
|
||||
use Dflydev\FigCookies\SetCookie;
|
||||
use Flarum\Foundation\InstalledSite;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Laminas\Diactoros\CallbackStream;
|
||||
use Laminas\Diactoros\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Zend\Diactoros\CallbackStream;
|
||||
use Zend\Diactoros\ServerRequest;
|
||||
|
||||
abstract class TestCase extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
@@ -1,166 +0,0 @@
|
||||
<?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\Tests\integration\api\Auth;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Flarum\Api\ApiKey;
|
||||
use Flarum\Api\Client;
|
||||
use Flarum\Api\Controller\CreateGroupController;
|
||||
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
|
||||
use Flarum\Tests\integration\TestCase;
|
||||
use Flarum\User\Guest;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Support\Str;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\ServerRequestFactory;
|
||||
use Zend\Stratigility\MiddlewarePipe;
|
||||
|
||||
class AuthenticateWithApiKeyTest extends TestCase
|
||||
{
|
||||
use RetrievesAuthorizedUsers;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->prepareDatabase([
|
||||
'users' => [
|
||||
$this->adminUser(),
|
||||
$this->normalUser(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
protected function key(int $user_id = null): ApiKey
|
||||
{
|
||||
return ApiKey::unguarded(function () use ($user_id) {
|
||||
return ApiKey::query()->firstOrCreate([
|
||||
'key' => Str::random(),
|
||||
'user_id' => $user_id,
|
||||
'created_at' => Carbon::now()
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function cannot_authorize_without_key()
|
||||
{
|
||||
/** @var Client $api */
|
||||
$api = $this->app()->getContainer()->make(Client::class);
|
||||
|
||||
$response = $api->send(CreateGroupController::class, new Guest);
|
||||
|
||||
$this->assertEquals(401, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function master_token_can_authenticate_as_anyone()
|
||||
{
|
||||
$key = $this->key();
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals()
|
||||
->withAddedHeader('Authorization', "Token {$key->key}; userId=1");
|
||||
|
||||
$pipe = $this->injectAuthorizationPipeline();
|
||||
|
||||
$response = $pipe->handle($request);
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertEquals(1, $response->getHeader('X-Authenticated-As')[0]);
|
||||
|
||||
$key = $key->refresh();
|
||||
|
||||
$this->assertNotNull($key->last_activity_at);
|
||||
|
||||
$key->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function personal_api_token_cannot_authenticate_as_anyone()
|
||||
{
|
||||
$user = User::find(2);
|
||||
|
||||
$key = $this->key($user->id);
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals()
|
||||
->withAddedHeader('Authorization', "Token {$key->key}; userId=1");
|
||||
|
||||
$pipe = $this->injectAuthorizationPipeline();
|
||||
|
||||
$response = $pipe->handle($request);
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertEquals($user->id, $response->getHeader('X-Authenticated-As')[0]);
|
||||
|
||||
$key = $key->refresh();
|
||||
|
||||
$this->assertNotNull($key->last_activity_at);
|
||||
|
||||
$key->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function personal_api_token_authenticates_user()
|
||||
{
|
||||
$user = User::find(2);
|
||||
|
||||
$key = $this->key($user->id);
|
||||
|
||||
$request = ServerRequestFactory::fromGlobals()
|
||||
->withAddedHeader('Authorization', "Token {$key->key}");
|
||||
|
||||
$pipe = $this->injectAuthorizationPipeline();
|
||||
|
||||
$response = $pipe->handle($request);
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertEquals($user->id, $response->getHeader('X-Authenticated-As')[0]);
|
||||
|
||||
$key = $key->refresh();
|
||||
|
||||
$this->assertNotNull($key->last_activity_at);
|
||||
|
||||
$key->delete();
|
||||
}
|
||||
|
||||
protected function injectAuthorizationPipeline(): MiddlewarePipe
|
||||
{
|
||||
app()->resolving('flarum.api.middleware', function ($pipeline) {
|
||||
$pipeline->pipe(new class implements MiddlewareInterface {
|
||||
public function process(
|
||||
ServerRequestInterface $request,
|
||||
RequestHandlerInterface $handler
|
||||
): ResponseInterface {
|
||||
if ($actor = $request->getAttribute('actor')) {
|
||||
return new Response\EmptyResponse(200, [
|
||||
'X-Authenticated-As' => $actor->id
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$pipe = app('flarum.api.middleware');
|
||||
|
||||
return $pipe;
|
||||
}
|
||||
}
|
121
tests/integration/api/authentication/WithApiKeyTest.php
Normal file
121
tests/integration/api/authentication/WithApiKeyTest.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?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\Tests\integration\api\authentication;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Flarum\Api\ApiKey;
|
||||
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
|
||||
use Flarum\Tests\integration\TestCase;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class WithApiKeyTest extends TestCase
|
||||
{
|
||||
use RetrievesAuthorizedUsers;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->prepareDatabase([
|
||||
'users' => [
|
||||
$this->adminUser(),
|
||||
$this->normalUser(),
|
||||
],
|
||||
'api_keys' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
protected function key(int $user_id = null): ApiKey
|
||||
{
|
||||
return ApiKey::unguarded(function () use ($user_id) {
|
||||
return ApiKey::query()->firstOrCreate([
|
||||
'key' => Str::random(),
|
||||
'user_id' => $user_id,
|
||||
'created_at' => Carbon::now()
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function cannot_authorize_without_key()
|
||||
{
|
||||
$response = $this->send(
|
||||
$this->request('GET', '/api')
|
||||
);
|
||||
|
||||
$data = json_decode($response->getBody(), true);
|
||||
$this->assertFalse($data['data']['attributes']['canViewUserList']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function master_token_can_authenticate_as_anyone()
|
||||
{
|
||||
$key = $this->key();
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('GET', '/api')
|
||||
->withAddedHeader('Authorization', "Token {$key->key}; userId=1")
|
||||
);
|
||||
|
||||
$data = json_decode($response->getBody(), true);
|
||||
$this->assertTrue($data['data']['attributes']['canViewUserList']);
|
||||
$this->assertArrayHasKey('adminUrl', $data['data']['attributes']);
|
||||
|
||||
$key->refresh();
|
||||
|
||||
$this->assertNotNull($key->last_activity_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function personal_api_token_cannot_authenticate_as_anyone()
|
||||
{
|
||||
$key = $this->key(2);
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('GET', '/api')
|
||||
->withAddedHeader('Authorization', "Token {$key->key}; userId=1")
|
||||
);
|
||||
|
||||
$data = json_decode($response->getBody(), true);
|
||||
$this->assertTrue($data['data']['attributes']['canViewUserList']);
|
||||
$this->assertArrayNotHasKey('adminUrl', $data['data']['attributes']);
|
||||
|
||||
$key->refresh();
|
||||
|
||||
$this->assertNotNull($key->last_activity_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function personal_api_token_authenticates_user()
|
||||
{
|
||||
$key = $this->key(2);
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('GET', '/api')
|
||||
->withAddedHeader('Authorization', "Token {$key->key}")
|
||||
);
|
||||
|
||||
$data = json_decode($response->getBody(), true);
|
||||
$this->assertTrue($data['data']['attributes']['canViewUserList']);
|
||||
$this->assertArrayNotHasKey('adminUrl', $data['data']['attributes']);
|
||||
|
||||
$key->refresh();
|
||||
|
||||
$this->assertNotNull($key->last_activity_at);
|
||||
}
|
||||
}
|
@@ -11,7 +11,7 @@ namespace Flarum\Tests\unit\Install;
|
||||
|
||||
use Flarum\Install\BaseUrl;
|
||||
use Flarum\Tests\unit\TestCase;
|
||||
use Zend\Diactoros\Uri;
|
||||
use Laminas\Diactoros\Uri;
|
||||
|
||||
class BaseUrlTest extends TestCase
|
||||
{
|
||||
|
@@ -3,12 +3,12 @@
|
||||
<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>
|
||||
|
||||
<div class="Problems">
|
||||
<?php foreach ($problems as $problem): ?>
|
||||
<?php foreach ($problems as $problem) { ?>
|
||||
<div class="Problem">
|
||||
<h3 class="Problem-message"><?php echo $problem['message']; ?></h3>
|
||||
<?php if (! empty($problem['detail'])): ?>
|
||||
<?php if (! empty($problem['detail'])) { ?>
|
||||
<p class="Problem-detail"><?php echo $problem['detail']; ?></p>
|
||||
<?php endif; ?>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user