diff --git a/public_html/index.html b/public_html/index.html index 0eff7b27..840a7858 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -34,6 +34,7 @@ + diff --git a/public_html/js/BrowsingSettings.js b/public_html/js/BrowsingSettings.js new file mode 100644 index 00000000..2c4a8fea --- /dev/null +++ b/public_html/js/BrowsingSettings.js @@ -0,0 +1,86 @@ +var App = App || {}; + +App.BrowsingSettings = function( + promise, + auth, + api) { + + var settings = getDefaultSettings(); + + auth.startObservingLoginChanges('top-navigation', loginStateChanged); + + readFromLocalStorage(); + if (auth.isLoggedIn()) + loginStateChanged(); + + function setSettings(newSettings) { + settings = newSettings; + return save(); + } + + function getSettings() { + return settings; + } + + function getDefaultSettings() { + return { + hideDownvoted: true, + endlessScroll: true, + listPosts: { + safe: true, + sketchy: true, + unsafe: true, + }, + }; + } + + function loginStateChanged() { + readFromUser(auth.getCurrentUser()); + } + + function readFromLocalStorage() { + readFromString(localStorage.getItem('browsingSettings')); + } + + function readFromUser(user) { + readFromString(user.browsingSettings); + } + + function readFromString(string) { + if (!string) + return; + try { + settings = JSON.parse(string); + } catch (e) { + } + } + + function saveToLocalStorage() { + localStorage.setItem('browsingSettings', JSON.stringify(settings)); + } + + function saveToUser(user) { + var formData = { + browsingSettings: JSON.stringify(settings), + }; + return api.put('/users/' + user.name, formData); + } + + function save() { + return promise.make(function(resolve, reject) { + saveToLocalStorage(); + if (auth.isLoggedIn()) { + saveToUser(auth.getCurrentUser()).then(resolve).fail(reject); + } else { + resolve(); + } + }); + } + + return { + getSettings: getSettings, + setSettings: setSettings, + }; +} + +App.DI.registerSingleton('browsingSettings', App.BrowsingSettings); diff --git a/public_html/js/Presenters/UserBrowsingSettingsPresenter.js b/public_html/js/Presenters/UserBrowsingSettingsPresenter.js index d4907d15..e366af28 100644 --- a/public_html/js/Presenters/UserBrowsingSettingsPresenter.js +++ b/public_html/js/Presenters/UserBrowsingSettingsPresenter.js @@ -5,7 +5,9 @@ App.Presenters.UserBrowsingSettingsPresenter = function( jQuery, util, promise, - auth) { + auth, + browsingSettings, + messagePresenter) { var target; var template; @@ -29,7 +31,27 @@ App.Presenters.UserBrowsingSettingsPresenter = function( function render() { var $el = jQuery(target); - $el.html(template({user: user})); + $el.html(template({user: user, settings: browsingSettings.getSettings()})); + $el.find('form').submit(browsingSettingsFormSubmitted); + } + + function browsingSettingsFormSubmitted(e) { + e.preventDefault(); + var $el = jQuery(target); + var $messages = $el.find('.messages'); + messagePresenter.hideMessages($messages); + var newSettings = { + endlessScroll: $el.find('[name=endless-scroll]:visible').prop('checked'), + hideDownvoted: $el.find('[name=hide-downvoted]:visible').prop('checked'), + listPosts: { + safe: $el.find('[name=listSafePosts]:visible').prop('checked'), + sketchy: $el.find('[name=listSketchyPosts]:visible').prop('checked'), + unsafe: $el.find('[name=listUnsafePosts]:visible').prop('checked'), + }, + }; + browsingSettings.setSettings(newSettings).then(function() { + messagePresenter.showInfo($messages, 'Browsing settings updated!'); + }); } function getPrivileges() { diff --git a/public_html/templates/account-removal.tpl b/public_html/templates/account-removal.tpl index 3daef798..076355b1 100644 --- a/public_html/templates/account-removal.tpl +++ b/public_html/templates/account-removal.tpl @@ -4,9 +4,8 @@
-
diff --git a/public_html/templates/browsing-settings.tpl b/public_html/templates/browsing-settings.tpl index cfbe04f8..2299e1f2 100644 --- a/public_html/templates/browsing-settings.tpl +++ b/public_html/templates/browsing-settings.tpl @@ -4,43 +4,38 @@
- - -
- +
- -
- +
- -
diff --git a/public_html/templates/login-form.tpl b/public_html/templates/login-form.tpl index a2f35b0d..2f4ae247 100644 --- a/public_html/templates/login-form.tpl +++ b/public_html/templates/login-form.tpl @@ -26,9 +26,8 @@
  -
diff --git a/src/Controllers/UserController.php b/src/Controllers/UserController.php index 609c387d..89cd1e18 100644 --- a/src/Controllers/UserController.php +++ b/src/Controllers/UserController.php @@ -99,6 +99,11 @@ final class UserController extends AbstractController $this->privilegeService->assertPrivilege(\Szurubooru\Privilege::CHANGE_ACCESS_RANK); } + if ($formData->browsingSettings) + { + $this->privilegeService->assertLoggedIn($userName); + } + $user = $this->userService->updateUser($userName, $formData); return $this->userViewProxy->fromEntity($user); } diff --git a/src/Controllers/ViewProxies/UserViewProxy.php b/src/Controllers/ViewProxies/UserViewProxy.php index c4b679e6..5b8104d8 100644 --- a/src/Controllers/ViewProxies/UserViewProxy.php +++ b/src/Controllers/ViewProxies/UserViewProxy.php @@ -22,6 +22,11 @@ class UserViewProxy extends AbstractViewProxy $result->lastLoginTime = $user->lastLoginTime; $result->avatarStyle = $user->avatarStyle; + if ($this->privilegeService->isLoggedIn($user)) + { + $result->browsingSettings = $user->browsingSettings; + } + if ($this->privilegeService->hasPrivilege(\Szurubooru\Privilege::VIEW_ALL_EMAIL_ADDRESSES) or $this->privilegeService->isLoggedIn($user)) { diff --git a/src/Entities/User.php b/src/Entities/User.php index 85944990..dd8c5797 100644 --- a/src/Entities/User.php +++ b/src/Entities/User.php @@ -21,4 +21,5 @@ final class User extends Entity public $registrationTime; public $lastLoginTime; public $avatarStyle; + public $browsingSettings; } diff --git a/src/FormData/UserEditFormData.php b/src/FormData/UserEditFormData.php index b396df50..4a016fe6 100644 --- a/src/FormData/UserEditFormData.php +++ b/src/FormData/UserEditFormData.php @@ -8,6 +8,7 @@ class UserEditFormData public $accessRank; public $password; public $avatarStyle; + public $browsingSettings; public function __construct($inputReader = null) { @@ -19,6 +20,7 @@ class UserEditFormData $this->accessRank = $inputReader->accessRank; $this->avatarStyle = $inputReader->avatarStyle; $this->avatarContent = $inputReader->avatarContent; + $this->browsingSettings = $inputReader->browsingSettings; } } } diff --git a/src/Services/PrivilegeService.php b/src/Services/PrivilegeService.php index 112591b3..251dce0b 100644 --- a/src/Services/PrivilegeService.php +++ b/src/Services/PrivilegeService.php @@ -47,6 +47,12 @@ class PrivilegeService throw new \DomainException('Unprivileged operation'); } + public function assertLoggedIn($userIdentifier) + { + if (!$this->isLoggedIn($userIdentifier)) + throw new \DomainException('Unprivileged operation'); + } + public function isLoggedIn($userIdentifier) { $loggedInUser = $this->authService->getLoggedInUser(); diff --git a/src/Services/UserService.php b/src/Services/UserService.php index 270ced9a..8e4dc5dc 100644 --- a/src/Services/UserService.php +++ b/src/Services/UserService.php @@ -109,6 +109,15 @@ class UserService $user->accessRank = \Szurubooru\Helpers\EnumHelper::accessRankFromString($formData->accessRank); } + if ($formData->browsingSettings !== null) + { + if (!is_string($formData->browsingSettings)) + throw new \InvalidArgumentException('Browsing settings must be stringified JSON.'); + if (strlen($formData->browsingSettings) > 2000) + throw new \InvalidArgumentException('Stringified browsing settings can have at most 2000 characters.'); + $user->browsingSettings = $formData->browsingSettings; + } + if ($formData->email !== null) $this->sendActivationMailIfNeeded($user);