1
0
mirror of https://github.com/flarum/core.git synced 2025-08-13 20:04:24 +02:00

Compare commits

...

26 Commits

Author SHA1 Message Date
Toby Zerner
5bcf72dd49 Bump version 2018-11-09 21:22:11 +10:30
Toby Zerner
0536b208e1 Fix leak of private information when updating users 2018-11-09 21:21:21 +10:30
Clark Winkelmann
c6aeeeb3c1 Always apply attributes from token when registering
The change introduced in #1033 transformed any identification attribute returned from an OAuth provider to just a default value.

When the identification attribute used by the provider is the email or username, this allowed the user to supply a different email or username and still getting an already-enabled account with the credentials he entered.

Skipping attributes with an existing value makes no sense here because it's a always a fresh user and values from AbstractOAuth2Controller::getIdentification() should always be enforced.
2018-01-06 20:04:42 +10:30
Toby Zerner
ce8a5b3e0f v0.1.0-beta.7 2017-07-22 12:48:58 +09:30
Toby Zerner
5faf0fcde5 And remove unused import 2017-07-22 12:31:23 +09:30
Toby Zerner
65c0b436c0 Fix missed instance of back button tooltip 2017-07-22 12:30:55 +09:30
Toby Zerner
8d76168bd4 Oops, forgot to correct test code 2017-07-22 12:29:03 +09:30
Toby Zerner
d16f4dbefa Recompile JS 2017-07-22 12:08:17 +09:30
Toby Zerner
e3e4786391 Simplify global back button
The behaviour is not overly intuitive, and the icon wasn't helping
(hamburger icon usually means "menu"). Now the back button always goes
back to the index, no matter where you are, and there's a tooltip that
says "Back to discussion list".
2017-07-22 12:08:09 +09:30
Toby Zerner
c1c7d4c73a Only display "show language selector" toggle if there is more than one language 2017-07-22 11:47:50 +09:30
Toby Zerner
8da8c9ac7d Clean up appearance of Rename Discussion modal
Also fix infinite loading if there's a validation error.
2017-07-22 11:47:04 +09:30
Toby Zerner
fb68aa88db Use default dropdown appearance for sort dropdown 2017-07-22 11:46:16 +09:30
Toby Zerner
afc597c189 Remove fa-fw class from all icons
Often it is desirable to NOT have this class applied, and it is easier
to apply its styles if needed rather than un-apply it.
2017-07-22 11:45:42 +09:30
Toby Zerner
4f3e67714e Fix incorrect migration notes for extensions without any migrations
When running migrations for an extension without any migrations (eg.
BBCode), the migration notes for the previous extension were being
displayed, because the Migrator never had a chance to clear them.
2017-07-22 11:43:50 +09:30
Toby Zerner
54be3ad3c8 Define the default moderator group ID
This allows extensions to add default permissions for moderators,
without having to hardcode in the default moderator group ID.
2017-07-22 11:41:20 +09:30
Toby Zerner
0b00d56416 Add a new migration helper for adding default permissions 2017-07-22 11:40:06 +09:30
Toby Zerner
89d4a1e849 Remove MySQL port field from visual installer
Port can still be specified by suffixing the host with a :

closes #825
2017-07-22 11:32:07 +09:30
Daniël Klabbers
43ee7b59a4 Update Client.php (#1198)
* Update Client.php

Now forwarding exceptions from client to page in case debug mode is on. Fixes #1120.

* Update Client.php

Satisfying .. the unsatisfiable.

* Update Client.php

Satisfying again.
2017-07-19 22:14:00 +02:00
David Sevilla Martín
d052f6b639 Use dropdown for discussion list order input (#1191)
* Use dropdown menu for index select input

* Fix space before `:`
2017-07-17 13:40:35 +09:30
Toby Zerner
4b47adabcf Oops, that should be in seconds not minutes 2017-07-08 22:35:11 +09:30
Toby Zerner
93140b8fa4 Remember users forever (5 years) rather than 2 weeks 2017-07-08 22:29:26 +09:30
Toby Zerner
ade2166310 Revise Remember Me checkbox appearance
Use a generic checkbox instead of a switch — it's more familiar and accessible.

Signed-off-by: Toby Zerner <toby.zerner@gmail.com>
2017-07-08 22:25:24 +09:30
Toby Zerner
a9969119d2 Merge branch 'master' of https://github.com/flarum/core 2017-07-08 21:52:01 +09:30
Toby Zerner
94a8eaec64 Update dependencies 2017-07-08 21:50:54 +09:30
Franz Liedke
8ea13dc826 Flatten implementation of SelfDemotionGuard listener
Refs #736 and #1195.
2017-07-06 21:57:47 +02:00
David Sevilla Martín
99d42372c3 Prevent yourself from locking yourself out of admin group (#1195) 2017-07-06 21:43:01 +02:00
32 changed files with 312 additions and 182 deletions

28
js/admin/dist/app.js vendored
View File

@@ -17101,13 +17101,11 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
// and clients support, then we'll send it as a POST request with the
// intended method specified in the X-HTTP-Method-Override header.
if (options.method !== 'GET' && options.method !== 'POST') {
(function () {
var method = options.method;
extend(options, 'config', function (result, xhr) {
return xhr.setRequestHeader('X-HTTP-Method-Override', method);
});
options.method = 'POST';
})();
var method = options.method;
extend(options, 'config', function (result, xhr) {
return xhr.setRequestHeader('X-HTTP-Method-Override', method);
});
options.method = 'POST';
}
// When we deserialize JSON data, if for some reason the server has provided
@@ -18105,14 +18103,12 @@ System.register('flarum/components/BasicsPage', ['flarum/components/Page', 'flar
options: this.localeOptions,
value: this.values.default_locale(),
onchange: this.values.default_locale
}), Switch.component({
state: this.values.show_language_selector(),
onchange: this.values.show_language_selector,
children: app.translator.trans('core.admin.basics.show_language_selector_label')
})]
}) : '',
Switch.component({
state: this.values.show_language_selector(),
onchange: this.values.show_language_selector,
children: app.translator.trans('core.admin.basics.show_language_selector_label')
}),
m('br', null),
FieldSet.component({
label: app.translator.trans('core.admin.basics.home_page_heading'),
className: 'BasicsPage-homePage',
@@ -19852,10 +19848,10 @@ System.register('flarum/components/Navigation', ['flarum/Component', 'flarum/com
var previous = history.getPrevious() || {};
return LinkButton.component({
className: 'Button Navigation-back ' + (previous.title ? '' : 'Button--icon'),
className: 'Button Navigation-back Button--icon',
href: history.backUrl(),
icon: 'chevron-left',
children: previous.title,
title: previous.title,
config: function config() {},
onclick: function onclick(e) {
if (e.shiftKey || e.ctrlKey || e.metaKey || e.which === 2) return;
@@ -21498,7 +21494,7 @@ System.register('flarum/helpers/icon', [], function (_export, _context) {
function icon(name) {
var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
attrs.className = 'icon fa fa-fw fa-' + name + ' ' + (attrs.className || '');
attrs.className = 'icon fa fa-' + name + ' ' + (attrs.className || '');
return m('i', attrs);
}

View File

@@ -66,19 +66,16 @@ export default class BasicsPage extends Page {
options: this.localeOptions,
value: this.values.default_locale(),
onchange: this.values.default_locale
}),
Switch.component({
state: this.values.show_language_selector(),
onchange: this.values.show_language_selector,
children: app.translator.trans('core.admin.basics.show_language_selector_label'),
})
]
})
: ''}
{Switch.component({
state: this.values.show_language_selector(),
onchange: this.values.show_language_selector,
children: app.translator.trans('core.admin.basics.show_language_selector_label'),
})}
<br/>
{FieldSet.component({
label: app.translator.trans('core.admin.basics.home_page_heading'),
className: 'BasicsPage-homePage',

184
js/forum/dist/app.js vendored
View File

@@ -19279,13 +19279,11 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert
// and clients support, then we'll send it as a POST request with the
// intended method specified in the X-HTTP-Method-Override header.
if (options.method !== 'GET' && options.method !== 'POST') {
(function () {
var method = options.method;
extend(options, 'config', function (result, xhr) {
return xhr.setRequestHeader('X-HTTP-Method-Override', method);
});
options.method = 'POST';
})();
var method = options.method;
extend(options, 'config', function (result, xhr) {
return xhr.setRequestHeader('X-HTTP-Method-Override', method);
});
options.method = 'POST';
}
// When we deserialize JSON data, if for some reason the server has provided
@@ -21696,21 +21694,17 @@ System.register('flarum/components/DiscussionListItem', ['flarum/Component', 'fl
}, {
key: 'config',
value: function config(isInitialized) {
var _this4 = this;
if (isInitialized) return;
// If we're on a touch device, set up the discussion row to be slidable.
// This allows the user to drag the row to either side of the screen to
// reveal controls.
if ('ontouchstart' in window) {
(function () {
var slidableInstance = slidable(_this4.$().addClass('Slidable'));
var slidableInstance = slidable(this.$().addClass('Slidable'));
_this4.$('.DiscussionListItem-controls').on('hidden.bs.dropdown', function () {
return slidableInstance.reset();
});
})();
this.$('.DiscussionListItem-controls').on('hidden.bs.dropdown', function () {
return slidableInstance.reset();
});
}
}
}, {
@@ -23281,10 +23275,10 @@ System.register('flarum/components/HeaderSecondary', ['flarum/Component', 'flaru
});;
'use strict';
System.register('flarum/components/IndexPage', ['flarum/extend', 'flarum/components/Page', 'flarum/utils/ItemList', 'flarum/helpers/listItems', 'flarum/helpers/icon', 'flarum/components/DiscussionList', 'flarum/components/WelcomeHero', 'flarum/components/DiscussionComposer', 'flarum/components/LogInModal', 'flarum/components/DiscussionPage', 'flarum/components/Select', 'flarum/components/Button', 'flarum/components/LinkButton', 'flarum/components/SelectDropdown'], function (_export, _context) {
System.register('flarum/components/IndexPage', ['flarum/extend', 'flarum/components/Page', 'flarum/utils/ItemList', 'flarum/helpers/listItems', 'flarum/helpers/icon', 'flarum/components/DiscussionList', 'flarum/components/WelcomeHero', 'flarum/components/DiscussionComposer', 'flarum/components/LogInModal', 'flarum/components/DiscussionPage', 'flarum/components/Dropdown', 'flarum/components/Button', 'flarum/components/LinkButton', 'flarum/components/SelectDropdown'], function (_export, _context) {
"use strict";
var extend, Page, ItemList, listItems, icon, DiscussionList, WelcomeHero, DiscussionComposer, LogInModal, DiscussionPage, Select, Button, LinkButton, SelectDropdown, IndexPage;
var extend, Page, ItemList, listItems, icon, DiscussionList, WelcomeHero, DiscussionComposer, LogInModal, DiscussionPage, Dropdown, Button, LinkButton, SelectDropdown, IndexPage;
return {
setters: [function (_flarumExtend) {
extend = _flarumExtend.extend;
@@ -23306,8 +23300,8 @@ System.register('flarum/components/IndexPage', ['flarum/extend', 'flarum/compone
LogInModal = _flarumComponentsLogInModal.default;
}, function (_flarumComponentsDiscussionPage) {
DiscussionPage = _flarumComponentsDiscussionPage.default;
}, function (_flarumComponentsSelect) {
Select = _flarumComponentsSelect.default;
}, function (_flarumComponentsDropdown) {
Dropdown = _flarumComponentsDropdown.default;
}, function (_flarumComponentsButton) {
Button = _flarumComponentsButton.default;
}, function (_flarumComponentsLinkButton) {
@@ -23363,7 +23357,7 @@ System.register('flarum/components/IndexPage', ['flarum/extend', 'flarum/compone
app.cache.discussionList = new DiscussionList({ params: params });
}
app.history.push('index', icon('bars'));
app.history.push('index', app.translator.trans('core.forum.header.back_to_index_tooltip'));
this.bodyClass = 'App--index';
}
@@ -23510,6 +23504,8 @@ System.register('flarum/components/IndexPage', ['flarum/extend', 'flarum/compone
}, {
key: 'viewItems',
value: function viewItems() {
var _this2 = this;
var items = new ItemList();
var sortMap = app.cache.discussionList.sortMap();
@@ -23518,10 +23514,22 @@ System.register('flarum/components/IndexPage', ['flarum/extend', 'flarum/compone
sortOptions[i] = app.translator.trans('core.forum.index_sort.' + i + '_button');
}
items.add('sort', Select.component({
options: sortOptions,
value: this.params().sort || Object.keys(sortMap)[0],
onchange: this.changeSort.bind(this)
items.add('sort', Dropdown.component({
buttonClassName: 'Button',
label: sortOptions[this.params().sort] || Object.keys(sortMap).map(function (key) {
return sortOptions[key];
})[0],
children: Object.keys(sortOptions).map(function (value) {
var label = sortOptions[value];
var active = (_this2.params().sort || Object.keys(sortMap)[0]) === value;
return Button.component({
children: label,
icon: active ? 'check' : true,
onclick: _this2.changeSort.bind(_this2, value),
active: active
});
})
}));
return items;
@@ -23875,10 +23883,10 @@ System.register('flarum/components/LogInButtons', ['flarum/Component', 'flarum/u
});;
'use strict';
System.register('flarum/components/LogInModal', ['flarum/components/Modal', 'flarum/components/ForgotPasswordModal', 'flarum/components/SignUpModal', 'flarum/components/Alert', 'flarum/components/Button', 'flarum/components/LogInButtons', 'flarum/components/Switch', 'flarum/utils/extractText'], function (_export, _context) {
System.register('flarum/components/LogInModal', ['flarum/components/Modal', 'flarum/components/ForgotPasswordModal', 'flarum/components/SignUpModal', 'flarum/components/Alert', 'flarum/components/Button', 'flarum/components/LogInButtons', 'flarum/utils/extractText'], function (_export, _context) {
"use strict";
var Modal, ForgotPasswordModal, SignUpModal, Alert, Button, LogInButtons, Switch, extractText, LogInModal;
var Modal, ForgotPasswordModal, SignUpModal, Alert, Button, LogInButtons, extractText, LogInModal;
return {
setters: [function (_flarumComponentsModal) {
Modal = _flarumComponentsModal.default;
@@ -23892,8 +23900,6 @@ System.register('flarum/components/LogInModal', ['flarum/components/Modal', 'fla
Button = _flarumComponentsButton.default;
}, function (_flarumComponentsLogInButtons) {
LogInButtons = _flarumComponentsLogInButtons.default;
}, function (_flarumComponentsSwitch) {
Switch = _flarumComponentsSwitch.default;
}, function (_flarumUtilsExtractText) {
extractText = _flarumUtilsExtractText.default;
}],
@@ -23930,7 +23936,7 @@ System.register('flarum/components/LogInModal', ['flarum/components/Modal', 'fla
*
* @type {Function}
*/
this.remember = m.prop(this.props.remember && true);
this.remember = m.prop(!!this.props.remember);
}
}, {
key: 'className',
@@ -23969,12 +23975,16 @@ System.register('flarum/components/LogInModal', ['flarum/components/Modal', 'fla
m(
'div',
{ className: 'Form-group' },
Switch.component({
children: app.translator.trans('core.forum.log_in.remember_me_label'),
disabled: this.loading,
onchange: this.remember,
state: this.remember()
})
m(
'div',
null,
m(
'label',
{ className: 'checkbox' },
m('input', { type: 'checkbox', bidi: this.remember, disabled: this.loading }),
app.translator.trans('core.forum.log_in.remember_me_label')
)
)
),
m(
'div',
@@ -24362,10 +24372,10 @@ System.register('flarum/components/Navigation', ['flarum/Component', 'flarum/com
var previous = history.getPrevious() || {};
return LinkButton.component({
className: 'Button Navigation-back ' + (previous.title ? '' : 'Button--icon'),
className: 'Button Navigation-back Button--icon',
href: history.backUrl(),
icon: 'chevron-left',
children: previous.title,
title: previous.title,
config: function config() {},
onclick: function onclick(e) {
if (e.shiftKey || e.ctrlKey || e.metaKey || e.which === 2) return;
@@ -24756,33 +24766,31 @@ System.register('flarum/components/NotificationList', ['flarum/Component', 'flar
var groups = [];
if (app.cache.notifications) {
(function () {
var discussions = {};
var discussions = {};
// Build an array of discussions which the notifications are related to,
// and add the notifications as children.
app.cache.notifications.forEach(function (notification) {
var subject = notification.subject();
// Build an array of discussions which the notifications are related to,
// and add the notifications as children.
app.cache.notifications.forEach(function (notification) {
var subject = notification.subject();
if (typeof subject === 'undefined') return;
if (typeof subject === 'undefined') return;
// Get the discussion that this notification is related to. If it's not
// directly related to a discussion, it may be related to a post or
// other entity which is related to a discussion.
var discussion = false;
if (subject instanceof Discussion) discussion = subject;else if (subject && subject.discussion) discussion = subject.discussion();
// Get the discussion that this notification is related to. If it's not
// directly related to a discussion, it may be related to a post or
// other entity which is related to a discussion.
var discussion = false;
if (subject instanceof Discussion) discussion = subject;else if (subject && subject.discussion) discussion = subject.discussion();
// If the notification is not related to a discussion directly or
// indirectly, then we will assign it to a neutral group.
var key = discussion ? discussion.id() : 0;
discussions[key] = discussions[key] || { discussion: discussion, notifications: [] };
discussions[key].notifications.push(notification);
// If the notification is not related to a discussion directly or
// indirectly, then we will assign it to a neutral group.
var key = discussion ? discussion.id() : 0;
discussions[key] = discussions[key] || { discussion: discussion, notifications: [] };
discussions[key].notifications.push(notification);
if (groups.indexOf(discussions[key]) === -1) {
groups.push(discussions[key]);
}
});
})();
if (groups.indexOf(discussions[key]) === -1) {
groups.push(discussions[key]);
}
});
}
return m(
@@ -26864,17 +26872,17 @@ System.register('flarum/components/RenameDiscussionModal', ['flarum/components/M
{ className: 'Modal-body' },
m(
'div',
{ className: 'Form' },
{ className: 'Form Form--centered' },
m(
'div',
{ className: 'Form-group' },
m('input', { className: 'FormControl title', placeholder: this.currentTitle, bidi: this.newTitle })
m('input', { className: 'FormControl', bidi: this.newTitle, type: 'text' })
),
m(
'div',
{ className: 'Form-group' },
Button.component({
className: 'Button Button--primary',
className: 'Button Button--primary Button--block',
type: 'submit',
loading: this.loading,
children: app.translator.trans('core.forum.rename_discussion.submit_button')
@@ -26905,6 +26913,9 @@ System.register('flarum/components/RenameDiscussionModal', ['flarum/components/M
}
m.redraw();
_this2.hide();
}).catch(function () {
_this2.loading = false;
m.redraw();
});
} else {
this.hide();
@@ -27027,25 +27038,23 @@ System.register('flarum/components/ReplyComposer', ['flarum/components/ComposerB
if (app.viewingDiscussion(discussion)) {
app.current.stream.update();
} else {
(function () {
// Otherwise, we'll create an alert message to inform the user that
// their reply has been posted, containing a button which will
// transition to their new post when clicked.
var alert = void 0;
var viewButton = Button.component({
className: 'Button Button--link',
children: app.translator.trans('core.forum.composer_reply.view_button'),
onclick: function onclick() {
m.route(app.route.post(post));
app.alerts.dismiss(alert);
}
});
app.alerts.show(alert = new Alert({
type: 'success',
message: app.translator.trans('core.forum.composer_reply.posted_message'),
controls: [viewButton]
}));
})();
// Otherwise, we'll create an alert message to inform the user that
// their reply has been posted, containing a button which will
// transition to their new post when clicked.
var alert = void 0;
var viewButton = Button.component({
className: 'Button Button--link',
children: app.translator.trans('core.forum.composer_reply.view_button'),
onclick: function onclick() {
m.route(app.route.post(post));
app.alerts.dismiss(alert);
}
});
app.alerts.show(alert = new Alert({
type: 'success',
message: app.translator.trans('core.forum.composer_reply.posted_message'),
controls: [viewButton]
}));
}
app.composer.hide();
@@ -28781,8 +28790,6 @@ System.register('flarum/components/UserPage', ['flarum/components/Page', 'flarum
*/
this.user = null;
app.history.push('user');
this.bodyClass = 'App--user';
}
}, {
@@ -28824,7 +28831,6 @@ System.register('flarum/components/UserPage', ['flarum/components/Page', 'flarum
value: function show(user) {
this.user = user;
app.history.push('user', user.username());
app.setTitle(user.username());
m.redraw();
@@ -29411,7 +29417,7 @@ System.register('flarum/helpers/icon', [], function (_export, _context) {
function icon(name) {
var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
attrs.className = 'icon fa fa-fw fa-' + name + ' ' + (attrs.className || '');
attrs.className = 'icon fa fa-' + name + ' ' + (attrs.className || '');
return m('i', attrs);
}
@@ -29656,10 +29662,10 @@ System.register('flarum/initializers/alertEmailConfirmation', ['flarum/component
});;
'use strict';
System.register('flarum/initializers/boot', ['flarum/utils/ScrollListener', 'flarum/utils/Pane', 'flarum/utils/Drawer', 'flarum/utils/mapRoutes', 'flarum/helpers/icon', 'flarum/components/Navigation', 'flarum/components/HeaderPrimary', 'flarum/components/HeaderSecondary', 'flarum/components/Composer', 'flarum/components/ModalManager', 'flarum/components/AlertManager'], function (_export, _context) {
System.register('flarum/initializers/boot', ['flarum/utils/ScrollListener', 'flarum/utils/Pane', 'flarum/utils/Drawer', 'flarum/utils/mapRoutes', 'flarum/components/Navigation', 'flarum/components/HeaderPrimary', 'flarum/components/HeaderSecondary', 'flarum/components/Composer', 'flarum/components/ModalManager', 'flarum/components/AlertManager'], function (_export, _context) {
"use strict";
var ScrollListener, Pane, Drawer, mapRoutes, icon, Navigation, HeaderPrimary, HeaderSecondary, Composer, ModalManager, AlertManager;
var ScrollListener, Pane, Drawer, mapRoutes, Navigation, HeaderPrimary, HeaderSecondary, Composer, ModalManager, AlertManager;
function boot(app) {
// Get the configured default route and update that route's path to be '/'.
// Push the homepage as the first route, so that the user will always be
@@ -29673,7 +29679,7 @@ System.register('flarum/initializers/boot', ['flarum/utils/ScrollListener', 'fla
}
app.routes[defaultAction].path = '/';
app.history.push(defaultAction, icon('bars'), '/');
app.history.push(defaultAction, app.translator.trans('core.forum.header.back_to_index_tooltip'), '/');
m.startComputation();
@@ -29737,8 +29743,6 @@ System.register('flarum/initializers/boot', ['flarum/utils/ScrollListener', 'fla
Drawer = _flarumUtilsDrawer.default;
}, function (_flarumUtilsMapRoutes) {
mapRoutes = _flarumUtilsMapRoutes.default;
}, function (_flarumHelpersIcon) {
icon = _flarumHelpersIcon.default;
}, function (_flarumComponentsNavigation) {
Navigation = _flarumComponentsNavigation.default;
}, function (_flarumComponentsHeaderPrimary) {

View File

@@ -8,7 +8,7 @@ import WelcomeHero from 'flarum/components/WelcomeHero';
import DiscussionComposer from 'flarum/components/DiscussionComposer';
import LogInModal from 'flarum/components/LogInModal';
import DiscussionPage from 'flarum/components/DiscussionPage';
import Select from 'flarum/components/Select';
import Dropdown from 'flarum/components/Dropdown';
import Button from 'flarum/components/Button';
import LinkButton from 'flarum/components/LinkButton';
import SelectDropdown from 'flarum/components/SelectDropdown';
@@ -55,7 +55,7 @@ export default class IndexPage extends Page {
app.cache.discussionList = new DiscussionList({params});
}
app.history.push('index', icon('bars'));
app.history.push('index', app.translator.trans('core.forum.header.back_to_index_tooltip'));
this.bodyClass = 'App--index';
}
@@ -212,10 +212,20 @@ export default class IndexPage extends Page {
}
items.add('sort',
Select.component({
options: sortOptions,
value: this.params().sort || Object.keys(sortMap)[0],
onchange: this.changeSort.bind(this)
Dropdown.component({
buttonClassName: 'Button',
label: sortOptions[this.params().sort] || Object.keys(sortMap).map(key => sortOptions[key])[0],
children: Object.keys(sortOptions).map(value => {
const label = sortOptions[value];
const active = (this.params().sort || Object.keys(sortMap)[0]) === value;
return Button.component({
children: label,
icon: active ? 'check' : true,
onclick: this.changeSort.bind(this, value),
active: active,
})
}),
})
);

View File

@@ -4,7 +4,6 @@ import SignUpModal from 'flarum/components/SignUpModal';
import Alert from 'flarum/components/Alert';
import Button from 'flarum/components/Button';
import LogInButtons from 'flarum/components/LogInButtons';
import Switch from 'flarum/components/Switch';
import extractText from 'flarum/utils/extractText';
/**
@@ -38,7 +37,7 @@ export default class LogInModal extends Modal {
*
* @type {Function}
*/
this.remember = m.prop(this.props.remember && true);
this.remember = m.prop(!!this.props.remember);
}
className() {
@@ -66,14 +65,14 @@ export default class LogInModal extends Modal {
bidi={this.password}
disabled={this.loading} />
</div>
<div className="Form-group">
{Switch.component({
children: app.translator.trans('core.forum.log_in.remember_me_label'),
disabled: this.loading,
onchange: this.remember,
state: this.remember()
})}
<div>
<label className="checkbox">
<input type="checkbox" bidi={this.remember} disabled={this.loading} />
{app.translator.trans('core.forum.log_in.remember_me_label')}
</label>
</div>
</div>
<div className="Form-group">

View File

@@ -24,13 +24,13 @@ export default class RenameDiscussionModal extends Modal {
content() {
return (
<div className="Modal-body">
<div className="Form">
<div className="Form Form--centered">
<div className="Form-group">
<input className="FormControl title" placeholder={this.currentTitle} bidi={this.newTitle} />
<input className="FormControl" bidi={this.newTitle} type="text" />
</div>
<div className="Form-group">
{Button.component({
className: 'Button Button--primary',
className: 'Button Button--primary Button--block',
type: 'submit',
loading: this.loading,
children: app.translator.trans('core.forum.rename_discussion.submit_button')
@@ -59,6 +59,9 @@ export default class RenameDiscussionModal extends Modal {
}
m.redraw();
this.hide();
}).catch(() => {
this.loading = false;
m.redraw();
});
} else {
this.hide();

View File

@@ -26,8 +26,6 @@ export default class UserPage extends Page {
*/
this.user = null;
app.history.push('user');
this.bodyClass = 'App--user';
}
@@ -74,7 +72,6 @@ export default class UserPage extends Page {
show(user) {
this.user = user;
app.history.push('user', user.username());
app.setTitle(user.username());
m.redraw();

View File

@@ -4,7 +4,6 @@ import ScrollListener from 'flarum/utils/ScrollListener';
import Pane from 'flarum/utils/Pane';
import Drawer from 'flarum/utils/Drawer';
import mapRoutes from 'flarum/utils/mapRoutes';
import icon from 'flarum/helpers/icon';
import Navigation from 'flarum/components/Navigation';
import HeaderPrimary from 'flarum/components/HeaderPrimary';
import HeaderSecondary from 'flarum/components/HeaderSecondary';
@@ -31,7 +30,7 @@ export default function boot(app) {
}
app.routes[defaultAction].path = '/';
app.history.push(defaultAction, icon('bars'), '/');
app.history.push(defaultAction, app.translator.trans('core.forum.header.back_to_index_tooltip'), '/');
m.startComputation();

View File

@@ -50,10 +50,10 @@ export default class Navigation extends Component {
const previous = history.getPrevious() || {};
return LinkButton.component({
className: 'Button Navigation-back ' + (previous.title ? '' : 'Button--icon'),
className: 'Button Navigation-back Button--icon',
href: history.backUrl(),
icon: 'chevron-left',
children: previous.title,
title: previous.title,
config: () => {},
onclick: e => {
if (e.shiftKey || e.ctrlKey || e.metaKey || e.which === 2) return;

View File

@@ -6,7 +6,7 @@
* @return {Object}
*/
export default function icon(name, attrs = {}) {
attrs.className = 'icon fa fa-fw fa-' + name + ' ' + (attrs.className || '');
attrs.className = 'icon fa fa-' + name + ' ' + (attrs.className || '');
return <i {...attrs}/>;
}

View File

@@ -9,7 +9,7 @@
}
fieldset {
margin-bottom: 30px;
margin-bottom: 20px;
> ul {
list-style: none;

View File

@@ -61,6 +61,7 @@
}
.icon {
font-size: 14px;
margin-right: 3px;
}
}
}

View File

@@ -31,6 +31,7 @@
.icon {
font-size: 14px;
margin-right: 2px;
.fa-fw();
}
}
.NotificationGrid-checkbox {

View File

@@ -224,14 +224,14 @@
}
}
.Button-icon {
margin-right: 3px;
margin-right: 7px;
}
.Button-icon,
.Button-caret {
font-size: 14px;
}
.Button-caret {
margin-left: 3px;
margin-left: 7px;
}
.Button-badge {
font-size: 12px;

View File

@@ -49,6 +49,7 @@
float: left;
margin-left: -25px;
margin-top: 2px;
.fa-fw();
}
&.disabled {

View File

@@ -16,4 +16,5 @@
margin-left: -30px;
pointer-events: none;
color: @control-color;
.fa-fw();
}

View File

@@ -83,6 +83,10 @@ fieldset {
padding: 0;
margin: 0;
border: 0;
> ul > li {
margin-bottom: 10px;
}
}
legend {
font-size: 14px;

View File

@@ -13,30 +13,29 @@ namespace Flarum\Api;
use Exception;
use Flarum\Core\User;
use Flarum\Foundation\Application;
use Flarum\Http\Controller\ControllerInterface;
use Illuminate\Contracts\Container\Container;
use InvalidArgumentException;
use Zend\Diactoros\ServerRequestFactory;
class Client
{
/**
* @var Container
*/
protected $container;
/**
* @var ErrorHandler
*/
protected $errorHandler;
/**
* @var Application
*/
private $app;
/**
* @param Container $container
* @param Application $app
* @param ErrorHandler $errorHandler
*/
public function __construct(Container $container, ErrorHandler $errorHandler)
public function __construct(Application $app, ErrorHandler $errorHandler)
{
$this->container = $container;
$this->app = $app;
$this->errorHandler = $errorHandler;
}
@@ -48,6 +47,7 @@ class Client
* @param array $queryParams
* @param array $body
* @return \Psr\Http\Message\ResponseInterface
* @throws Exception
*/
public function send($controller, $actor, array $queryParams = [], array $body = [])
{
@@ -56,7 +56,7 @@ class Client
$request = $request->withAttribute('actor', $actor);
if (is_string($controller)) {
$controller = $this->container->make($controller);
$controller = $this->app->make($controller);
}
if (! ($controller instanceof ControllerInterface)) {
@@ -68,6 +68,10 @@ class Client
try {
return $controller->handle($request);
} catch (Exception $e) {
if ($this->app->inDebugMode()) {
throw $e;
}
return $this->errorHandler->handle($e);
}
}

View File

@@ -11,6 +11,8 @@
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Api\Serializer\UserSerializer;
use Flarum\Core\Command\EditUser;
use Flarum\Core\Exception\PermissionDeniedException;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -22,7 +24,7 @@ class UpdateUserController extends AbstractResourceController
/**
* {@inheritdoc}
*/
public $serializer = 'Flarum\Api\Serializer\CurrentUserSerializer';
public $serializer = UserSerializer::class;
/**
* {@inheritdoc}
@@ -51,6 +53,10 @@ class UpdateUserController extends AbstractResourceController
$actor = $request->getAttribute('actor');
$data = array_get($request->getParsedBody(), 'data', []);
if ($actor->id == $id) {
$this->serializer = CurrentUserSerializer::class;
}
// Require the user's current password if they are attempting to change
// their own email address.
if (isset($data['attributes']['email']) && $actor->id == $id) {

View File

@@ -116,9 +116,7 @@ class RegisterUserHandler
// from the get-go.
if (isset($token)) {
foreach ($token->payload as $k => $v) {
if (in_array($user->$k, ['', null], true)) {
$user->$k = $v;
}
$user->$k = $v;
}
if (isset($token->payload['email'])) {

View File

@@ -104,6 +104,7 @@ class CoreServiceProvider extends AbstractServiceProvider
$events = $this->app->make('events');
$events->subscribe('Flarum\Core\Listener\SelfDemotionGuard');
$events->subscribe('Flarum\Core\Listener\DiscussionMetadataUpdater');
$events->subscribe('Flarum\Core\Listener\UserMetadataUpdater');
$events->subscribe('Flarum\Core\Listener\ExtensionValidator');

View File

@@ -52,6 +52,11 @@ class Group extends AbstractModel
*/
const MEMBER_ID = 3;
/**
* The ID of the mod group.
*/
const MODERATOR_ID = 4;
/**
* Boot the model.
*

View File

@@ -0,0 +1,67 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Core\Listener;
use Flarum\Core\Exception\PermissionDeniedException;
use Flarum\Core\Group;
use Flarum\Event\UserWillBeSaved;
use Illuminate\Contracts\Events\Dispatcher;
class SelfDemotionGuard
{
/**
* @param Dispatcher $events
*/
public function subscribe(Dispatcher $events)
{
$events->listen(UserWillBeSaved::class, [$this, 'whenUserWillBeSaved']);
}
/**
* Prevent an admin from removing their admin permission via the API.
* @param UserWillBeSaved $event
* @throws PermissionDeniedException
*/
public function whenUserWillBeSaved(UserWillBeSaved $event)
{
// Non-admin users pose no problem
if (! $event->actor->isAdmin()) {
return;
}
// Only admins can demote users, which means demoting other users is
// fine, because we still have at least one admin (the actor) left
if ($event->actor->id !== $event->user->id) {
return;
}
$groups = array_get($event->data, 'relationships.groups.data');
// If there is no group data (not even an empty array), this means
// groups were not changed (and thus not removed) - we're fine!
if (! isset($groups)) {
return;
}
$adminGroups = array_filter($groups, function ($group) {
return $group['id'] == Group::ADMINISTRATOR_ID;
});
// As long as the user is still part of the admin group, all is good
if ($adminGroups) {
return;
}
// If we get to this point, we have to prohibit the edit
throw new PermissionDeniedException;
}
}

View File

@@ -12,6 +12,7 @@
namespace Flarum\Database;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Schema\Builder;
@@ -96,7 +97,7 @@ abstract class Migration
/**
* Add default values for config values.
*/
public static function addSettings($defaults)
public static function addSettings(array $defaults)
{
return [
'up' => function (SettingsRepositoryInterface $settings) use ($defaults) {
@@ -111,4 +112,39 @@ abstract class Migration
}
];
}
/**
* Add default permissions.
*/
public static function addPermissions(array $permissions)
{
$keys = [];
foreach ($permissions as $permission => $groups) {
foreach ((array) $groups as $group) {
$keys[] = [
'group_id' => $group,
'permission' => $permission,
];
}
}
return [
'up' => function (ConnectionInterface $db) use ($keys) {
foreach ($keys as $key) {
$instance = $db->table('permissions')->where($key)->first();
if (is_null($instance)) {
$db->table('permissions')->insert($key);
}
}
},
'down' => function (ConnectionInterface $db) use ($keys) {
foreach ($keys as $key) {
$db->table('permissions')->where($key)->delete();
}
}
];
}
}

View File

@@ -219,6 +219,7 @@ class ExtensionManager
*
* @param Extension $extension
* @param bool|true $up
* @return array Notes from the migrator.
*/
public function migrate(Extension $extension, $up = true)
{
@@ -234,7 +235,11 @@ class ExtensionManager
} else {
$this->migrator->reset($migrationDir, $extension);
}
return $this->migrator->getNotes();
}
return [];
}
/**

View File

@@ -25,7 +25,7 @@ class Application extends Container implements ApplicationContract
*
* @var string
*/
const VERSION = '0.1.0-beta.6';
const VERSION = '0.1.0-beta.7.2';
/**
* The base path for the Flarum installation.

View File

@@ -37,9 +37,7 @@ class Rememberer
$lifetime = null;
if (! $session) {
$lifetime = 60 * 60 * 24 * 14;
$token->lifetime = $lifetime;
$token->lifetime = $lifetime = 5 * 365 * 24 * 60 * 60; // 5 years
$token->save();
}

View File

@@ -25,8 +25,6 @@ use Symfony\Component\Console\Input\InputOption;
class InstallCommand extends AbstractCommand
{
const MOD_GROUP_ID = 4;
/**
* @var DataProviderInterface
*/
@@ -271,7 +269,7 @@ class InstallCommand extends AbstractCommand
[Group::ADMINISTRATOR_ID, 'Admin', 'Admins', '#B72A2A', 'wrench'],
[Group::GUEST_ID, 'Guest', 'Guests', null, null],
[Group::MEMBER_ID, 'Member', 'Members', null, null],
[static::MOD_GROUP_ID, 'Mod', 'Mods', '#80349E', 'bolt']
[Group::MODERATOR_ID, 'Mod', 'Mods', '#80349E', 'bolt']
];
foreach ($groups as $group) {
@@ -297,10 +295,10 @@ class InstallCommand extends AbstractCommand
[Group::MEMBER_ID, 'viewUserList'],
// Moderators can edit + delete stuff
[static::MOD_GROUP_ID, 'discussion.delete'],
[static::MOD_GROUP_ID, 'discussion.deletePosts'],
[static::MOD_GROUP_ID, 'discussion.editPosts'],
[static::MOD_GROUP_ID, 'discussion.rename'],
[Group::MODERATOR_ID, 'discussion.hide'],
[Group::MODERATOR_ID, 'discussion.editPosts'],
[Group::MODERATOR_ID, 'discussion.rename'],
[Group::MODERATOR_ID, 'discussion.viewIpsPosts'],
];
foreach ($permissions as &$permission) {

View File

@@ -36,11 +36,10 @@ class UserDataProvider implements DataProviderInterface
public function getDatabaseConfiguration()
{
$host = $this->ask('Database host:');
$port = '3306';
if (str_contains($host, ':')) {
list($host, $port) = explode(':', $host, 2);
} else {
$port = $this->ask('Database port:');
}
return [

View File

@@ -52,14 +52,21 @@ class InstallController implements ControllerInterface
$data = new DefaultsDataProvider;
$host = array_get($input, 'mysqlHost');
$port = '3306';
if (str_contains($host, ':')) {
list($host, $port) = explode(':', $host, 2);
}
$data->setDatabaseConfiguration([
'driver' => 'mysql',
'host' => array_get($input, 'mysqlHost'),
'host' => $host,
'database' => array_get($input, 'mysqlDatabase'),
'username' => array_get($input, 'mysqlUsername'),
'password' => array_get($input, 'mysqlPassword'),
'prefix' => array_get($input, 'tablePrefix'),
'port' => array_get($input, 'mysqlPort'),
'port' => $port,
]);
$data->setAdminUser([

View File

@@ -69,8 +69,6 @@ class MigrateCommand extends AbstractCommand
$extensions = $this->container->make('Flarum\Extension\ExtensionManager');
$migrator = $extensions->getMigrator();
foreach ($extensions->getExtensions() as $name => $extension) {
if (! $extension->isEnabled()) {
continue;
@@ -78,9 +76,9 @@ class MigrateCommand extends AbstractCommand
$this->info('Migrating extension: '.$name);
$extensions->migrate($extension);
$notes = $extensions->migrate($extension);
foreach ($migrator->getNotes() as $note) {
foreach ($notes as $note) {
$this->info($note);
}
}

View File

@@ -33,11 +33,6 @@
<input type="password" name="mysqlPassword">
</div>
<div class="FormField">
<label>MySQL Port</label>
<input type="number" name="mysqlPort">
</div>
<div class="FormField">
<label>Table Prefix</label>
<input type="text" name="tablePrefix">