diff --git a/js/forum/Gulpfile.js b/js/forum/Gulpfile.js
index 8a1ab4698..2eca8d9f6 100644
--- a/js/forum/Gulpfile.js
+++ b/js/forum/Gulpfile.js
@@ -30,7 +30,6 @@ gulp({
'src/**/*.js',
'../lib/**/*.js'
],
- bootstrapFiles: [],
modulePrefix: 'flarum',
externalHelpers: true,
outputFile: 'dist/app.js'
diff --git a/js/forum/src/components/DiscussionHero.js b/js/forum/src/components/DiscussionHero.js
index 98d52894a..633501ac0 100644
--- a/js/forum/src/components/DiscussionHero.js
+++ b/js/forum/src/components/DiscussionHero.js
@@ -31,7 +31,7 @@ export default class DiscussionHero extends Component {
const badges = discussion.badges().toArray();
if (badges.length) {
- items.add('badges',
- {type.label}
+ {icon(type.icon)} {type.label}
|
{this.methods.map(method => (
@@ -181,7 +181,8 @@ export default class NotificationGrid extends Component {
items.add('discussionRenamed', {
name: 'discussionRenamed',
- label: [icon('pencil'), ' ', app.trans('core.notify_discussion_renamed')]
+ icon: 'pencil',
+ label: app.trans('core.notify_discussion_renamed')
});
return items;
diff --git a/js/forum/src/components/PostStream.js b/js/forum/src/components/PostStream.js
index aa81bbb79..26d05377f 100644
--- a/js/forum/src/components/PostStream.js
+++ b/js/forum/src/components/PostStream.js
@@ -167,7 +167,11 @@ class PostStream extends mixin(Component, evented) {
posts() {
return this.discussion.postIds()
.slice(this.visibleStart, this.visibleEnd)
- .map(id => app.store.getById('posts', id));
+ .map(id => {
+ const post = app.store.getById('posts', id);
+
+ return post && post.discussion() ? post : null;
+ });
}
view() {
@@ -365,10 +369,10 @@ class PostStream extends mixin(Component, evented) {
this.discussion.postIds().slice(start, end).forEach(id => {
const post = app.store.getById('posts', id);
- if (!post) {
- loadIds.push(id);
- } else {
+ if (post && post.discussion()) {
loaded.push(post);
+ } else {
+ loadIds.push(id);
}
});
diff --git a/js/lib/Translator.js b/js/lib/Translator.js
index 404595819..777cc8a67 100644
--- a/js/lib/Translator.js
+++ b/js/lib/Translator.js
@@ -61,7 +61,9 @@ export default class Translator {
// translation key. This will allow a gender property to determine which
// translation key is used.
if (input.user instanceof User) {
- input.username = username(extract(input, 'user'));
+ const user = extract(input, 'user');
+
+ if (!input.username) input.username = username(user);
}
// If we've found the appropriate translation string, then we'll sub in the
diff --git a/js/lib/extend.js b/js/lib/extend.js
index 2aadcdea6..fe55c7012 100644
--- a/js/lib/extend.js
+++ b/js/lib/extend.js
@@ -59,17 +59,3 @@ export function override(object, method, newMethod) {
return newMethod.apply(this, [original.bind(this)].concat(args));
};
}
-
-/**
- * Register a notification type.
- *
- * @param {String} name The name of the notification type (equivalent to the
- * serialized `contentType`)
- * @param {Object} Component The constructor of the component that this
- * notification type should be rendered with
- * @param {String|Array} label vDOM to render a label in the notification
- * preferences grid for this notification type
- */
-export function notificationType(name, Component, label) {
- // TODO
-}
diff --git a/js/lib/utils/string.js b/js/lib/utils/string.js
index 69d89bd69..6d5a14aa8 100644
--- a/js/lib/utils/string.js
+++ b/js/lib/utils/string.js
@@ -36,3 +36,13 @@ export function slug(string) {
export function getPlainContent(string) {
return $('').html(string.replace(/(<\/p>| )/g, '$1 ')).text();
}
+
+/**
+ * Make a string's first character uppercase.
+ *
+ * @param {String} string
+ * @return {String}
+ */
+export function ucfirst(string) {
+ return string.substr(0, 1).toUpperCase() + string.substr(1);
+}
diff --git a/less/forum/DiscussionHero.less b/less/forum/DiscussionHero.less
index 4eff60d1a..d8a60f918 100644
--- a/less/forum/DiscussionHero.less
+++ b/less/forum/DiscussionHero.less
@@ -1,6 +1,6 @@
.DiscussionHero {
.badges {
- margin-right: 5px;
+ margin-right: 10px;
margin-bottom: -2px;
}
}
diff --git a/less/forum/DiscussionListItem.less b/less/forum/DiscussionListItem.less
index cb2306e9f..beb749e1e 100644
--- a/less/forum/DiscussionListItem.less
+++ b/less/forum/DiscussionListItem.less
@@ -25,7 +25,7 @@
white-space: nowrap;
pointer-events: none;
- .badge {
+ .Badge {
margin-left: -15px;
position: relative;
pointer-events: auto;
diff --git a/less/lib/App.less b/less/lib/App.less
index 48bce816b..8b4ebe4b9 100755
--- a/less/lib/App.less
+++ b/less/lib/App.less
@@ -1,6 +1,8 @@
.App {
position: relative !important;
padding-top: @header-height;
+ overflow-x: hidden;
+ min-height: 100vh;
@media @phone {
padding-top: @header-height-phone;
diff --git a/less/lib/Checkbox.less b/less/lib/Checkbox.less
index 8cc9da46c..42b8576d7 100755
--- a/less/lib/Checkbox.less
+++ b/less/lib/Checkbox.less
@@ -32,7 +32,7 @@
.transition(background-color 0.2s);
.on& {
- background: @primary-color;
+ background: #58A400;
}
&:before {
diff --git a/less/lib/scaffolding.less b/less/lib/scaffolding.less
index c1a7dcbbf..a48c0db1b 100755
--- a/less/lib/scaffolding.less
+++ b/less/lib/scaffolding.less
@@ -72,11 +72,6 @@ p {
margin: 0 auto;
}
-.global-page {
- overflow-x: hidden;
- min-height: 100vh;
-}
-
mark {
background: #FFE300;
padding: 1px;
diff --git a/locale/en/translations.yml b/locale/en/translations.yml
index bfd409ba7..43939a938 100644
--- a/locale/en/translations.yml
+++ b/locale/en/translations.yml
@@ -25,7 +25,7 @@ core:
delete_forever: Delete Forever
deleted: "[deleted]"
disclose_online: Allow others to see when I am online
- discussion_renamed: "changed the title from {old} to {new}"
+ discussion_renamed_post: "{username} changed the title from {old} to {new}."
discussion_renamed_notification: "{username} changed the title"
discussion_replied: "{username} replied {ago}"
discussion_started: "{username} started {ago}"
@@ -93,10 +93,11 @@ core:
send_password_reset_email: Send Password Reset Email
settings: Settings
sign_up: Sign Up
+ sort_latest: Latest
sort_newest: Newest
sort_oldest: Oldest
- sort_recent: Recent
- sort_replies: Replies
+ sort_relevance: Relevance
+ sort_top: Top
start_a_discussion: Start a Discussion
started_a_discussion: Started a discussion
unread_posts: "{count} unread"
diff --git a/src/Api/Actions/Activity/IndexAction.php b/src/Api/Actions/Activity/IndexAction.php
index b78552da0..bae677d43 100644
--- a/src/Api/Actions/Activity/IndexAction.php
+++ b/src/Api/Actions/Activity/IndexAction.php
@@ -21,12 +21,12 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\ActivitySerializer';
+ public $serializer = 'Flarum\Api\Serializers\ActivitySerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'subject' => true,
'subject.user' => true,
'subject.discussion' => true
@@ -35,27 +35,27 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $link = ['user'];
+ public $link = ['user'];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param UserRepository $users
diff --git a/src/Api/Actions/Discussions/CreateAction.php b/src/Api/Actions/Discussions/CreateAction.php
index 0e19e2b74..10178b51e 100644
--- a/src/Api/Actions/Discussions/CreateAction.php
+++ b/src/Api/Actions/Discussions/CreateAction.php
@@ -18,12 +18,12 @@ class CreateAction extends BaseCreateAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
+ public $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'posts' => true,
'startUser' => true,
'lastUser' => true,
@@ -34,27 +34,27 @@ class CreateAction extends BaseCreateAction
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* Instantiate the action.
diff --git a/src/Api/Actions/Discussions/IndexAction.php b/src/Api/Actions/Discussions/IndexAction.php
index 9dd676957..870c7051f 100644
--- a/src/Api/Actions/Discussions/IndexAction.php
+++ b/src/Api/Actions/Discussions/IndexAction.php
@@ -22,12 +22,12 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
+ public $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'startUser' => true,
'lastUser' => true,
'startPost' => false,
@@ -40,27 +40,27 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = ['lastTime', 'commentsCount', 'startTime'];
+ public $sortFields = ['lastTime', 'commentsCount', 'startTime'];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param DiscussionSearcher $searcher
@@ -93,7 +93,7 @@ class IndexAction extends SerializeCollectionAction
$results = $this->searcher->search($criteria, $request->limit, $request->offset, $load);
// TODO: add query params (filter, sort, include) to the pagination URLs
- static::addPaginationLinks(
+ $this->addPaginationLinks(
$document,
$request,
$request->http ? $this->url->toRoute('flarum.api.discussions.index') : '',
diff --git a/src/Api/Actions/Discussions/ShowAction.php b/src/Api/Actions/Discussions/ShowAction.php
index 04a7f4e6f..ddbda9305 100644
--- a/src/Api/Actions/Discussions/ShowAction.php
+++ b/src/Api/Actions/Discussions/ShowAction.php
@@ -19,12 +19,12 @@ class ShowAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
+ public $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'startUser' => false,
'lastUser' => false,
'startPost' => false,
@@ -39,27 +39,27 @@ class ShowAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $link = ['posts', 'posts.discussion'];
+ public $link = ['posts', 'posts.discussion'];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = ['time'];
+ public $sortFields = ['time'];
/**
* @inheritdoc
*/
- public static $sort = ['time' => 'asc'];
+ public $sort = ['time' => 'asc'];
/**
* Instantiate the action.
diff --git a/src/Api/Actions/Discussions/UpdateAction.php b/src/Api/Actions/Discussions/UpdateAction.php
index 16048c55b..cbfb60420 100644
--- a/src/Api/Actions/Discussions/UpdateAction.php
+++ b/src/Api/Actions/Discussions/UpdateAction.php
@@ -17,37 +17,37 @@ class UpdateAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
+ public $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
/**
* @inheritdoc
*/
- public static $include = [];
+ public $include = [];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param Dispatcher $bus
diff --git a/src/Api/Actions/Forum/ShowAction.php b/src/Api/Actions/Forum/ShowAction.php
index cb64ee4ec..2125cae5d 100644
--- a/src/Api/Actions/Forum/ShowAction.php
+++ b/src/Api/Actions/Forum/ShowAction.php
@@ -9,37 +9,37 @@ class ShowAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\ForumSerializer';
+ public $serializer = 'Flarum\Api\Serializers\ForumSerializer';
/**
* @inheritdoc
*/
- public static $include = [];
+ public $include = [];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* Get the forum, ready to be serialized and assigned to the JsonApi
diff --git a/src/Api/Actions/Groups/IndexAction.php b/src/Api/Actions/Groups/IndexAction.php
index 3326be049..8b57c07cc 100644
--- a/src/Api/Actions/Groups/IndexAction.php
+++ b/src/Api/Actions/Groups/IndexAction.php
@@ -10,37 +10,37 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\GroupSerializer';
+ public $serializer = 'Flarum\Api\Serializers\GroupSerializer';
/**
* @inheritdoc
*/
- public static $include = [];
+ public $include = [];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* Get the groups, ready to be serialized and assigned to the document
diff --git a/src/Api/Actions/Notifications/IndexAction.php b/src/Api/Actions/Notifications/IndexAction.php
index 6b9000204..c7a1371b1 100644
--- a/src/Api/Actions/Notifications/IndexAction.php
+++ b/src/Api/Actions/Notifications/IndexAction.php
@@ -16,12 +16,12 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\NotificationSerializer';
+ public $serializer = 'Flarum\Api\Serializers\NotificationSerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'sender' => true,
'subject' => true,
'subject.discussion' => true
@@ -30,27 +30,27 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 10;
+ public $limit = 10;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* Instantiate the action.
diff --git a/src/Api/Actions/Notifications/UpdateAction.php b/src/Api/Actions/Notifications/UpdateAction.php
index 9ea9d7cba..54316a02c 100644
--- a/src/Api/Actions/Notifications/UpdateAction.php
+++ b/src/Api/Actions/Notifications/UpdateAction.php
@@ -16,37 +16,37 @@ class UpdateAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\NotificationSerializer';
+ public $serializer = 'Flarum\Api\Serializers\NotificationSerializer';
/**
* @inheritdoc
*/
- public static $include = [];
+ public $include = [];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param Dispatcher $bus
diff --git a/src/Api/Actions/Posts/CreateAction.php b/src/Api/Actions/Posts/CreateAction.php
index 8a3eeac1f..23fa07a84 100644
--- a/src/Api/Actions/Posts/CreateAction.php
+++ b/src/Api/Actions/Posts/CreateAction.php
@@ -16,12 +16,12 @@ class CreateAction extends BaseCreateAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\PostSerializer';
+ public $serializer = 'Flarum\Api\Serializers\PostSerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'user' => true,
'discussion' => true
];
@@ -29,27 +29,27 @@ class CreateAction extends BaseCreateAction
/**
* @inheritdoc
*/
- public static $link = ['discussion.posts'];
+ public $link = ['discussion.posts'];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* Instantiate the action.
diff --git a/src/Api/Actions/Posts/IndexAction.php b/src/Api/Actions/Posts/IndexAction.php
index c6627b9f1..71881898e 100644
--- a/src/Api/Actions/Posts/IndexAction.php
+++ b/src/Api/Actions/Posts/IndexAction.php
@@ -12,12 +12,12 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\PostSerializer';
+ public $serializer = 'Flarum\Api\Serializers\PostSerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'user' => true,
'user.groups' => true,
'editUser' => true,
@@ -28,27 +28,27 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param PostRepository $posts
diff --git a/src/Api/Actions/Posts/ShowAction.php b/src/Api/Actions/Posts/ShowAction.php
index 8c67757b1..e2fd92eff 100644
--- a/src/Api/Actions/Posts/ShowAction.php
+++ b/src/Api/Actions/Posts/ShowAction.php
@@ -16,12 +16,12 @@ class ShowAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\PostSerializer';
+ public $serializer = 'Flarum\Api\Serializers\PostSerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'user' => true,
'user.groups' => true,
'editUser' => true,
@@ -32,27 +32,27 @@ class ShowAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param PostRepository $posts
diff --git a/src/Api/Actions/Posts/UpdateAction.php b/src/Api/Actions/Posts/UpdateAction.php
index 462c11e1d..204df58cf 100644
--- a/src/Api/Actions/Posts/UpdateAction.php
+++ b/src/Api/Actions/Posts/UpdateAction.php
@@ -16,37 +16,37 @@ class UpdateAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\PostSerializer';
+ public $serializer = 'Flarum\Api\Serializers\PostSerializer';
/**
* @inheritdoc
*/
- public static $include = [];
+ public $include = [];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param Dispatcher $bus
diff --git a/src/Api/Actions/SerializeAction.php b/src/Api/Actions/SerializeAction.php
index 8b04050a7..6cef0e892 100644
--- a/src/Api/Actions/SerializeAction.php
+++ b/src/Api/Actions/SerializeAction.php
@@ -1,6 +1,7 @@
buildJsonApiRequest($request);
$document = new Document();
$data = $this->data($request, $document);
event(new WillSerializeData($this, $data, $request));
- $serializer = new static::$serializer($request->actor, $request->include, $request->link);
+ $serializer = new $this->serializer($request->actor, $request->include, $request->link);
$document->setData($this->serialize($serializer, $data));
@@ -107,17 +108,19 @@ abstract class SerializeAction extends JsonApiAction
* @param Request $request
* @return JsonApiRequest
*/
- protected static function buildJsonApiRequest(Request $request)
+ protected function buildJsonApiRequest(Request $request)
{
$request = new JsonApiRequest($request->input, $request->actor, $request->http);
$criteria = new Criteria($request->input);
- $request->include = static::sanitizeInclude($criteria->getInclude());
- $request->sort = static::sanitizeSort($criteria->getSort());
+ event(new BuildApiAction($this));
+
+ $request->include = $this->sanitizeInclude($criteria->getInclude());
+ $request->sort = $this->sanitizeSort($criteria->getSort());
$request->offset = $criteria->getOffset();
- $request->limit = static::sanitizeLimit($criteria->getLimit());
- $request->link = static::$link;
+ $request->limit = $this->sanitizeLimit($criteria->getLimit());
+ $request->link = $this->link;
return $request;
}
@@ -129,9 +132,9 @@ abstract class SerializeAction extends JsonApiAction
* @param array $include
* @return array
*/
- protected static function sanitizeInclude(array $include)
+ protected function sanitizeInclude(array $include)
{
- return array_intersect($include, array_keys(static::$include)) ?: array_keys(array_filter(static::$include));
+ return array_intersect($include, array_keys($this->include)) ?: array_keys(array_filter($this->include));
}
/**
@@ -141,9 +144,9 @@ abstract class SerializeAction extends JsonApiAction
* @param array $sort
* @return array
*/
- protected static function sanitizeSort(array $sort)
+ protected function sanitizeSort(array $sort)
{
- return array_intersect_key($sort, array_flip(static::$sortFields)) ?: static::$sort;
+ return array_intersect_key($sort, array_flip($this->sortFields)) ?: $this->sort;
}
/**
@@ -152,9 +155,9 @@ abstract class SerializeAction extends JsonApiAction
* @param int $limit
* @return int
*/
- protected static function sanitizeLimit($limit)
+ protected function sanitizeLimit($limit)
{
- return min($limit, static::$limitMax) ?: static::$limit;
+ return min($limit, $this->limitMax) ?: $this->limit;
}
/**
@@ -169,10 +172,10 @@ abstract class SerializeAction extends JsonApiAction
* is unknown ('last' link is ommitted).
* @return void
*/
- protected static function addPaginationLinks(Document $document, JsonApiRequest $request, $url, $total = true)
+ protected function addPaginationLinks(Document $document, JsonApiRequest $request, $url, $total = true)
{
$input = [];
- if ($request->limit != static::$limit) {
+ if ($request->limit != $this->limit) {
array_set($input, 'page.limit', $request->limit);
}
diff --git a/src/Api/Actions/TokenAction.php b/src/Api/Actions/TokenAction.php
index c4786f519..1ccff5dba 100644
--- a/src/Api/Actions/TokenAction.php
+++ b/src/Api/Actions/TokenAction.php
@@ -4,7 +4,7 @@ use Flarum\Api\Commands\GenerateAccessToken;
use Flarum\Api\Request;
use Flarum\Core\Users\UserRepository;
use Flarum\Core\Exceptions\PermissionDeniedException;
-use Flarum\Core\Users\Events\UserEmailChangeWasRequested;
+use Flarum\Events\UserEmailChangeWasRequested;
use Illuminate\Contracts\Bus\Dispatcher;
use Zend\Diactoros\Response\JsonResponse;
diff --git a/src/Api/Actions/Users/CreateAction.php b/src/Api/Actions/Users/CreateAction.php
index ce46aa5fd..8f26cb860 100644
--- a/src/Api/Actions/Users/CreateAction.php
+++ b/src/Api/Actions/Users/CreateAction.php
@@ -15,37 +15,37 @@ class CreateAction extends BaseCreateAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
+ public $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* @inheritdoc
*/
- public static $include = [];
+ public $include = [];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param Dispatcher $bus
diff --git a/src/Api/Actions/Users/DeleteAvatarAction.php b/src/Api/Actions/Users/DeleteAvatarAction.php
index 2919c2623..8d843845d 100644
--- a/src/Api/Actions/Users/DeleteAvatarAction.php
+++ b/src/Api/Actions/Users/DeleteAvatarAction.php
@@ -16,7 +16,7 @@ class DeleteAvatarAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
+ public $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* @param Dispatcher $bus
diff --git a/src/Api/Actions/Users/IndexAction.php b/src/Api/Actions/Users/IndexAction.php
index 0229c5336..bb7543efb 100644
--- a/src/Api/Actions/Users/IndexAction.php
+++ b/src/Api/Actions/Users/IndexAction.php
@@ -22,39 +22,39 @@ class IndexAction extends SerializeCollectionAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
+ public $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'groups' => true
];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = ['username', 'postsCount', 'discussionsCount', 'lastSeenTime', 'joinTime'];
+ public $sortFields = ['username', 'postsCount', 'discussionsCount', 'lastSeenTime', 'joinTime'];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param UserSearcher $searcher
@@ -84,7 +84,7 @@ class IndexAction extends SerializeCollectionAction
$results = $this->searcher->search($criteria, $request->limit, $request->offset, $request->include);
- static::addPaginationLinks(
+ $this->addPaginationLinks(
$document,
$request,
$this->url->toRoute('flarum.api.users.index'),
diff --git a/src/Api/Actions/Users/ShowAction.php b/src/Api/Actions/Users/ShowAction.php
index 263636b8f..371fff19e 100644
--- a/src/Api/Actions/Users/ShowAction.php
+++ b/src/Api/Actions/Users/ShowAction.php
@@ -15,39 +15,39 @@ class ShowAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\CurrentUserSerializer';
+ public $serializer = 'Flarum\Api\Serializers\CurrentUserSerializer';
/**
* @inheritdoc
*/
- public static $include = [
+ public $include = [
'groups' => true
];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param UserRepository $users
diff --git a/src/Api/Actions/Users/UpdateAction.php b/src/Api/Actions/Users/UpdateAction.php
index 6f30713f7..616b61f14 100644
--- a/src/Api/Actions/Users/UpdateAction.php
+++ b/src/Api/Actions/Users/UpdateAction.php
@@ -16,37 +16,37 @@ class UpdateAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\CurrentUserSerializer';
+ public $serializer = 'Flarum\Api\Serializers\CurrentUserSerializer';
/**
* @inheritdoc
*/
- public static $include = [];
+ public $include = [];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param Dispatcher $bus
diff --git a/src/Api/Actions/Users/UploadAvatarAction.php b/src/Api/Actions/Users/UploadAvatarAction.php
index 2b699efcb..545bfd855 100644
--- a/src/Api/Actions/Users/UploadAvatarAction.php
+++ b/src/Api/Actions/Users/UploadAvatarAction.php
@@ -16,37 +16,37 @@ class UploadAvatarAction extends SerializeResourceAction
/**
* @inheritdoc
*/
- public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
+ public $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* @inheritdoc
*/
- public static $include = [];
+ public $include = [];
/**
* @inheritdoc
*/
- public static $link = [];
+ public $link = [];
/**
* @inheritdoc
*/
- public static $limitMax = 50;
+ public $limitMax = 50;
/**
* @inheritdoc
*/
- public static $limit = 20;
+ public $limit = 20;
/**
* @inheritdoc
*/
- public static $sortFields = [];
+ public $sortFields = [];
/**
* @inheritdoc
*/
- public static $sort;
+ public $sort;
/**
* @param Dispatcher $bus
diff --git a/src/Api/ApiServiceProvider.php b/src/Api/ApiServiceProvider.php
index 737892f3d..c3c9860d8 100644
--- a/src/Api/ApiServiceProvider.php
+++ b/src/Api/ApiServiceProvider.php
@@ -1,6 +1,11 @@
routes();
+
+ $this->registerActivitySerializers();
+ $this->registerNotificationSerializers();
+ }
+
+ /**
+ * Register activity serializers.
+ */
+ protected function registerActivitySerializers()
+ {
+ $blueprints = [];
+ $serializers = [
+ 'posted' => 'Flarum\Api\Serializers\PostBasicSerializer',
+ 'startedDiscussion' => 'Flarum\Api\Serializers\PostBasicSerializer',
+ 'joined' => 'Flarum\Api\Serializers\UserSerializer'
+ ];
+
+ event(new RegisterActivityTypes($blueprints, $serializers));
+
+ foreach ($serializers as $type => $serializer) {
+ ActivitySerializer::setSubjectSerializer($type, $serializer);
+ }
+ }
+
+ /**
+ * Register notification serializers.
+ */
+ protected function registerNotificationSerializers()
+ {
+ $blueprints = [];
+ $serializers = [
+ 'discussionRenamed' => 'Flarum\Api\Serializers\DiscussionBasicSerializer'
+ ];
+
+ event(new RegisterNotificationTypes($blueprints, $serializers));
+
+ foreach ($serializers as $type => $serializer) {
+ NotificationSerializer::setSubjectSerializer($type, $serializer);
+ }
}
protected function routes()
@@ -268,6 +312,8 @@ class ApiServiceProvider extends ServiceProvider
'flarum.api.groups.delete',
$this->action('Flarum\Api\Actions\Groups\DeleteAction')
);
+
+ event(new RegisterApiRoutes($routes));
}
protected function action($class)
diff --git a/src/Api/Serializers/Serializer.php b/src/Api/Serializers/Serializer.php
index 75818e120..5da1f43ed 100644
--- a/src/Api/Serializers/Serializer.php
+++ b/src/Api/Serializers/Serializer.php
@@ -1,10 +1,10 @@
getDefaultAttributes($model);
- event(new SerializeAttributes($this, $model, $attributes));
+ event(new ApiAttributes($this, $model, $attributes));
return $attributes;
}
@@ -57,13 +50,26 @@ abstract class Serializer extends SerializerAbstract
*/
protected function getRelationshipFromMethod($name)
{
- if (isset(static::$relationMethods[$name])) {
- return call_user_func(static::$relationMethods[$name], $this);
+ if ($relationship = $this->getCustomRelationship($name)) {
+ return $relationship;
}
return parent::getRelationshipFromMethod($name);
}
+ /**
+ * Get a custom relationship.
+ *
+ * @param string $name
+ * @return mixed
+ */
+ protected function getCustomRelationship($name)
+ {
+ return app('events')->until(
+ new ApiRelationship($this, $name)
+ );
+ }
+
/**
* Get a closure that returns a Collection/Resource representing a relation.
*
@@ -154,16 +160,4 @@ abstract class Serializer extends SerializerAbstract
{
return $this->getRelationship($serializer, $relation, true);
}
-
- /**
- * Add a custom relation to the model.
- *
- * @param string $name The name of the relation.
- * @param callable $callback The callback to execute. This should return a
- * relation closure {@see Serializer::getRelationship()}
- */
- public static function setRelationMethod($name, callable $callback)
- {
- static::$relationMethods[get_called_class()][$name] = $callback;
- }
}
diff --git a/src/Console/GenerateExtensionCommand.php b/src/Console/GenerateExtensionCommand.php
index db4680644..caa0ab873 100644
--- a/src/Console/GenerateExtensionCommand.php
+++ b/src/Console/GenerateExtensionCommand.php
@@ -42,10 +42,12 @@ class GenerateExtensionCommand extends Command
public function fire()
{
do {
- $name = $this->ask('Extension name (-):');
- } while (! preg_match('/^([a-z0-9]+)-([a-z0-9-]+)$/i', $name, $match));
+ $vendor = $this->ask('Vendor name:');
+ } while (! preg_match('/^([a-z0-9-]+)$/i', $vendor));
- list(, $vendor, $package) = $match;
+ do {
+ $name = $this->ask('Extension name:');
+ } while (! preg_match('/^([a-z0-9-]+)$/i', $name));
do {
$title = $this->ask('Title:');
@@ -64,9 +66,8 @@ class GenerateExtensionCommand extends Command
$dir = public_path().'/extensions/'.$name;
$replacements = [
- '{{namespace}}' => ucfirst($vendor).'\\'.ucfirst($package),
- '{{escapedNamespace}}' => ucfirst($vendor).'\\\\'.ucfirst($package),
- '{{classPrefix}}' => ucfirst($package),
+ '{{namespace}}' => ucfirst($vendor).'\\'.ucfirst($name),
+ '{{escapedNamespace}}' => ucfirst($vendor).'\\\\'.ucfirst($name),
'{{name}}' => $name
];
@@ -78,7 +79,7 @@ class GenerateExtensionCommand extends Command
'name' => $name,
'title' => $title,
'description' => $description,
- 'tags' => [],
+ 'keywords' => [],
'version' => '0.1.0',
'author' => [
'name' => $authorName,
diff --git a/src/Console/ImportCommand.php b/src/Console/ImportCommand.php
index ae0f3a414..4329b380f 100644
--- a/src/Console/ImportCommand.php
+++ b/src/Console/ImportCommand.php
@@ -9,7 +9,7 @@ use Flarum\Core\Discussions\Discussion;
use Flarum\Core\Discussions\DiscussionState;
use Flarum\Core\Posts\CommentPost;
use Flarum\Tags\Tag;
-use Flarum\Core\Posts\Events\PostWasPosted;
+use Flarum\Events\PostWasPosted;
use Symfony\Component\Console\Helper\ProgressBar;
class ImportCommand extends Command
diff --git a/src/Core/Activity/Activity.php b/src/Core/Activity/Activity.php
index 4048b2f0b..16b5de481 100644
--- a/src/Core/Activity/Activity.php
+++ b/src/Core/Activity/Activity.php
@@ -27,7 +27,7 @@ class Activity extends Model
/**
* {@inheritdoc}
*/
- protected static $dateAttributes = ['time'];
+ protected $dates = ['time'];
/**
* A map of activity types and the model classes to use for their subjects.
diff --git a/src/Core/Activity/ActivityServiceProvider.php b/src/Core/Activity/ActivityServiceProvider.php
index b36bc2d19..c689ebbff 100644
--- a/src/Core/Activity/ActivityServiceProvider.php
+++ b/src/Core/Activity/ActivityServiceProvider.php
@@ -1,5 +1,7 @@
extend([
- (new Extend\EventSubscriber('Flarum\Core\Activity\Listeners\UserActivitySyncer')),
+ $this->registerActivityTypes();
- (new Extend\ActivityType('Flarum\Core\Activity\PostedBlueprint'))
- ->subjectSerializer('Flarum\Api\Serializers\PostBasicSerializer'),
+ $events = $this->app->make('events');
+ $events->subscribe('Flarum\Core\Activity\Listeners\UserActivitySyncer');
+ }
- (new Extend\ActivityType('Flarum\Core\Activity\StartedDiscussionBlueprint'))
- ->subjectSerializer('Flarum\Api\Serializers\PostBasicSerializer'),
+ /**
+ * Register activity types.
+ *
+ * @return void
+ */
+ public function registerActivityTypes()
+ {
+ $blueprints = [
+ 'Flarum\Core\Activity\PostedBlueprint',
+ 'Flarum\Core\Activity\StartedDiscussionBlueprint',
+ 'Flarum\Core\Activity\JoinedBlueprint'
+ ];
- (new Extend\ActivityType('Flarum\Core\Activity\JoinedBlueprint'))
- ->subjectSerializer('Flarum\Api\Serializers\UserBasicSerializer')
- ]);
+ event(new RegisterActivityTypes($blueprints));
+
+ foreach ($blueprints as $blueprint) {
+ Activity::setSubjectModel(
+ $blueprint::getType(),
+ $blueprint::getSubjectModel()
+ );
+ }
}
/**
diff --git a/src/Core/Activity/Listeners/UserActivitySyncer.php b/src/Core/Activity/Listeners/UserActivitySyncer.php
index cc8e8688d..2aebbcd3e 100755
--- a/src/Core/Activity/Listeners/UserActivitySyncer.php
+++ b/src/Core/Activity/Listeners/UserActivitySyncer.php
@@ -5,11 +5,11 @@ use Flarum\Core\Activity\PostedBlueprint;
use Flarum\Core\Activity\StartedDiscussionBlueprint;
use Flarum\Core\Activity\JoinedBlueprint;
use Flarum\Core\Posts\Post;
-use Flarum\Core\Posts\Events\PostWasPosted;
-use Flarum\Core\Posts\Events\PostWasDeleted;
-use Flarum\Core\Posts\Events\PostWasHidden;
-use Flarum\Core\Posts\Events\PostWasRestored;
-use Flarum\Core\Users\Events\UserWasRegistered;
+use Flarum\Events\PostWasPosted;
+use Flarum\Events\PostWasDeleted;
+use Flarum\Events\PostWasHidden;
+use Flarum\Events\PostWasRestored;
+use Flarum\Events\UserWasRegistered;
use Illuminate\Contracts\Events\Dispatcher;
class UserActivitySyncer
@@ -33,15 +33,15 @@ class UserActivitySyncer
*/
public function subscribe(Dispatcher $events)
{
- $events->listen('Flarum\Core\Posts\Events\PostWasPosted', __CLASS__.'@whenPostWasPosted');
- $events->listen('Flarum\Core\Posts\Events\PostWasHidden', __CLASS__.'@whenPostWasHidden');
- $events->listen('Flarum\Core\Posts\Events\PostWasRestored', __CLASS__.'@whenPostWasRestored');
- $events->listen('Flarum\Core\Posts\Events\PostWasDeleted', __CLASS__.'@whenPostWasDeleted');
- $events->listen('Flarum\Core\Users\Events\UserWasRegistered', __CLASS__.'@whenUserWasRegistered');
+ $events->listen('Flarum\Events\PostWasPosted', __CLASS__.'@whenPostWasPosted');
+ $events->listen('Flarum\Events\PostWasHidden', __CLASS__.'@whenPostWasHidden');
+ $events->listen('Flarum\Events\PostWasRestored', __CLASS__.'@whenPostWasRestored');
+ $events->listen('Flarum\Events\PostWasDeleted', __CLASS__.'@whenPostWasDeleted');
+ $events->listen('Flarum\Events\UserWasRegistered', __CLASS__.'@whenUserWasRegistered');
}
/**
- * @param \Flarum\Core\Posts\Events\PostWasPosted $event
+ * @param \Flarum\Events\PostWasPosted $event
* @return void
*/
public function whenPostWasPosted(PostWasPosted $event)
@@ -50,7 +50,7 @@ class UserActivitySyncer
}
/**
- * @param \Flarum\Core\Posts\Events\PostWasHidden $event
+ * @param \Flarum\Events\PostWasHidden $event
* @return void
*/
public function whenPostWasHidden(PostWasHidden $event)
@@ -59,7 +59,7 @@ class UserActivitySyncer
}
/**
- * @param \Flarum\Core\Posts\Events\PostWasRestored $event
+ * @param \Flarum\Events\PostWasRestored $event
* @return void
*/
public function whenPostWasRestored(PostWasRestored $event)
@@ -68,7 +68,7 @@ class UserActivitySyncer
}
/**
- * @param \Flarum\Core\Posts\Events\PostWasDeleted $event
+ * @param \Flarum\Events\PostWasDeleted $event
* @return void
*/
public function whenPostWasDeleted(PostWasDeleted $event)
@@ -77,7 +77,7 @@ class UserActivitySyncer
}
/**
- * @param \Flarum\Core\Users\Events\UserWasRegistered $event
+ * @param \Flarum\Events\UserWasRegistered $event
* @return void
*/
public function whenUserWasRegistered(UserWasRegistered $event)
diff --git a/src/Core/CoreServiceProvider.php b/src/Core/CoreServiceProvider.php
index ed3618bab..063701907 100644
--- a/src/Core/CoreServiceProvider.php
+++ b/src/Core/CoreServiceProvider.php
@@ -1,8 +1,7 @@
hasPermission('forum.'.$action) ?: null;
+ $events = $this->app->make('events');
+
+ $events->listen(ModelAllow::class, function (ModelAllow $event) {
+ if ($event->model instanceof Forum &&
+ $event->actor->hasPermission('forum.'.$event->action)) {
+ return true;
+ }
});
}
@@ -33,14 +37,6 @@ class CoreServiceProvider extends ServiceProvider
*/
public function register()
{
- $this->app->singleton('Flarum\Core\Settings\SettingsRepository', function() {
- return new MemoryCacheSettingsRepository(
- new DatabaseSettingsRepository(
- $this->app->make('Illuminate\Database\ConnectionInterface')
- )
- );
- });
-
$this->app->singleton('flarum.forum', 'Flarum\Core\Forum');
// TODO: probably use Illuminate's AggregateServiceProvider
diff --git a/src/Core/Discussions/Commands/DeleteDiscussionHandler.php b/src/Core/Discussions/Commands/DeleteDiscussionHandler.php
index b09c0d7f5..745d96184 100644
--- a/src/Core/Discussions/Commands/DeleteDiscussionHandler.php
+++ b/src/Core/Discussions/Commands/DeleteDiscussionHandler.php
@@ -1,7 +1,7 @@
extend([
- new Extend\EventSubscriber('Flarum\Core\Discussions\Listeners\DiscussionMetadataUpdater')
- ]);
-
Discussion::setValidator($this->app->make('validator'));
- Discussion::allow('*', function (Discussion $discussion, User $user, $action) {
- return $user->hasPermission('discussion.'.$action) ?: null;
- });
+ $events = $this->app->make('events');
- // Allow a user to rename their own discussion.
- Discussion::allow('rename', function (Discussion $discussion, User $user) {
- return $discussion->start_user_id == $user->id ?: null;
- // TODO: add limitations to time etc. according to a config setting
- });
+ $events->subscribe('Flarum\Core\Discussions\Listeners\DiscussionMetadataUpdater');
- Discussion::allow('delete', function (Discussion $discussion, User $user) {
- return $discussion->start_user_id == $user->id && $discussion->participants_count == 1 ?: null;
- // TODO: add limitations to time etc. according to a config setting
+ $events->listen(ModelAllow::class, function (ModelAllow $event) {
+ if ($event->model instanceof Discussion) {
+ if ($event->action === 'rename' &&
+ $event->model->start_user_id == $event->actor->id) {
+ return true;
+ }
+
+ if ($event->action === 'delete' &&
+ $event->model->start_user_id == $event->actor->id &&
+ $event->model->participants_count == 1) {
+ return true;
+ }
+
+ if ($event->actor->hasPermission('discussion.'.$event->action)) {
+ return true;
+ }
+ }
});
}
@@ -49,21 +55,15 @@ class DiscussionsServiceProvider extends ServiceProvider
'Flarum\Core\Discussions\Search\Fulltext\MySqlFulltextDriver'
);
- $this->app->instance('flarum.discussionGambits', [
- 'Flarum\Core\Discussions\Search\Gambits\AuthorGambit',
- 'Flarum\Core\Discussions\Search\Gambits\UnreadGambit'
- ]);
-
$this->app->when('Flarum\Core\Discussions\Search\DiscussionSearcher')
->needs('Flarum\Core\Search\GambitManager')
->give(function (Container $app) {
$gambits = new GambitManager($app);
-
- foreach ($app->make('flarum.discussionGambits') as $gambit) {
- $gambits->add($gambit);
- }
-
$gambits->setFulltextGambit('Flarum\Core\Discussions\Search\Gambits\FulltextGambit');
+ $gambits->add('Flarum\Core\Discussions\Search\Gambits\AuthorGambit');
+ $gambits->add('Flarum\Core\Discussions\Search\Gambits\UnreadGambit');
+
+ event(new RegisterDiscussionGambits($gambits));
return $gambits;
});
diff --git a/src/Core/Discussions/Listeners/DiscussionMetadataUpdater.php b/src/Core/Discussions/Listeners/DiscussionMetadataUpdater.php
index 416b467c3..30414333f 100755
--- a/src/Core/Discussions/Listeners/DiscussionMetadataUpdater.php
+++ b/src/Core/Discussions/Listeners/DiscussionMetadataUpdater.php
@@ -1,10 +1,10 @@
extend([
- new Extend\PostFormatter('Flarum\Core\Formatter\LinkifyFormatter')
- ]);
}
/**
diff --git a/src/Core/Model.php b/src/Core/Model.php
index ee461350a..922cbe4eb 100755
--- a/src/Core/Model.php
+++ b/src/Core/Model.php
@@ -1,6 +1,13 @@
dates);
+ $dates = $this->dates;
+
+ event(new ModelDates($this, $dates));
+
+ return $dates;
}
/**
- * Add an attribute to be converted to a date.
+ * Check whether or not a user has permission to perform an action,
+ * according to the collected conditions.
*
- * @param string $attribute
+ * @param User $actor
+ * @param string $action
+ * @return bool
*/
- public static function addDateAttribute($attribute)
+ public function can(User $actor, $action)
{
- static::$dateAttributes[] = $attribute;
+ $can = static::$dispatcher->until(new ModelAllow($this, $actor, $action));
+
+ if ($can !== null) {
+ return $can;
+ }
+
+ return false;
+ }
+
+ /**
+ * Assert that the user has a certain permission for this model, throwing
+ * an exception if they don't.
+ *
+ * @param User $actor
+ * @param string $action
+ * @throws PermissionDeniedException
+ */
+ public function assertCan(User $actor, $action)
+ {
+ if (! $this->can($actor, $action)) {
+ throw new PermissionDeniedException;
+ }
+ }
+
+ /**
+ * Scope a query to only include records that are visible to a user.
+ *
+ * @param Builder $query
+ * @param User $actor
+ */
+ public function scopeWhereVisibleTo(Builder $query, User $actor)
+ {
+ event(new ScopeModelVisibility($this, $query, $actor));
}
/**
@@ -71,40 +106,38 @@ abstract class Model extends Eloquent
// If a custom relation with this key has been set up, then we will load
// and return results from the query and hydrate the relationship's
// value on the "relationships" array.
- if (isset(static::$relationMethods[get_called_class()][$key])) {
- return $this->getCustomRelationship($key);
+ if ($relation = $this->getCustomRelation($key)) {
+ if (! $relation instanceof Relation) {
+ throw new LogicException('Relationship method must return an object of type '
+ . 'Illuminate\Database\Eloquent\Relations\Relation');
+ }
+
+ return $this->relations[$key] = $relation->getResults();
}
}
/**
- * Get a relationship value from a custom relationship method.
+ * Get a custom relation object.
*
* @param string $name
* @return mixed
- *
- * @throws \LogicException
*/
- protected function getCustomRelationship($name)
+ protected function getCustomRelation($name)
{
- $relation = static::$relationMethods[get_called_class()][$name]($this);
-
- if (! $relation instanceof Relation) {
- throw new LogicException('Relationship method must return an object of type '
- . 'Illuminate\Database\Eloquent\Relations\Relation');
- }
-
- return $this->relations[$name] = $relation->getResults();
+ return static::$dispatcher->until(
+ new ModelRelationship($this, $name)
+ );
}
/**
- * Add a custom relation to the model.
- *
- * @param string $name The name of the relation.
- * @param callable $callback The callback to execute. This should return an
- * object of type Illuminate\Database\Eloquent\Relations\Relation.
+ * @inheritdoc
*/
- public static function setRelationMethod($name, callable $callback)
+ public function __call($method, $arguments)
{
- static::$relationMethods[get_called_class()][$name] = $callback;
+ if ($relation = $this->getCustomRelation($method)) {
+ return $relation;
+ }
+
+ return parent::__call($method, $arguments);
}
}
diff --git a/src/Core/Notifications/Listeners/DiscussionRenamedNotifier.php b/src/Core/Notifications/Listeners/DiscussionRenamedNotifier.php
index 1d6c1d545..c8276c7a8 100755
--- a/src/Core/Notifications/Listeners/DiscussionRenamedNotifier.php
+++ b/src/Core/Notifications/Listeners/DiscussionRenamedNotifier.php
@@ -1,6 +1,6 @@
whereIn('type', $user->getAlertableNotificationTypes())
->where('is_deleted', false)
->groupBy('type', 'subject_id')
- ->latest('time')
+ ->orderByRaw('MAX(time) DESC')
->skip($offset)
->take($limit);
diff --git a/src/Core/Notifications/NotificationSyncer.php b/src/Core/Notifications/NotificationSyncer.php
index 7e32614b1..71943320c 100644
--- a/src/Core/Notifications/NotificationSyncer.php
+++ b/src/Core/Notifications/NotificationSyncer.php
@@ -1,6 +1,6 @@
extend([
- (new Extend\EventSubscriber('Flarum\Core\Notifications\Listeners\DiscussionRenamedNotifier')),
+ $events = $this->app->make('events');
- (new Extend\NotificationType('Flarum\Core\Notifications\DiscussionRenamedBlueprint'))
- ->subjectSerializer('Flarum\Api\Serializers\DiscussionBasicSerializer')
- ->enableByDefault('alert')
- ]);
+ $events->subscribe('Flarum\Core\Notifications\Listeners\DiscussionRenamedNotifier');
+
+ $this->registerNotificationTypes();
+ }
+
+ /**
+ * Register notification types.
+ *
+ * @return void
+ */
+ public function registerNotificationTypes()
+ {
+ $blueprints = [
+ 'Flarum\Core\Notifications\DiscussionRenamedBlueprint' => ['alert']
+ ];
+
+ event(new RegisterNotificationTypes($blueprints));
+
+ foreach ($blueprints as $blueprint => $enabled) {
+ Notification::setSubjectModel(
+ $type = $blueprint::getType(),
+ $blueprint::getSubjectModel()
+ );
+
+ User::addPreference(
+ User::getNotificationPreferenceKey($type, 'alert'),
+ 'boolval',
+ in_array('alert', $enabled)
+ );
+
+ if ((new ReflectionClass($blueprint))->implementsInterface('Flarum\Core\Notifications\MailableBlueprint')) {
+ User::addPreference(
+ User::getNotificationPreferenceKey($type, 'email'),
+ 'boolval',
+ in_array('email', $enabled)
+ );
+ }
+ }
}
/**
diff --git a/src/Core/Posts/Commands/DeletePostHandler.php b/src/Core/Posts/Commands/DeletePostHandler.php
index cc5d7b43b..ca854727f 100644
--- a/src/Core/Posts/Commands/DeletePostHandler.php
+++ b/src/Core/Posts/Commands/DeletePostHandler.php
@@ -1,7 +1,7 @@
exists = true;
$instance->setRawAttributes($attributes, true);
diff --git a/src/Core/Posts/PostsServiceProvider.php b/src/Core/Posts/PostsServiceProvider.php
index 765fbfa38..cb93b7fd6 100644
--- a/src/Core/Posts/PostsServiceProvider.php
+++ b/src/Core/Posts/PostsServiceProvider.php
@@ -2,6 +2,9 @@
use Flarum\Core\Discussions\Discussion;
use Flarum\Core\Users\User;
+use Flarum\Events\ModelAllow;
+use Flarum\Events\RegisterPostTypes;
+use Flarum\Events\ScopePostVisibility;
use Flarum\Support\ServiceProvider;
use Flarum\Extend;
@@ -14,45 +17,73 @@ class PostsServiceProvider extends ServiceProvider
*/
public function boot()
{
- $this->extend([
- new Extend\PostType('Flarum\Core\Posts\CommentPost'),
- new Extend\PostType('Flarum\Core\Posts\DiscussionRenamedPost')
- ]);
-
Post::setValidator($this->app->make('validator'));
CommentPost::setFormatter($this->app->make('flarum.formatter'));
- Post::allow('*', function ($post, $user, $action) {
- return $post->discussion->can($user, $action.'Posts') ?: null;
+ $this->registerPostTypes();
+
+ $events = $this->app->make('events');
+
+ $events->listen(ModelAllow::class, function (ModelAllow $event) {
+ if ($event->model instanceof Post) {
+ $post = $event->model;
+ $action = $event->action;
+ $actor = $event->actor;
+
+ if ($action === 'view' &&
+ (! $post->hide_user_id || $post->can($actor, 'edit'))) {
+ return true;
+ }
+
+ // A post is allowed to be edited if the user has permission to moderate
+ // the discussion which it's in, or if they are the author and the post
+ // hasn't been deleted by someone else.
+ if ($action === 'edit' &&
+ ($post->discussion->can($actor, 'editPosts') ||
+ ($post->user_id == $actor->id &&
+ (! $post->hide_user_id || $post->hide_user_id == $actor->id)))) {
+ return true;
+ }
+
+ if ($post->discussion->can($actor, $action.'Posts')) {
+ return true;
+ }
+ }
});
// When fetching a discussion's posts: if the user doesn't have permission
// to moderate the discussion, then they can't see posts that have been
// hidden by someone other than themself.
- Discussion::addPostVisibilityScope(function ($query, User $user, Discussion $discussion) {
- if (! $discussion->can($user, 'editPosts')) {
- $query->where(function ($query) use ($user) {
+ $events->listen(ScopePostVisibility::class, function (ScopePostVisibility $event) {
+ $user = $event->actor;
+
+ if (! $event->discussion->can($user, 'editPosts')) {
+ $event->query->where(function ($query) use ($user) {
$query->whereNull('hide_user_id')
- ->orWhere('hide_user_id', $user->id);
+ ->orWhere('hide_user_id', $user->id);
});
}
});
+ }
- Post::allow('view', function ($post, $user) {
- return ! $post->hide_user_id || $post->can($user, 'edit') ?: null;
- });
+ /**
+ * Register post types.
+ *
+ * @return void
+ */
+ public function registerPostTypes()
+ {
+ $models = [
+ 'Flarum\Core\Posts\CommentPost',
+ 'Flarum\Core\Posts\DiscussionRenamedPost'
+ ];
- // A post is allowed to be edited if the user has permission to moderate
- // the discussion which it's in, or if they are the author and the post
- // hasn't been deleted by someone else.
- Post::allow('edit', function ($post, $user) {
- if ($post->discussion->can($user, 'editPosts') ||
- ($post->user_id == $user->id && (! $post->hide_user_id || $post->hide_user_id == $user->id))
- ) {
- return true;
- }
- });
+ event(new RegisterPostTypes($models));
+
+ foreach ($models as $model) {
+ Post::setModel($model::$type, $model);
+ }
}
/**
diff --git a/src/Core/Search/RegexGambit.php b/src/Core/Search/RegexGambit.php
index 594ced2a9..cf8557fd1 100644
--- a/src/Core/Search/RegexGambit.php
+++ b/src/Core/Search/RegexGambit.php
@@ -17,7 +17,7 @@ abstract class RegexGambit implements Gambit
if ($matches = $this->match($bit)) {
list($negate) = array_splice($matches, 1, 1);
- $this->conditions($searcher, $matches, !! $negate);
+ $this->conditions($search, $matches, !! $negate);
}
return !! $matches;
diff --git a/src/Core/Settings/SettingsServiceProvider.php b/src/Core/Settings/SettingsServiceProvider.php
new file mode 100644
index 000000000..1bc6064ac
--- /dev/null
+++ b/src/Core/Settings/SettingsServiceProvider.php
@@ -0,0 +1,22 @@
+app->singleton('Flarum\Core\Settings\SettingsRepository', function () {
+ return new MemoryCacheSettingsRepository(
+ new DatabaseSettingsRepository(
+ $this->app->make('Illuminate\Database\ConnectionInterface')
+ )
+ );
+ });
+ }
+}
diff --git a/src/Core/Support/Locked.php b/src/Core/Support/Locked.php
index 56dc9df78..bce8cd2c3 100644
--- a/src/Core/Support/Locked.php
+++ b/src/Core/Support/Locked.php
@@ -2,6 +2,8 @@
use Flarum\Core\Exceptions\PermissionDeniedException;
use Flarum\Core\Users\User;
+use Flarum\Events\ModelAllow;
+use Illuminate\Contracts\Events\Dispatcher;
/**
* 'Lock' an object, allowing the permission of a user to perform an action to
@@ -9,75 +11,5 @@ use Flarum\Core\Users\User;
*/
trait Locked
{
- /**
- * @var callable[]
- */
- protected static $conditions = [];
- /**
- * Get the condition callbacks for the specified action.
- *
- * @param string $action
- * @return callable[]
- */
- protected static function getConditions($action)
- {
- $conditions = array_get(static::$conditions, $action, []);
- $all = array_get(static::$conditions, '*', []);
-
- return array_merge($conditions, $all);
- }
-
- /**
- * Allow the specified action if the given condition is satisfied.
- *
- * @param string $action
- * @param callable $condition The condition callback. Parameters are the
- * object that is locked, the user performing the action,
- * and the name of the action. This condition will be ignored if it
- * returns null; otherwise, the return value will determine whether or
- * not the action is allowed.
- */
- public static function allow($action, callable $condition)
- {
- foreach ((array)$action as $action) {
- static::$conditions[$action][] = $condition;
- }
- }
-
- /**
- * Check whether or not a user has permission to perform an action,
- * according to the collected conditions.
- *
- * @param User $actor
- * @param string $action
- * @return bool
- */
- public function can(User $actor, $action)
- {
- foreach ($this->getConditions($action) as $condition) {
- $can = $condition($this, $actor, $action);
-
- if ($can !== null) {
- return $can;
- }
- }
-
- return false;
- }
-
- /**
- * Assert that the user has a certain permission for this model, throwing
- * an exception if they don't.
- *
- * @param User $actor
- * @param string $action
- * @throws PermissionDeniedException
- */
- public function assertCan(User $actor, $action)
- {
- if (! $this->can($actor, $action)) {
- throw new PermissionDeniedException;
- }
- }
}
diff --git a/src/Core/Support/ValidatesBeforeSave.php b/src/Core/Support/ValidatesBeforeSave.php
index 1beebc5c9..85cc1626b 100644
--- a/src/Core/Support/ValidatesBeforeSave.php
+++ b/src/Core/Support/ValidatesBeforeSave.php
@@ -1,6 +1,7 @@
getDirty();
+ $rules = $this->expandUniqueRules($this->rules);
- $rules = $this->expandUniqueRules(array_only($this->rules, array_keys($dirty)));
+ $validator = static::$validator->make($this->getAttributes(), $rules);
- $validator = static::$validator->make($dirty, $rules);
-
- // TODO: event
+ event(new ModelValidator($this, $validator));
return $validator;
}
diff --git a/src/Core/Support/VisibleScope.php b/src/Core/Support/VisibleScope.php
deleted file mode 100644
index d09cf29f8..000000000
--- a/src/Core/Support/VisibleScope.php
+++ /dev/null
@@ -1,40 +0,0 @@
-raise(new UserWasDeleted($user));
});
+
+ event(new RegisterUserPreferences);
}
/**
diff --git a/src/Core/Users/UsersServiceProvider.php b/src/Core/Users/UsersServiceProvider.php
index d7be4d49b..14e446f77 100644
--- a/src/Core/Users/UsersServiceProvider.php
+++ b/src/Core/Users/UsersServiceProvider.php
@@ -1,6 +1,9 @@
extend([
- new Extend\EventSubscriber('Flarum\Core\Users\Listeners\UserMetadataUpdater'),
- new Extend\EventSubscriber('Flarum\Core\Users\Listeners\EmailConfirmationMailer')
- ]);
-
User::setHasher($this->app->make('hash'));
User::setFormatter($this->app->make('flarum.formatter'));
User::setValidator($this->app->make('validator'));
- User::addPreference('discloseOnline', 'boolval', true);
- User::addPreference('indexProfile', 'boolval', true);
+ $events = $this->app->make('events');
- User::allow('*', function (User $user, User $actor, $action) {
- return $actor->hasPermission('user.'.$action) ?: null;
+ $events->listen(RegisterUserPreferences::class, function (RegisterUserPreferences $event) {
+ $event->register('discloseOnline', 'boolval', true);
+ $event->register('indexProfile', 'boolval', true);
});
- User::allow(['edit', 'delete'], function (User $user, User $actor) {
- return $user->id == $actor->id ?: null;
+ $events->listen(ModelAllow::class, function (ModelAllow $event) {
+ if ($event->model instanceof User) {
+ if (in_array($event->action, ['edit', 'delete']) &&
+ $event->model->id == $event->actor->id) {
+ return true;
+ }
+
+ if ($event->actor->hasPermission('user.'.$event->action)) {
+ return true;
+ }
+ }
});
+
+ $events->subscribe('Flarum\Core\Users\Listeners\UserMetadataUpdater');
+ $events->subscribe('Flarum\Core\Users\Listeners\EmailConfirmationMailer');
}
/**
@@ -63,19 +73,14 @@ class UsersServiceProvider extends ServiceProvider
public function registerGambits()
{
- $this->app->instance('flarum.userGambits', []);
-
$this->app->when('Flarum\Core\Users\Search\UserSearcher')
->needs('Flarum\Core\Search\GambitManager')
->give(function (Container $app) {
$gambits = new GambitManager($app);
-
- foreach ($app->make('flarum.userGambits') as $gambit) {
- $gambits->add($gambit);
- }
-
$gambits->setFulltextGambit('Flarum\Core\Users\Search\Gambits\FulltextGambit');
+ event(new RegisterUserGambits($gambits));
+
return $gambits;
});
}
diff --git a/src/Api/Events/SerializeAttributes.php b/src/Events/ApiAttributes.php
similarity index 82%
rename from src/Api/Events/SerializeAttributes.php
rename to src/Events/ApiAttributes.php
index a92cdf7c6..98a73e2bd 100644
--- a/src/Api/Events/SerializeAttributes.php
+++ b/src/Events/ApiAttributes.php
@@ -1,8 +1,8 @@
-serializer = $serializer;
$this->model = $model;
$this->attributes = &$attributes;
+ $this->actor = $serializer->actor;
}
}
diff --git a/src/Events/ApiRelationship.php b/src/Events/ApiRelationship.php
new file mode 100644
index 000000000..59df26de8
--- /dev/null
+++ b/src/Events/ApiRelationship.php
@@ -0,0 +1,26 @@
+serializer = $serializer;
+ $this->relationship = $relationship;
+ }
+}
diff --git a/src/Core/Users/Events/AvatarWillBeDeleted.php b/src/Events/AvatarWillBeDeleted.php
similarity index 92%
rename from src/Core/Users/Events/AvatarWillBeDeleted.php
rename to src/Events/AvatarWillBeDeleted.php
index e1fc60bae..04b41ed80 100644
--- a/src/Core/Users/Events/AvatarWillBeDeleted.php
+++ b/src/Events/AvatarWillBeDeleted.php
@@ -1,4 +1,4 @@
-action = $action;
+ }
+
+ public function serializer($serializer)
+ {
+ $this->action->serializer = $serializer;
+ }
+
+ public function addInclude($relation, $default = true)
+ {
+ $this->action->include[$relation] = $default;
+ }
+
+ public function removeInclude($relation)
+ {
+ unset($this->action->include[$relation]);
+ }
+
+ public function addLink($relation)
+ {
+ $this->action->link[] = $relation;
+ }
+
+ public function removeLink($relation)
+ {
+ if (($k = array_search($relation, $this->action->link)) !== false) {
+ unset($this->action->link[$k]);
+ }
+ }
+
+ public function limitMax($limitMax)
+ {
+ $this->action->limitMax = $limitMax;
+ }
+
+ public function limit($limit)
+ {
+ $this->action->limit = $limit;
+ }
+
+ public function addSortField($field)
+ {
+ $this->action->sortFields[] = $field;
+ }
+
+ public function removeSortField($field)
+ {
+ if (($k = array_search($field, $this->action->sortFields)) !== false) {
+ unset($this->action->sortFields[$k]);
+ }
+ }
+
+ public function sort($sort)
+ {
+ $this->action->sort = $sort;
+ }
+}
diff --git a/src/Events/BuildClientView.php b/src/Events/BuildClientView.php
new file mode 100644
index 000000000..2528f91a5
--- /dev/null
+++ b/src/Events/BuildClientView.php
@@ -0,0 +1,57 @@
+action = $action;
+ $this->view = $view;
+ $this->keys = &$keys;
+ }
+
+ public function forumAssets($files)
+ {
+ if ($this->action instanceof ForumClientAction) {
+ $this->view->getAssets()->addFiles((array) $files);
+ }
+ }
+
+ public function forumBootstrapper($bootstrapper)
+ {
+ if ($this->action instanceof ForumClientAction) {
+ $this->view->addBootstrapper($bootstrapper);
+ }
+ }
+
+ public function forumTranslations(array $keys)
+ {
+ if ($this->action instanceof ForumClientAction) {
+ foreach ($keys as $key) {
+ $this->keys[] = $key;
+ }
+ }
+ }}
diff --git a/src/Core/Discussions/Events/DiscussionSearchWillBePerformed.php b/src/Events/DiscussionSearchWillBePerformed.php
similarity index 91%
rename from src/Core/Discussions/Events/DiscussionSearchWillBePerformed.php
rename to src/Events/DiscussionSearchWillBePerformed.php
index 74ad66495..3fb74983c 100644
--- a/src/Core/Discussions/Events/DiscussionSearchWillBePerformed.php
+++ b/src/Events/DiscussionSearchWillBePerformed.php
@@ -1,4 +1,4 @@
-model = $model;
+ $this->actor = $actor;
+ $this->action = $action;
+ }
+}
diff --git a/src/Events/ModelDates.php b/src/Events/ModelDates.php
new file mode 100644
index 000000000..371b47cdf
--- /dev/null
+++ b/src/Events/ModelDates.php
@@ -0,0 +1,30 @@
+model = $model;
+ $this->dates = &$dates;
+ }
+}
diff --git a/src/Events/ModelRelationship.php b/src/Events/ModelRelationship.php
new file mode 100644
index 000000000..ef8b92754
--- /dev/null
+++ b/src/Events/ModelRelationship.php
@@ -0,0 +1,30 @@
+model = $model;
+ $this->relationship = $relationship;
+ }
+}
diff --git a/src/Events/ModelValidator.php b/src/Events/ModelValidator.php
new file mode 100644
index 000000000..171b3ad17
--- /dev/null
+++ b/src/Events/ModelValidator.php
@@ -0,0 +1,32 @@
+model = $model;
+ $this->validator = $validator;
+ }
+}
diff --git a/src/Core/Notifications/Events/NotificationWillBeSent.php b/src/Events/NotificationWillBeSent.php
similarity index 91%
rename from src/Core/Notifications/Events/NotificationWillBeSent.php
rename to src/Events/NotificationWillBeSent.php
index fc30a253e..030332514 100644
--- a/src/Core/Notifications/Events/NotificationWillBeSent.php
+++ b/src/Events/NotificationWillBeSent.php
@@ -1,4 +1,4 @@
-blueprints = &$blueprints;
+ $this->serializers = &$serializers;
+ }
+
+ public function register($blueprint, $serializer)
+ {
+ if (! (new ReflectionClass($blueprint))->implementsInterface('Flarum\Core\Activity\Blueprint')) {
+ throw new InvalidArgumentException('Activity blueprint ' . $blueprint
+ . ' must implement Flarum\Core\Activity\Blueprint');
+ }
+
+ $this->blueprints[] = $blueprint;
+
+ $this->serializers[$blueprint::getType()] = $serializer;
+ }
+}
diff --git a/src/Events/RegisterApiRoutes.php b/src/Events/RegisterApiRoutes.php
new file mode 100644
index 000000000..aca6a9846
--- /dev/null
+++ b/src/Events/RegisterApiRoutes.php
@@ -0,0 +1,19 @@
+routes = $routes;
+ }
+}
diff --git a/src/Events/RegisterDiscussionGambits.php b/src/Events/RegisterDiscussionGambits.php
new file mode 100644
index 000000000..c7ca0ec40
--- /dev/null
+++ b/src/Events/RegisterDiscussionGambits.php
@@ -0,0 +1,19 @@
+gambits = $gambits;
+ }
+}
diff --git a/src/Events/RegisterForumRoutes.php b/src/Events/RegisterForumRoutes.php
new file mode 100644
index 000000000..d859930b5
--- /dev/null
+++ b/src/Events/RegisterForumRoutes.php
@@ -0,0 +1,19 @@
+routes = $routes;
+ }
+}
diff --git a/src/Events/RegisterLocales.php b/src/Events/RegisterLocales.php
new file mode 100644
index 000000000..737698433
--- /dev/null
+++ b/src/Events/RegisterLocales.php
@@ -0,0 +1,24 @@
+manager = $manager;
+ }
+
+ public function addTranslations($locale, $file)
+ {
+ $this->manager->addTranslations($locale, $file);
+ }
+}
diff --git a/src/Events/RegisterNotificationTypes.php b/src/Events/RegisterNotificationTypes.php
new file mode 100644
index 000000000..0c44fc9b1
--- /dev/null
+++ b/src/Events/RegisterNotificationTypes.php
@@ -0,0 +1,35 @@
+blueprints = &$blueprints;
+ $this->serializers = &$serializers;
+ }
+
+ public function register($blueprint, $serializer, $enabledByDefault = [])
+ {
+ if (! (new ReflectionClass($blueprint))->implementsInterface('Flarum\Core\Notifications\Blueprint')) {
+ throw new InvalidArgumentException('Notification blueprint ' . $blueprint
+ . ' must implement Flarum\Core\Notifications\Blueprint');
+ }
+
+ $this->blueprints[$blueprint] = $enabledByDefault;
+
+ $this->serializers[$blueprint::getType()] = $serializer;
+ }
+}
diff --git a/src/Events/RegisterPostTypes.php b/src/Events/RegisterPostTypes.php
new file mode 100644
index 000000000..5798fd137
--- /dev/null
+++ b/src/Events/RegisterPostTypes.php
@@ -0,0 +1,16 @@
+models = &$models;
+ }
+
+ public function register($class)
+ {
+ $this->models[] = $class;
+ }
+}
diff --git a/src/Events/RegisterUserGambits.php b/src/Events/RegisterUserGambits.php
new file mode 100644
index 000000000..c906b5d72
--- /dev/null
+++ b/src/Events/RegisterUserGambits.php
@@ -0,0 +1,27 @@
+gambits = $gambits;
+ }
+
+ /**
+ * @param string $gambit
+ */
+ public function register($gambit)
+ {
+ $this->gambits->add($gambit);
+ }
+}
diff --git a/src/Events/RegisterUserPreferences.php b/src/Events/RegisterUserPreferences.php
new file mode 100644
index 000000000..359017fc0
--- /dev/null
+++ b/src/Events/RegisterUserPreferences.php
@@ -0,0 +1,11 @@
+model = $model;
+ $this->query = $query;
+ $this->actor = $actor;
+ }
+}
diff --git a/src/Events/ScopePostVisibility.php b/src/Events/ScopePostVisibility.php
new file mode 100644
index 000000000..8fa63f822
--- /dev/null
+++ b/src/Events/ScopePostVisibility.php
@@ -0,0 +1,38 @@
+discussion = $discussion;
+ $this->query = $query;
+ $this->actor = $actor;
+ }
+}
diff --git a/src/Core/Users/Events/UserAvatarWasChanged.php b/src/Events/UserAvatarWasChanged.php
similarity index 88%
rename from src/Core/Users/Events/UserAvatarWasChanged.php
rename to src/Events/UserAvatarWasChanged.php
index c90a8e237..0ac341464 100644
--- a/src/Core/Users/Events/UserAvatarWasChanged.php
+++ b/src/Events/UserAvatarWasChanged.php
@@ -1,4 +1,4 @@
-class = $class;
- }
-
- public function subjectSerializer($serializer)
- {
- $this->serializer = $serializer;
-
- return $this;
- }
-
- public function extend(Container $container)
- {
- $class = $this->class;
- $type = $class::getType();
-
- Activity::setSubjectModel($type, $class::getSubjectModel());
-
- if ($this->serializer) {
- ActivitySerializer::setSubjectSerializer($type, $this->serializer);
- }
- }
-}
diff --git a/src/Extend/AdminClient.php b/src/Extend/AdminClient.php
deleted file mode 100644
index b12e82ae5..000000000
--- a/src/Extend/AdminClient.php
+++ /dev/null
@@ -1,34 +0,0 @@
-assets = array_merge($this->assets, $assets);
-
- return $this;
- }
-
- public function translations($keys)
- {
- $this->translations = array_merge($this->translations, $keys);
-
- return $this;
- }
-
- public function extend(Container $container)
- {
- $container->make('events')->listen('Flarum\Admin\Events\RenderView', function ($event) {
- $event->assets->addFiles($this->assets);
- });
-
- IndexAction::$translations = array_merge(IndexAction::$translations, $this->translations);
- }
-}
diff --git a/src/Extend/Api.php b/src/Extend/Api.php
deleted file mode 100644
index 616f2d07f..000000000
--- a/src/Extend/Api.php
+++ /dev/null
@@ -1,35 +0,0 @@
-routes[] = compact('method', 'url', 'name', 'action');
-
- return $this;
- }
-
- public function extend(Container $container)
- {
- if ($container->make('type') !== 'api') {
- return;
- }
-
- if (count($this->routes)) {
- $routes = $container->make('flarum.api.routes');
-
- foreach ($this->routes as $route) {
- $method = $route['method'];
- $routes->$method($route['url'], $route['name'], function (ServerRequestInterface $httpRequest, $routeParams) use ($container, $route) {
- $action = $container->make($route['action']);
-
- return $action->handle($httpRequest, $routeParams);
- });
- }
- }
- }
-}
diff --git a/src/Extend/ApiAction.php b/src/Extend/ApiAction.php
deleted file mode 100644
index cd2f25951..000000000
--- a/src/Extend/ApiAction.php
+++ /dev/null
@@ -1,143 +0,0 @@
-action = $action;
- }
-
- public function serializer($serializer)
- {
- $this->serializer = $serializer;
-
- return $this;
- }
-
- public function addInclude($relation, $default = true)
- {
- $this->addInclude[] = compact('relation', 'default');
-
- return $this;
- }
-
- public function removeInclude($relation)
- {
- $this->removeInclude[] = $relation;
-
- return $this;
- }
-
- public function addLink($relation)
- {
- $this->addLink[] = $relation;
-
- return $this;
- }
-
- public function removeLink($relation)
- {
- $this->removeLink[] = $relation;
-
- return $this;
- }
-
- public function limitMax($limitMax)
- {
- $this->limitMax = $limitMax;
-
- return $this;
- }
-
- public function limit($limit)
- {
- $this->limit = $limit;
-
- return $this;
- }
-
- public function addSortField($field)
- {
- $this->addSortFields[] = $field;
-
- return $this;
- }
-
- public function removeSortField($field)
- {
- $this->removeSortFields[] = $field;
-
- return $this;
- }
-
- public function sort($sort)
- {
- $this->sort = $sort;
-
- return $this;
- }
-
- public function extend(Container $container)
- {
- foreach ((array) $this->action as $action) {
- if ($this->serializer) {
- $action::$serializer = $this->serializer;
- }
- foreach ($this->addInclude as $include) {
- $action::$include[$include['relation']] = $include['default'];
- }
- foreach ($this->removeInclude as $relation) {
- unset($action::$include[$relation]);
- }
- foreach ($this->addLink as $relation) {
- $action::$link[] = $relation;
- }
- foreach ($this->removeLink as $relation) {
- if (($k = array_search($relation, $action::$link)) !== false) {
- unset($action::$link[$k]);
- }
- }
- if ($this->limitMax) {
- $action::$limitMax = $this->limitMax;
- }
- if ($this->limit) {
- $action::$limit = $this->limit;
- }
- foreach ($this->addSortFields as $field) {
- $action::$sortFields[] = $field;
- }
- foreach ($this->removeSortFields as $field) {
- if (($k = array_search($field, $action::$sortFields)) !== false) {
- unset($action::$sortFields[$k]);
- }
- }
- if ($this->sort) {
- $action::$sort = $this->sort;
- }
- }
- }
-}
diff --git a/src/Extend/ApiSerializer.php b/src/Extend/ApiSerializer.php
deleted file mode 100644
index 14010c745..000000000
--- a/src/Extend/ApiSerializer.php
+++ /dev/null
@@ -1,61 +0,0 @@
-serializer = $serializer;
- }
-
- public function attributes($callback)
- {
- $this->attributes[] = $callback;
-
- return $this;
- }
-
- public function hasOne($relation, $related)
- {
- $this->relations[$relation] = function ($serializer) use ($relation, $related) {
- return $serializer->hasOne($related, $relation);
- };
-
- return $this;
- }
-
- public function hasMany($relation, $related)
- {
- $this->relations[$relation] = function ($serializer) use ($relation, $related) {
- return $serializer->hasMany($related, $relation);
- };
-
- return $this;
- }
-
- public function extend(Container $container)
- {
- $serializer = $this->serializer;
-
- if (count($this->attributes)) {
- $container->make('events')->listen('Flarum\Api\Events\SerializeAttributes', function ($event) use ($serializer) {
- if ($event->serializer instanceof $serializer) {
- foreach ($this->attributes as $callback) {
- $callback($event->attributes, $event->model, $event->serializer->actor->getUser());
- }
- }
- });
- }
-
- foreach ($this->relations as $relation => $callback) {
- $serializer::addRelationship($relation, $callback);
- }
- }
-}
diff --git a/src/Extend/DiscussionGambit.php b/src/Extend/DiscussionGambit.php
deleted file mode 100644
index 40ee5dbbb..000000000
--- a/src/Extend/DiscussionGambit.php
+++ /dev/null
@@ -1,18 +0,0 @@
-class = $class;
- }
-
- public function extend(Container $container)
- {
- $container->make('flarum.discussionGambits')[] = $this->class;
- }
-}
diff --git a/src/Extend/EventSubscriber.php b/src/Extend/EventSubscriber.php
deleted file mode 100644
index 27b129afc..000000000
--- a/src/Extend/EventSubscriber.php
+++ /dev/null
@@ -1,20 +0,0 @@
-subscriber = $subscriber;
- }
-
- public function extend(Container $container)
- {
- foreach ((array) $this->subscriber as $subscriber) {
- $container->make('events')->subscribe($subscriber);
- }
- }
-}
diff --git a/src/Extend/ExtenderInterface.php b/src/Extend/ExtenderInterface.php
deleted file mode 100644
index adc96c30a..000000000
--- a/src/Extend/ExtenderInterface.php
+++ /dev/null
@@ -1,8 +0,0 @@
-assets = array_merge($this->assets, $assets);
-
- return $this;
- }
-
- public function translations($keys)
- {
- $this->translations = array_merge($this->translations, $keys);
-
- return $this;
- }
-
- public function route($method, $url, $name, $action = 'Flarum\Forum\Actions\IndexAction')
- {
- $this->routes[] = compact('method', 'url', 'name', 'action');
-
- return $this;
- }
-
- public function extend(Container $container)
- {
- if ($container->make('type') !== 'forum') {
- return;
- }
-
- $container->make('events')->listen('Flarum\Forum\Events\RenderView', function ($event) {
- $event->assets->addFiles($this->assets);
- });
-
- IndexAction::$translations = array_merge(IndexAction::$translations, $this->translations);
-
- if (count($this->routes)) {
- $routes = $container->make('flarum.forum.routes');
-
- foreach ($this->routes as $route) {
- $method = $route['method'];
- $routes->$method($route['url'], $route['name'], function (ServerRequestInterface $httpRequest, $routeParams) use ($container, $route) {
- $action = $container->make($route['action']);
-
- return $action->handle($httpRequest, $routeParams);
- });
- }
- }
- }
-}
diff --git a/src/Extend/Locale.php b/src/Extend/Locale.php
deleted file mode 100644
index 6178db770..000000000
--- a/src/Extend/Locale.php
+++ /dev/null
@@ -1,57 +0,0 @@
-locale = $locale;
- }
-
- public function translations($translations)
- {
- $this->translations = $translations;
-
- return $this;
- }
-
- public function config($config)
- {
- $this->config = $config;
-
- return $this;
- }
-
- public function js($js)
- {
- $this->js = $js;
-
- return $this;
- }
-
- public function extend(Container $container)
- {
- $manager = $container->make('flarum.localeManager');
-
- if ($this->translations) {
- $manager->addTranslations($this->locale, $this->translations);
- }
-
- if ($this->config) {
- $manager->addConfig($this->locale, $this->config);
- }
-
- if ($this->js) {
- $manager->addJsFile($this->locale, $this->js);
- }
- }
-}
diff --git a/src/Extend/Model.php b/src/Extend/Model.php
deleted file mode 100644
index bc449e0ec..000000000
--- a/src/Extend/Model.php
+++ /dev/null
@@ -1,96 +0,0 @@
-model = $model;
- }
-
- public function scopeVisible(Closure $callback)
- {
- $this->scopeVisible[] = $callback;
-
- return $this;
- }
-
- public function allow($action, Closure $callback)
- {
- $this->allow[] = compact('action', 'callback');
-
- return $this;
- }
-
- public function date($attribute)
- {
- $this->dates[] = $attribute;
- }
-
- public function hasOne($relation, $related, $foreignKey = null, $localKey = null)
- {
- $this->relations[$relation] = function ($model) use ($relation, $related, $foreignKey, $localKey) {
- return $model->hasOne($related, $foreignKey, $localKey, $relation);
- };
-
- return $this;
- }
-
- public function belongsTo($relation, $related, $foreignKey = null, $otherKey = null)
- {
- $this->relations[$relation] = function ($model) use ($relation, $related, $foreignKey, $otherKey) {
- return $model->belongsTo($related, $foreignKey, $otherKey, $relation);
- };
-
- return $this;
- }
-
- public function hasMany($relation, $related, $foreignKey = null, $localKey = null)
- {
- $this->relations[$relation] = function ($model) use ($relation, $related, $foreignKey, $localKey) {
- return $model->hasMany($related, $foreignKey, $localKey, $relation);
- };
-
- return $this;
- }
-
- public function belongsToMany($relation, $related, $table = null, $foreignKey = null, $otherKey = null)
- {
- $this->relations[$relation] = function ($model) use ($relation, $related, $table, $foreignKey, $otherKey) {
- return $model->belongsToMany($related, $table, $foreignKey, $otherKey, $relation);
- };
-
- return $this;
- }
-
- public function extend(Container $container)
- {
- $model = $this->model;
-
- foreach ($this->relations as $relation => $callback) {
- $model::setRelationMethod($relation, $callback);
- }
-
- foreach ($this->scopeVisible as $callback) {
- $model::addVisibleScope($callback);
- }
-
- foreach ($this->allow as $info) {
- $model::allow($info['action'], $info['callback']);
- }
-
- foreach ($this->dates as $attribute) {
- $model::addDateAttribute($attribute);
- }
- }
-}
diff --git a/src/Extend/NotificationType.php b/src/Extend/NotificationType.php
deleted file mode 100644
index 6517b86ce..000000000
--- a/src/Extend/NotificationType.php
+++ /dev/null
@@ -1,51 +0,0 @@
-class = $class;
- }
-
- public function subjectSerializer($serializer)
- {
- $this->serializer = $serializer;
-
- return $this;
- }
-
- public function enableByDefault($method)
- {
- $this->enabled[] = $method;
-
- return $this;
- }
-
- public function extend(Container $container)
- {
- $class = $this->class;
- $type = $class::getType();
-
- Notification::setSubjectModel($type, $class::getSubjectModel());
-
- User::addPreference(User::getNotificationPreferenceKey($type, 'alert'), 'boolval', in_array('alert', $this->enabled));
-
- if ((new ReflectionClass($class))->implementsInterface('Flarum\Core\Notifications\MailableBlueprint')) {
- User::addPreference(User::getNotificationPreferenceKey($type, 'email'), 'boolval', in_array('email', $this->enabled));
- }
-
- NotificationSerializer::setSubjectSerializer($type, $this->serializer);
- }
-}
diff --git a/src/Extend/PostFormatter.php b/src/Extend/PostFormatter.php
deleted file mode 100644
index 04018272c..000000000
--- a/src/Extend/PostFormatter.php
+++ /dev/null
@@ -1,20 +0,0 @@
-class = $class;
- }
-
- public function extend(Container $container)
- {
- $container->make('flarum.formatter')->add($this->class);
- }
-}
diff --git a/src/Extend/PostType.php b/src/Extend/PostType.php
deleted file mode 100644
index 57e762ef0..000000000
--- a/src/Extend/PostType.php
+++ /dev/null
@@ -1,21 +0,0 @@
-class = $class;
- }
-
- public function extend(Container $container)
- {
- $class = $this->class;
-
- Post::setModel($class::$type, $class);
- }
-}
diff --git a/src/Forum/Actions/ClientAction.php b/src/Forum/Actions/ClientAction.php
index 57e511a89..b63afaf02 100644
--- a/src/Forum/Actions/ClientAction.php
+++ b/src/Forum/Actions/ClientAction.php
@@ -44,7 +44,7 @@ abstract class ClientAction extends BaseClientAction
'core.delete_forever',
'core.deleted',
'core.disclose_online',
- 'core.discussion_renamed',
+ 'core.discussion_renamed_post',
'core.discussion_renamed_notification',
'core.discussion_replied',
'core.discussion_started',
@@ -112,10 +112,11 @@ abstract class ClientAction extends BaseClientAction
'core.send_password_reset_email',
'core.settings',
'core.sign_up',
+ 'core.sort_latest',
'core.sort_newest',
'core.sort_oldest',
- 'core.sort_recent',
- 'core.sort_replies',
+ 'core.sort_relevance',
+ 'core.sort_top',
'core.start_a_discussion',
'core.started_a_discussion',
'core.unread_posts',
diff --git a/src/Forum/Actions/LoginAction.php b/src/Forum/Actions/LoginAction.php
index 833f90ea6..dfcf1a863 100644
--- a/src/Forum/Actions/LoginAction.php
+++ b/src/Forum/Actions/LoginAction.php
@@ -1,7 +1,7 @@
command = $command;
- $this->params = $params;
- }
-}
diff --git a/src/Forum/Events/RenderView.php b/src/Forum/Events/RenderView.php
deleted file mode 100644
index 1607288cf..000000000
--- a/src/Forum/Events/RenderView.php
+++ /dev/null
@@ -1,17 +0,0 @@
-view = &$view;
- $this->assets = $assets;
- $this->action = $action;
- }
-}
diff --git a/src/Forum/ForumServiceProvider.php b/src/Forum/ForumServiceProvider.php
index 354cac101..9f8cc6a47 100644
--- a/src/Forum/ForumServiceProvider.php
+++ b/src/Forum/ForumServiceProvider.php
@@ -1,6 +1,7 @@
action('Flarum\Forum\Actions\SavePasswordAction')
);
+
+ event(new RegisterForumRoutes($routes));
}
protected function action($class)
diff --git a/src/Locale/JsCompiler.php b/src/Locale/JsCompiler.php
index 1d574956a..96b18e10f 100644
--- a/src/Locale/JsCompiler.php
+++ b/src/Locale/JsCompiler.php
@@ -13,14 +13,18 @@ class JsCompiler extends RevisionCompiler
public function compile()
{
- $output = "var initLocale = function(app) {
- app.translator.translations = ".json_encode($this->translations).";";
+ $output = "System.register('locale', [], function() {
+ return {
+ execute: function() {
+ app.translator.translations = ".json_encode($this->translations).";\n";
foreach ($this->files as $filename) {
$output .= file_get_contents($filename);
}
- $output .= "};";
+ $output .= "}
+ };
+});";
return $output;
}
diff --git a/src/Locale/LocaleServiceProvider.php b/src/Locale/LocaleServiceProvider.php
index ac339dca8..0ce07488e 100644
--- a/src/Locale/LocaleServiceProvider.php
+++ b/src/Locale/LocaleServiceProvider.php
@@ -1,7 +1,7 @@
setupLocale('en');
+ $manager = $this->app->make('flarum.localeManager');
+
+ $this->registerLocale($manager, 'en');
+
+ event(new RegisterLocales($manager));
}
- public function setupLocale($locale)
+ public function registerLocale(LocaleManager $manager, $locale)
{
$dir = __DIR__.'/../../locale/'.$locale;
- $this->extend(
- (new Extend\Locale($locale))
- ->translations($dir.'/translations.yml')
- ->config($dir.'/config.php')
- ->js($dir.'/config.js')
- );
+ $manager->addTranslations($locale, $dir.'/translations.yml');
+ $manager->addConfig($locale, $dir.'/config.php');
+ $manager->addJsFile($locale, $dir.'/config.js');
}
public function register()
diff --git a/src/Support/ClientAction.php b/src/Support/ClientAction.php
index 3ad5c5a96..64025e29f 100644
--- a/src/Support/ClientAction.php
+++ b/src/Support/ClientAction.php
@@ -7,6 +7,7 @@ use Flarum\Assets\LessCompiler;
use Flarum\Core;
use Flarum\Core\Settings\SettingsRepository;
use Flarum\Core\Users\User;
+use Flarum\Events\BuildClientView;
use Flarum\Locale\JsCompiler as LocaleJsCompiler;
use Flarum\Locale\LocaleManager;
use Psr\Http\Message\ServerRequestInterface as Request;
@@ -107,7 +108,7 @@ abstract class ClientAction extends HtmlAction
$translations = $this->locales->getTranslations($actor->locale);
$keys = $this->translationKeys;
- // TODO: event($this, $view, $keys)
+ event(new BuildClientView($this, $view, $keys));
$translations = $this->filterTranslations($translations, $keys);
diff --git a/src/Support/ClientView.php b/src/Support/ClientView.php
index c36388c64..c2679a6f2 100644
--- a/src/Support/ClientView.php
+++ b/src/Support/ClientView.php
@@ -47,6 +47,13 @@ class ClientView implements Renderable
*/
protected $layout;
+ /**
+ * An array of JS modules to import before booting the app.
+ *
+ * @var array
+ */
+ protected $bootstrappers = ['locale'];
+
/**
* An array of strings to append to the page's .
*
@@ -156,6 +163,16 @@ class ClientView implements Renderable
$this->footStrings[] = $string;
}
+ /**
+ * Add a JavaScript module to be imported before the app is booted.
+ *
+ * @param string $string
+ */
+ public function addBootstrapper($string)
+ {
+ $this->bootstrappers[] = $string;
+ }
+
/**
* Get the view's asset manager.
*
@@ -196,6 +213,7 @@ class ClientView implements Renderable
$view->head = implode("\n", $this->headStrings);
$view->foot = implode("\n", $this->footStrings);
+ $view->bootstrappers = $this->bootstrappers;
return $view->render();
}
diff --git a/src/Support/Extension.php b/src/Support/Extension.php
new file mode 100644
index 000000000..65b947b28
--- /dev/null
+++ b/src/Support/Extension.php
@@ -0,0 +1,7 @@
+app->make('Flarum\Core\Settings\SettingsRepository')->get('extensions_enabled');
- $extensions = json_decode($config, true);
- $providers = [];
-
- foreach ($extensions as $extension) {
- if (file_exists($file = public_path().'/extensions/'.$extension.'/bootstrap.php') ||
- file_exists($file = base_path().'/extensions/'.$extension.'/bootstrap.php')) {
- $providers[$extension] = require $file;
- }
- }
-
- // @todo store $providers somewhere (in Core?) so that extensions can talk to each other
- }
-}
diff --git a/src/Support/ExtensionsServiceProvider.php b/src/Support/ExtensionsServiceProvider.php
new file mode 100644
index 000000000..8399c4897
--- /dev/null
+++ b/src/Support/ExtensionsServiceProvider.php
@@ -0,0 +1,23 @@
+app->make('Flarum\Core\Settings\SettingsRepository')->get('extensions_enabled');
+ $extensions = json_decode($config, true);
+ $providers = [];
+
+ foreach ($extensions as $extension) {
+ if (file_exists($file = public_path().'/extensions/'.$extension.'/bootstrap.php')) {
+ $providerName = require $file;
+ $providers[$extension] = $this->app->register($providerName);
+ }
+ }
+ }
+}
diff --git a/src/Support/ServiceProvider.php b/src/Support/ServiceProvider.php
index f67858b49..b50ac38f3 100644
--- a/src/Support/ServiceProvider.php
+++ b/src/Support/ServiceProvider.php
@@ -1,22 +1,9 @@
extend($this->extenders());
- }
-
/**
* Register the service provider.
*
@@ -25,32 +12,4 @@ class ServiceProvider extends IlluminateServiceProvider
public function register()
{
}
-
- /**
- * @return ExtenderInterface[]
- */
- public function extenders()
- {
- return [];
- }
-
- /**
- * @param ExtenderInterface|ExtenderInterface[] $extenders
- * @return void
- */
- protected function extend($extenders)
- {
- if (! is_array($extenders)) {
- $extenders = [$extenders];
- }
-
- foreach ($extenders as $extender) {
- if (! $extender instanceof ExtenderInterface) {
- throw new InvalidArgumentException('Argument must be an object of type '
- . ExtenderInterface::class);
- }
-
- $extender->extend($this->app);
- }
- }
}
diff --git a/stubs/extension/.editorconfig b/stubs/extension/.editorconfig
new file mode 100644
index 000000000..5612a5e74
--- /dev/null
+++ b/stubs/extension/.editorconfig
@@ -0,0 +1,32 @@
+# EditorConfig helps developers define and maintain consistent
+# coding styles between different editors and IDEs
+# editorconfig.org
+
+root = true
+
+[*]
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+indent_size = 2
+
+[*.js]
+indent_style = space
+indent_size = 2
+
+[*.{css,less}]
+indent_style = space
+indent_size = 2
+
+[*.html]
+indent_style = space
+indent_size = 2
+
+[*.{diff,md}]
+trim_trailing_whitespace = false
+
+[*.php]
+indent_style = space
+indent_size = 4
diff --git a/stubs/extension/.eslintignore b/stubs/extension/.eslintignore
new file mode 100644
index 000000000..86b7c8854
--- /dev/null
+++ b/stubs/extension/.eslintignore
@@ -0,0 +1,5 @@
+**/bower_components/**/*
+**/node_modules/**/*
+vendor/**/*
+**/Gulpfile.js
+**/dist/**/*
diff --git a/stubs/extension/.eslintrc b/stubs/extension/.eslintrc
new file mode 100644
index 000000000..9cebc759d
--- /dev/null
+++ b/stubs/extension/.eslintrc
@@ -0,0 +1,171 @@
+{
+ "parser": "babel-eslint", // https://github.com/babel/babel-eslint
+ "env": { // http://eslint.org/docs/user-guide/configuring.html#specifying-environments
+ "browser": true // browser global variables
+ },
+ "ecmaFeatures": {
+ "arrowFunctions": true,
+ "blockBindings": true,
+ "classes": true,
+ "defaultParams": true,
+ "destructuring": true,
+ "forOf": true,
+ "generators": false,
+ "modules": true,
+ "objectLiteralComputedProperties": true,
+ "objectLiteralDuplicateProperties": false,
+ "objectLiteralShorthandMethods": true,
+ "objectLiteralShorthandProperties": true,
+ "spread": true,
+ "superInFunctions": true,
+ "templateStrings": true,
+ "jsx": true
+ },
+ "globals": {
+ "m": true,
+ "app": true,
+ "$": true,
+ "moment": true
+ },
+ "rules": {
+/**
+ * Strict mode
+ */
+ // babel inserts "use strict"; for us
+ "strict": [2, "never"], // http://eslint.org/docs/rules/strict
+
+/**
+ * ES6
+ */
+ "no-var": 2, // http://eslint.org/docs/rules/no-var
+ "prefer-const": 2, // http://eslint.org/docs/rules/prefer-const
+
+/**
+ * Variables
+ */
+ "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow
+ "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names
+ "no-unused-vars": [2, { // http://eslint.org/docs/rules/no-unused-vars
+ "vars": "local",
+ "args": "after-used"
+ }],
+ "no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define
+
+/**
+ * Possible errors
+ */
+ "comma-dangle": [2, "never"], // http://eslint.org/docs/rules/comma-dangle
+ "no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign
+ "no-console": 1, // http://eslint.org/docs/rules/no-console
+ "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger
+ "no-alert": 1, // http://eslint.org/docs/rules/no-alert
+ "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition
+ "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys
+ "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case
+ "no-empty": 2, // http://eslint.org/docs/rules/no-empty
+ "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign
+ "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast
+ "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi
+ "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign
+ "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations
+ "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp
+ "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace
+ "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls
+ "no-reserved-keys": 2, // http://eslint.org/docs/rules/no-reserved-keys
+ "no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays
+ "no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable
+ "use-isnan": 2, // http://eslint.org/docs/rules/use-isnan
+ "block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var
+
+/**
+ * Best practices
+ */
+ "consistent-return": 2, // http://eslint.org/docs/rules/consistent-return
+ "curly": [2, "multi-line"], // http://eslint.org/docs/rules/curly
+ "default-case": 2, // http://eslint.org/docs/rules/default-case
+ "dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation
+ "allowKeywords": true
+ }],
+ "eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq
+ "no-caller": 2, // http://eslint.org/docs/rules/no-caller
+ "no-else-return": 2, // http://eslint.org/docs/rules/no-else-return
+ "no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null
+ "no-eval": 2, // http://eslint.org/docs/rules/no-eval
+ "no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native
+ "no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind
+ "no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough
+ "no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal
+ "no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval
+ "no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks
+ "no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func
+ "no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str
+ "no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign
+ "no-new": 2, // http://eslint.org/docs/rules/no-new
+ "no-new-func": 2, // http://eslint.org/docs/rules/no-new-func
+ "no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers
+ "no-octal": 2, // http://eslint.org/docs/rules/no-octal
+ "no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape
+ "no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign
+ "no-proto": 2, // http://eslint.org/docs/rules/no-proto
+ "no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare
+ "no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign
+ "no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare
+ "no-sequences": 2, // http://eslint.org/docs/rules/no-sequences
+ "no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal
+ "no-with": 2, // http://eslint.org/docs/rules/no-with
+ "radix": 2, // http://eslint.org/docs/rules/radix
+ "vars-on-top": 2, // http://eslint.org/docs/rules/vars-on-top
+ "wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife
+ "yoda": 2, // http://eslint.org/docs/rules/yoda
+
+/**
+ * Style
+ */
+ "indent": [2, 2], // http://eslint.org/docs/rules/indent
+ "brace-style": [2, // http://eslint.org/docs/rules/brace-style
+ "1tbs", {
+ "allowSingleLine": true
+ }],
+ "quotes": [
+ 2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes
+ ],
+ "camelcase": [2, { // http://eslint.org/docs/rules/camelcase
+ "properties": "never"
+ }],
+ "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing
+ "before": false,
+ "after": true
+ }],
+ "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style
+ "eol-last": 2, // http://eslint.org/docs/rules/eol-last
+ "func-names": 1, // http://eslint.org/docs/rules/func-names
+ "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing
+ "beforeColon": false,
+ "afterColon": true
+ }],
+ "new-cap": [2, { // http://eslint.org/docs/rules/new-cap
+ "newIsCap": true
+ }],
+ "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines
+ "max": 2
+ }],
+ "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object
+ "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func
+ "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces
+ "no-wrap-func": 2, // http://eslint.org/docs/rules/no-wrap-func
+ "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle
+ "one-var": [2, "never"], // http://eslint.org/docs/rules/one-var
+ "padded-blocks": [2, "never"], // http://eslint.org/docs/rules/padded-blocks
+ "semi": [2, "always"], // http://eslint.org/docs/rules/semi
+ "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing
+ "before": false,
+ "after": true
+ }],
+ "space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords
+ "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks
+ "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren
+ "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops
+ "space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case
+ "spaced-line-comment": 2, // http://eslint.org/docs/rules/spaced-line-comment
+ }
+}
diff --git a/stubs/extension/bootstrap.php b/stubs/extension/bootstrap.php
index 1d29892f9..891396609 100644
--- a/stubs/extension/bootstrap.php
+++ b/stubs/extension/bootstrap.php
@@ -4,6 +4,7 @@
// classes in the src directory to be autoloaded.
require __DIR__.'/vendor/autoload.php';
-// Register our service provider with the Flarum application. In here we can
-// register bindings and execute code when the application boots.
-return $this->app->register('{{namespace}}\{{classPrefix}}ServiceProvider');
+// Return the name of our Extension class. Flarum will register it as a service
+// provider, allowing it to register bindings and execute code when the
+// application boots.
+return '{{namespace}}\Extension';
diff --git a/stubs/extension/js/bootstrap.js b/stubs/extension/js/bootstrap.js
deleted file mode 100644
index 421294ea7..000000000
--- a/stubs/extension/js/bootstrap.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { extend, override } from 'flarum/extension-utils';
-import app from 'flarum/app';
-
-app.initializers.add('{{name}}', function() {
-
- // @todo
-
-});
diff --git a/stubs/extension/js/src/main.js b/stubs/extension/js/src/main.js
new file mode 100644
index 000000000..ac168d85b
--- /dev/null
+++ b/stubs/extension/js/src/main.js
@@ -0,0 +1,4 @@
+import { extend } from 'flarum/extend';
+import app from 'flarum/app';
+
+// TODO
diff --git a/stubs/extension/locale/en.yml b/stubs/extension/locale/en.yml
index 7d28ca184..15828fbe1 100644
--- a/stubs/extension/locale/en.yml
+++ b/stubs/extension/locale/en.yml
@@ -1,2 +1,2 @@
{{name}}:
- # hello_world: Hello, world!
+ # hello_world: "Hello, world!"
diff --git a/stubs/extension/src/Extension.php b/stubs/extension/src/Extension.php
new file mode 100644
index 000000000..a64d047d1
--- /dev/null
+++ b/stubs/extension/src/Extension.php
@@ -0,0 +1,27 @@
+subscribe('{{namespace}}\Listeners\AddClientAssets');
+ }
+
+ /**
+ * Register the service provider.
+ *
+ * @return void
+ */
+ public function register()
+ {
+ //
+ }
+}
diff --git a/stubs/extension/src/Listeners/AddClientAssets.php b/stubs/extension/src/Listeners/AddClientAssets.php
new file mode 100755
index 000000000..4a3634b50
--- /dev/null
+++ b/stubs/extension/src/Listeners/AddClientAssets.php
@@ -0,0 +1,33 @@
+listen(RegisterLocales::class, __CLASS__.'@addLocale');
+ $events->listen(BuildClientView::class, __CLASS__.'@addAssets');
+ }
+
+ public function addLocale(RegisterLocales $event)
+ {
+ $event->addTranslations('en', __DIR__.'/../../locale/en.yml');
+ }
+
+ public function addAssets(BuildClientView $event)
+ {
+ $event->forumAssets([
+ __DIR__.'/../../js/dist/extension.js',
+ __DIR__.'/../../less/extension.less'
+ ]);
+
+ $event->forumBootstrapper('{{name}}/main');
+
+ $event->forumTranslations([
+ // '{{name}}.hello_world'
+ ]);
+ }
+}
diff --git a/stubs/extension/src/ServiceProvider.php b/stubs/extension/src/ServiceProvider.php
deleted file mode 100644
index dc71b1235..000000000
--- a/stubs/extension/src/ServiceProvider.php
+++ /dev/null
@@ -1,39 +0,0 @@
-extend([
- (new Extend\Locale('en'))->translations(__DIR__.'/../locale/en.yml'),
-
- (new Extend\ForumClient())
- ->assets([
- __DIR__.'/../js/dist/extension.js',
- __DIR__.'/../less/extension.less'
- ])
- ->translations([
- // Add the keys of translations you would like to be available
- // for use by the JS client application.
- ])
- ]);
- }
-
- /**
- * Register the service provider.
- *
- * @return void
- */
- public function register()
- {
- //
- }
-}
diff --git a/views/app.blade.php b/views/app.blade.php
index 57ad2af8d..5a3627f03 100644
--- a/views/app.blade.php
+++ b/views/app.blade.php
@@ -35,7 +35,11 @@
document: {!! json_encode($document) !!},
session: {!! json_encode($session) !!}
};
- initLocale(app);
+
+ @foreach ($bootstrappers as $bootstrapper)
+ System.import('{{ $bootstrapper }}');
+ @endforeach
+
app.boot();
} catch (e) {
document.write('Something went wrong. ');
|