diff --git a/app/Database/Repositories/Decorators/Forum/CachingDecorator.php b/app/Database/Repositories/Decorators/Forum/CachingDecorator.php index ff741d7f..962048fe 100644 --- a/app/Database/Repositories/Decorators/Forum/CachingDecorator.php +++ b/app/Database/Repositories/Decorators/Forum/CachingDecorator.php @@ -247,7 +247,7 @@ public function update(Forum $forum, $details) return $this->decoratedRepository->update($forum, $details); } - /** + /** * {@inheritdoc} */ public function changeParent(Forum $forum, int $newParent) @@ -256,4 +256,12 @@ public function changeParent(Forum $forum, int $newParent) $this->cache->forget('forums.index_tree'); return $this->cache->forget('forums.all'); } + + /** + * {@inheritdoc} + */ + public function onlyChildren() + { + return $this->decoratedRepository->onlyChildren(); + } } diff --git a/app/Database/Repositories/Eloquent/ForumRepository.php b/app/Database/Repositories/Eloquent/ForumRepository.php index 1e477234..6f420052 100644 --- a/app/Database/Repositories/Eloquent/ForumRepository.php +++ b/app/Database/Repositories/Eloquent/ForumRepository.php @@ -282,4 +282,12 @@ public function changeParent(Forum $forum, int $newParent) { //TODO implement function } + + /** + * {@inheritdoc} + */ + public function onlyChildren() + { + return $this->forumModel->where('parent_id', '!=', null)->get(); + } } diff --git a/app/Database/Repositories/ForumRepositoryInterface.php b/app/Database/Repositories/ForumRepositoryInterface.php index 869b5458..dababce9 100644 --- a/app/Database/Repositories/ForumRepositoryInterface.php +++ b/app/Database/Repositories/ForumRepositoryInterface.php @@ -131,4 +131,11 @@ public function update(Forum $forum, $details); * @return mixed */ public function changeParent(Forum $forum, int $newParent); + + /** + * Get only children forums + * + * @return mixed + */ + public function onlyChildren(); } diff --git a/app/Exceptions/SettingNotFoundException.php b/app/Exceptions/SettingNotFoundException.php new file mode 100644 index 00000000..b4ce1904 --- /dev/null +++ b/app/Exceptions/SettingNotFoundException.php @@ -0,0 +1,33 @@ +message); + } + + parent::__construct($message, $previous, $code); + } +} diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 2111d3fe..56155ffa 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -15,6 +15,7 @@ use Illuminate\Translation\Translator; use MyBB\Core\Database\Repositories\ProfileFieldGroupRepositoryInterface; use MyBB\Core\Database\Repositories\UserProfileFieldRepositoryInterface; +use MyBB\Settings\Repositories\SettingRepositoryInterface; use MyBB\Core\Http\Requests\Account\CropAvatarRequest; use MyBB\Core\Http\Requests\Account\UpdateAvatarRequest; use MyBB\Core\Http\Requests\Account\UpdateEmailRequest; @@ -33,14 +34,21 @@ class AccountController extends AbstractController */ private $guard; + /** + * @var SettingRepositoryInterface + */ + private $settingRepository; + /** * Create a new controller instance. * * @param Guard $guard + * @param SettingRepositoryInterface $settingRepository */ - public function __construct(Guard $guard) + public function __construct(Guard $guard, SettingRepositoryInterface $settingRepository) { $this->guard = $guard; + $this->settingRepository = $settingRepository; } /** @@ -171,7 +179,7 @@ public function postEmail(UpdateEmailRequest $request) /** * @param string $token * - * @return $this + * @return \Illuminate\Http\RedirectResponse */ public function confirmEmail($token) { @@ -464,12 +472,11 @@ public function getPreferences(Store $settings, Filesystem $files, Translator $t /** * @param UpdatePreferencesRequest $request - * @param Store $settings * @param Translator $trans * * @return \Illuminate\Http\RedirectResponse */ - public function postPreferences(UpdatePreferencesRequest $request, Store $settings, Translator $trans) + public function postPreferences(UpdatePreferencesRequest $request, Translator $trans) { $input = $request->except(['_token']); @@ -521,7 +528,8 @@ public function postPreferences(UpdatePreferencesRequest $request, Store $settin $modifiedSettings["user.{$key}"] = $value; } - $settings->set($modifiedSettings, null, true); + $user = $this->guard->user(); + $this->settingRepository->updateSettings($modifiedSettings, $user->getAuthIdentifier()); return redirect()->route('account.preferences')->withSuccess(trans('account.saved_preferences')); } @@ -536,11 +544,10 @@ public function getPrivacy() /** * @param UpdatePrivacyRequest $request - * @param Store $settings * * @return \Illuminate\Http\RedirectResponse */ - public function postPrivacy(UpdatePrivacyRequest $request, Store $settings) + public function postPrivacy(UpdatePrivacyRequest $request) { $input = $request->except(['_token']); @@ -557,7 +564,8 @@ public function postPrivacy(UpdatePrivacyRequest $request, Store $settings) $modifiedSettings["user.{$key}"] = $value; } - $settings->set($modifiedSettings, null, true); + $user = $this->guard->user(); + $this->settingRepository->updateSettings($modifiedSettings, $user->getAuthIdentifier()); return redirect()->route('account.privacy')->withSuccess(trans('account.saved_privacy')); } diff --git a/app/Http/Controllers/Admin/Settings/SettingsController.php b/app/Http/Controllers/Admin/Settings/SettingsController.php new file mode 100644 index 00000000..3594d9d7 --- /dev/null +++ b/app/Http/Controllers/Admin/Settings/SettingsController.php @@ -0,0 +1,162 @@ +settingRepository = $settingRepository; + $this->roleRepository = $roleRepository; + $this->forumRepository = $forumRepository; + } + + /** + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function listGroups() + { + $groups = $this->settingRepository->getSettingsGroups(['user'])->unique(); + + $core = []; + $extensions = []; + foreach ($groups as $group) { + if ($group['package']['original'] == 'mybb/core') { + $core[] = $group; + } else { + $extensions[] = $group; + } + } + + return view('admin.settings.groups', compact('core', 'extensions'))->withActive('settings'); + } + + /** + * @param string $group + * @param string $package + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function editGroupOfSettings(string $group, string $package = 'mybb.core') + { + // get original package name + $originalPackage = str_replace('.', '/', $package); + + $settings = $this->settingRepository->getSettingsForGroup($group, $originalPackage); + if (!count($settings) || $group == 'user') { + throw new SettingNotFoundException(); + } + + $roles = $this->roleRepository->all(); + $forums = $this->forumRepository->onlyChildren(); + + $packageName = explode('.', $package); + $packageName = $packageName[1]; + if ($packageName == 'core') { + $packageName = 'admin'; + } + + return view('admin.settings.edit', compact('settings', 'group', 'package', 'roles', 'forums', 'packageName')) + ->withActive('settings'); + } + + /** + * @param Request $request + * @param string $group + * @param string $package + * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse + */ + public function saveGroupOfSettings(Request $request, string $group, string $package = 'mybb.core') + { + $inputs = $request->get('setting'); + // restore original package name + $package = str_replace('.', '/', $package); + + $oldSettings = $this->settingRepository->getSettingsForGroup($group, $package)->keyBy('name'); + + $modifiedSettings = []; + foreach ($oldSettings as $name => $setting) { + switch ($setting['setting_type']) { + case 'number': + $value = (int)$inputs[$name]; + break; + case 'checkbox': + $value = isset($inputs[$name]); + break; + case 'switch': + $value = (bool)$inputs[$name]; + break; + case 'choose': + case 'radio': + case 'string': + $value = (string)$inputs[$name]; + break; + case 'multichoose': + $value = implode("|", $inputs[$name]); + break; + case 'roleselect': + case 'forumselect': + if ($inputs[$name] == "-1") { + // none + $value = null; + } elseif ($inputs[$name] == 0) { + // all + $value = 0; + } else { + // select + if (isset($inputs[$name . '_select'])) { + $value = implode("|", $inputs[$name . '_select']); + } else { + $value = null; + } + } + break; + default: + $value = $inputs[$name]; + break; + } + $modifiedSettings[$setting['name']] = $value; + } + + $this->settingRepository->updateSettings($modifiedSettings, false, $package); + + return redirect()->route('admin.settings')->withSuccess(trans('admin::general.success_saved')); + } +} diff --git a/app/Http/routes.php b/app/Http/routes.php index 06b2db4a..7aaa8da8 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -205,6 +205,20 @@ 'uses' => 'Admin\Forums\ForumsController@update', ]); }); + Route::group(['prefix' => 'settings'], function () { + Route::get('/', [ + 'as' => 'admin.settings', + 'uses' => 'Admin\Settings\SettingsController@listGroups', + ]); + Route::get('edit/{group}/{package?}', [ + 'as' => 'admin.settings.edit', + 'uses' => 'Admin\Settings\SettingsController@editGroupOfSettings', + ]); + Route::post('edit/{group}/{package?}', [ + 'as' => 'admin.settings.edit', + 'uses' => 'Admin\Settings\SettingsController@saveGroupOfSettings', + ]); + }); }); Route::get('captcha/{imagehash}', ['as' => 'captcha', 'uses' => 'CaptchaController@captcha', 'noOnline' => true]); diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 8e25601e..70c82c2d 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -49,6 +49,8 @@ use MyBB\Core\Database\Repositories\WarningTypesRepositoryInterface; use MyBB\Core\Likes\Database\Repositories\Eloquent\LikesRepository; use MyBB\Core\Likes\Database\Repositories\LikesRepositoryInterface; +use MyBB\Settings\Repositories\SettingRepositoryInterface; +use MyBB\Settings\Repositories\Eloquent\SettingRepository; use MyBB\Core\Permissions\PermissionChecker; use MyBB\Core\Renderers\Post\Quote\MyCode; use MyBB\Core\Renderers\Post\Quote\QuoteInterface; @@ -81,6 +83,11 @@ public function register() PostRepository::class ); + $this->app->bind( + SettingRepositoryInterface::class, + SettingRepository::class + ); + $this->app->bind( TopicRepositoryInterface::class, TopicRepository::class diff --git a/database/seeds/SettingsTableSeeder.php b/database/seeds/SettingsTableSeeder.php index f51edea8..d424d985 100644 --- a/database/seeds/SettingsTableSeeder.php +++ b/database/seeds/SettingsTableSeeder.php @@ -15,62 +15,62 @@ public function run() DB::table('settings')->delete(); DB::table('settings')->insert([ - ['name' => 'general.board_name'], - ['name' => 'general.board_desc'], - ['name' => 'general.site_name'], - ['name' => 'general.site_url'], - ['name' => 'wio.minutes'], - ['name' => 'wio.refresh'], - ['name' => 'captcha.method'], - ['name' => 'captcha.recaptcha_public_key'], - ['name' => 'captcha.recaptcha_private_key'], - ['name' => 'captcha.nocaptcha_public_key'], - ['name' => 'captcha.nocaptcha_private_key'], - ['name' => 'user.date_format'], - ['name' => 'user.time_format'], - ['name' => 'user.timezone'], - ['name' => 'user.dst'], - ['name' => 'user.follow_started_topics'], - ['name' => 'user.follow_replied_topics'], - ['name' => 'user.show_editor'], - ['name' => 'user.topics_per_page'], - ['name' => 'user.posts_per_page'], - ['name' => 'user.style'], - ['name' => 'user.language'], - ['name' => 'user.notify_on_like'], - ['name' => 'user.notify_on_quote'], - ['name' => 'user.notify_on_reply'], - ['name' => 'user.notify_on_new_post'], - ['name' => 'user.notify_on_new_comment'], - ['name' => 'user.notify_on_comment_like'], - ['name' => 'user.notify_on_my_comment_like'], - ['name' => 'user.notify_on_comment_reply'], - ['name' => 'user.notify_on_my_comment_reply'], - ['name' => 'user.notify_on_new_message'], - ['name' => 'user.notify_on_reply_message'], - ['name' => 'user.notify_on_group_request'], - ['name' => 'user.notify_on_moderation_post'], - ['name' => 'user.notify_on_report'], - ['name' => 'user.notify_on_username_change'], - ['name' => 'user.notification_mails'], - ['name' => 'user.showonline'], - ['name' => 'user.receive_messages'], - ['name' => 'user.block_blocked_messages'], - ['name' => 'user.hide_blocked_posts'], - ['name' => 'user.only_buddy_messages'], - ['name' => 'user.receive_email'], - ['name' => 'user.dob_privacy'], - ['name' => 'user.dob_visibility'], - ['name' => 'post.likes_to_show'], - ['name' => 'likes.per_page'], - ['name' => 'memberlist.sort_by'], - ['name' => 'memberlist.sort_dir'], - ['name' => 'memberlist.per_page'], - ['name' => 'conversations.enabled'], - ['name' => 'conversations.message_order'], - ['name' => 'warnings.max_points'], - ['name' => 'warnings.allow_zero'], - ['name' => 'warnings.allow_custom'], + ['name' => 'general.board_name', 'setting_type' => 'string'], + ['name' => 'general.board_desc', 'setting_type' => 'string'], + ['name' => 'general.site_name', 'setting_type' => 'string'], + ['name' => 'general.site_url', 'setting_type' => 'string'], + ['name' => 'wio.minutes', 'setting_type' => 'number'], + ['name' => 'wio.refresh', 'setting_type' => 'number'], + ['name' => 'captcha.method', 'setting_type' => 'choose', 'options' => 'captcha|recaptcha'], + ['name' => 'captcha.recaptcha_public_key', 'setting_type' => 'string'], + ['name' => 'captcha.recaptcha_private_key', 'setting_type' => 'string'], + ['name' => 'captcha.nocaptcha_public_key', 'setting_type' => 'string'], + ['name' => 'captcha.nocaptcha_private_key', 'setting_type' => 'string'], + ['name' => 'user.date_format', 'setting_type' => 'string'], + ['name' => 'user.time_format', 'setting_type' => 'number'], + ['name' => 'user.timezone', 'setting_type' => 'string'], + ['name' => 'user.dst', 'setting_type' => 'radio', 'options' => 'enable|disable|auto'], + ['name' => 'user.follow_started_topics', 'setting_type' => 'checkbox'], + ['name' => 'user.follow_replied_topics', 'setting_type' => 'checkbox'], + ['name' => 'user.show_editor', 'setting_type' => 'checkbox'], + ['name' => 'user.topics_per_page', 'setting_type' => 'number'], + ['name' => 'user.posts_per_page', 'setting_type' => 'number'], + ['name' => 'user.style', 'setting_type' => 'string'], + ['name' => 'user.language', 'setting_type' => 'string'], + ['name' => 'user.notify_on_like', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_quote', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_reply', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_new_post', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_new_comment', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_comment_like', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_my_comment_like', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_comment_reply', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_my_comment_reply', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_new_message', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_reply_message', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_group_request', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_moderation_post', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_report', 'setting_type' => 'checkbox'], + ['name' => 'user.notify_on_username_change', 'setting_type' => 'checkbox'], + ['name' => 'user.notification_mails', 'setting_type' => 'checkbox'], + ['name' => 'user.showonline', 'setting_type' => 'checkbox'], + ['name' => 'user.receive_messages', 'setting_type' => 'checkbox'], + ['name' => 'user.block_blocked_messages', 'setting_type' => 'checkbox'], + ['name' => 'user.hide_blocked_posts', 'setting_type' => 'checkbox'], + ['name' => 'user.only_buddy_messages', 'setting_type' => 'checkbox'], + ['name' => 'user.receive_email', 'setting_type' => 'checkbox'], + ['name' => 'user.dob_privacy', 'setting_type' => 'radio', 'options' => 'nothing|age|dob'], + ['name' => 'user.dob_visibility', 'setting_type' => 'radio', 'options' => 'everyone|members|following'], + ['name' => 'post.likes_to_show', 'setting_type' => 'number'], + ['name' => 'likes.per_page', 'setting_type' => 'number'], + ['name' => 'memberlist.sort_by', 'setting_type' => 'choose', 'options' => 'created_at|num_posts|num_topics|name'], + ['name' => 'memberlist.sort_dir', 'setting_type' => 'choose', 'options' => 'desc|asc'], + ['name' => 'memberlist.per_page', 'setting_type' => 'number'], + ['name' => 'conversations.enabled', 'setting_type' => 'switch'], + ['name' => 'conversations.message_order', 'setting_type' => 'choose', 'options' => 'desc|asc'], + ['name' => 'warnings.max_points', 'setting_type' => 'number'], + ['name' => 'warnings.allow_zero', 'setting_type' => 'switch'], + ['name' => 'warnings.allow_custom', 'setting_type' => 'switch'], ]); DB::table('setting_values')->insert([ diff --git a/resources/lang/admin/en/settings.php b/resources/lang/admin/en/settings.php new file mode 100644 index 00000000..72529534 --- /dev/null +++ b/resources/lang/admin/en/settings.php @@ -0,0 +1,145 @@ + 'Yes', + 'no' => 'No', + 'board_settings' => 'Board Settings', + 'extensions' => 'Extensions settings', + 'role' => [ + 'none' => 'None', + 'select' => 'Select roles', + 'all' => 'All roles', + ], + 'forum' => [ + 'none' => 'None', + 'select' => 'Select forums', + 'all' => 'All forums', + ], + + // settings + 'general' => [ + '__group' => [ + 'title' => 'General forum settings', + 'desc' => 'This section contains various settings such as your board name and url, as well as your website name and url.', + ], + 'board_desc' => [ + 'title' => 'Board description', + 'desc' => 'setting description', + ], + 'board_name' => [ + 'title' => 'Board name', + 'desc' => 'The name of your community. We recommend that it is not over 75 characters.', + ], + 'site_name' => [ + 'title' => 'Site name', + 'desc' => 'setting description', + ], + 'site_url' => [ + 'title' => 'Site url', + 'desc' => 'setting description', + ], + ], + + 'likes' => [ + '__group' => [ + 'title' => 'Like system', + 'desc' => 'Settings for likes' + ], + 'per_page' => [ + 'title' => 'Likes per page', + 'desc' => 'The number of likes to show per page' + ] + ], + + 'captcha' => [ + '__group' => [ + 'title' => 'Captcha system', + 'desc' => 'Settings for captcha' + ], + ], + + 'post' => [ + '__group' => [ + 'title' => 'Posts', + 'desc' => 'Settings for posts' + ], + ], + + 'conversations' => [ + '__group' => [ + 'title' => 'Conversations system', + 'desc' => 'Settings for user conversations' + ], + ], + + 'wio' => [ + '__group' => [ + 'title' => 'Who is online', + 'desc' => 'Various settings regarding the Who is Online functionality.', + ], + 'minutes' => [ + 'title' => 'Cut-off Time (mins)', + 'desc' => 'The number of minutes before a user is marked offline.', + ], + 'refresh' => [ + 'title' => 'Refresh Who\'s online page Time (mins)', + 'desc' => 'The number of minutes before the "Who\'s online" page refreshes. 0 for disabled.', + ], + ], + + 'memberlist' => [ + '__group' => [ + 'title' => 'Member list', + 'desc' => 'This section allows you to control various aspects of the board member listing, such as how many members to show per page, and which features to enable or disable.', + ], + 'per_page' => [ + 'title' => 'Members per page', + 'desc' => 'The number of members to show per page on the member list.', + ], + 'sort_by' => [ + 'title' => 'Default sort field', + 'desc' => 'Select the field that you want members to be sorted by default.', + '__option' => [ + 'created_at' => 'Registration date', + 'num_posts' => 'Post count', + 'num_topics' => 'Topics count', + 'name' => 'Username', + ], + ], + 'sort_dir' => [ + 'title' => 'Default sort order', + 'desc' => 'Select the order that you want members to be sorted by default. + Ascending: A-Z / beginning-end + Descending: Z-A / end-beginning', + '__option' => [ + 'asc' => 'Ascending', + 'desc' => 'Descending', + ], + ], + ], + + 'warnings' => [ + '__group' => [ + 'title' => 'Warning system', + 'desc' => 'The warning system allows forum staff to warn users for rule violations. Here you can manage the settings that control the warning system.', + ], + 'allow_custom' => [ + 'title' => 'Allow custom warning types?', + 'desc' => 'Allow a custom reason and amount of points to be specified by those with permissions to warn users.', + ], + 'allow_zero' => [ + 'title' => 'Allow warnings with 0 points?', + 'desc' => 'Allow to creating warnings with 0 warning points.', + ], + 'max_points' => [ + 'title' => 'Maximum warning points', + 'desc' => 'The maximum warning points that can be given to a user before it is considered a warning level of 100%.', + ], + ], +]; diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index 55ebb262..5244e73e 100644 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -40,5 +40,6 @@ 'warnings_content_invalid_class' => "Failed to load Warnings Content Class ':class'", 'user_not_belongs_to_content' => ':user is not author of this content', 'warning_type_not_found' => 'Warning Type not found', - 'warning_not_found' => 'Warning not found', + 'warning_not_found' => 'Warning not found', + 'setting_not_found' => 'Setting group nof found', ]; diff --git a/resources/views/admin/settings/edit.twig b/resources/views/admin/settings/edit.twig new file mode 100644 index 00000000..7a732ca1 --- /dev/null +++ b/resources/views/admin/settings/edit.twig @@ -0,0 +1,26 @@ +{% extends "layouts.admin" %} +{% block title %} {{ trans(packageName ~ '::settings.' ~ group ~ '.__group.title') }} {% endblock %} +{% block contents %} +