diff --git a/client/js/controllers/top_navigation_controller.js b/client/js/controllers/top_navigation_controller.js index b1de03ec..550400cf 100644 --- a/client/js/controllers/top_navigation_controller.js +++ b/client/js/controllers/top_navigation_controller.js @@ -47,10 +47,12 @@ class TopNavigationController { topNavigation.hide('users'); } if (api.isLoggedIn()) { - topNavigation.hide('register'); + if (!api.hasPrivilege('users:create:any')) { + topNavigation.hide('register'); + } topNavigation.hide('login'); } else { - if (!api.hasPrivilege('users:create')) { + if (!api.hasPrivilege('users:create:self')) { topNavigation.hide('register'); } topNavigation.hide('account'); diff --git a/client/js/controllers/user_registration_controller.js b/client/js/controllers/user_registration_controller.js index 7d822380..78b94024 100644 --- a/client/js/controllers/user_registration_controller.js +++ b/client/js/controllers/user_registration_controller.js @@ -10,7 +10,7 @@ const EmptyView = require('../views/empty_view.js'); class UserRegistrationController { constructor() { - if (!api.hasPrivilege('users:create')) { + if (!api.hasPrivilege('users:create:self')) { this._view = new EmptyView(); this._view.showError('Registration is closed.'); return; @@ -29,12 +29,22 @@ class UserRegistrationController { user.name = e.detail.name; user.email = e.detail.email; user.password = e.detail.password; + const isLoggedIn = api.isLoggedIn(); user.save().then(() => { - api.forget(); - return api.login(e.detail.name, e.detail.password, false); + if (isLoggedIn) { + return Promise.resolve(); + } else { + api.forget(); + return api.login(e.detail.name, e.detail.password, false); + } }).then(() => { - const ctx = router.show(uri.formatClientLink()); - ctx.controller.showSuccess('Welcome aboard!'); + if (isLoggedIn) { + const ctx = router.show(uri.formatClientLink('users')); + ctx.controller.showSuccess('User added!'); + } else { + const ctx = router.show(uri.formatClientLink()); + ctx.controller.showSuccess('Welcome aboard!'); + } }, error => { this._view.showError(error.message); this._view.enableForm(); diff --git a/config.yaml.dist b/config.yaml.dist index c79b0d77..79e17230 100644 --- a/config.yaml.dist +++ b/config.yaml.dist @@ -68,7 +68,8 @@ default_rank: regular privileges: - 'users:create': anonymous + 'users:create:self': anonymous # Registration permission + 'users:create:any': administrator 'users:list': regular 'users:view': regular 'users:edit:any:name': moderator diff --git a/server/szurubooru/api/user_api.py b/server/szurubooru/api/user_api.py index e456f22e..5e14fabe 100644 --- a/server/szurubooru/api/user_api.py +++ b/server/szurubooru/api/user_api.py @@ -26,7 +26,11 @@ def get_users( @rest.routes.post('/users/?') def create_user( ctx: rest.Context, _params: Dict[str, str] = {}) -> rest.Response: - auth.verify_privilege(ctx.user, 'users:create') + if ctx.user.user_id is None: + auth.verify_privilege(ctx.user, 'users:create:self') + else: + auth.verify_privilege(ctx.user, 'users:create:any') + name = ctx.get_param_as_string('name') password = ctx.get_param_as_string('password') email = ctx.get_param_as_string('email', default='') @@ -40,6 +44,7 @@ def create_user( ctx.get_file('avatar', default=b'')) ctx.session.add(user) ctx.session.commit() + return _serialize(ctx, user, force_show_email=True) diff --git a/server/szurubooru/func/images.py b/server/szurubooru/func/images.py index befaf2a6..b3df55e7 100644 --- a/server/szurubooru/func/images.py +++ b/server/szurubooru/func/images.py @@ -11,10 +11,6 @@ from szurubooru.func import mime, util logger = logging.getLogger(__name__) -_SCALE_FIT_FMT = ( - r'scale=iw*max({width}/iw\,{height}/ih):ih*max({width}/iw\,{height}/ih)') - - class Image: def __init__(self, content: bytes) -> None: self.content = content @@ -33,10 +29,14 @@ class Image: return self.info['streams'][0]['nb_read_frames'] def resize_fill(self, width: int, height: int) -> None: + width_greater = self.width > self.height + width, height = (-1, height) if width_greater else (width, -1) + cli = [ '-i', '{path}', '-f', 'image2', - '-vf', _SCALE_FIT_FMT.format(width=width, height=height), + '-filter:v', "scale='{width}:{height}'".format( + width=width, height=height), '-map', '0:v:0', '-vframes', '1', '-vcodec', 'png', @@ -50,7 +50,7 @@ class Image: '-ss', '%d' % math.floor(duration * 0.3), ] + cli - content = self._execute(cli) + content = self._execute(cli, ignore_error_if_data=True) if not content: raise errors.ProcessingError('Error while resizing image.') self.content = content @@ -141,7 +141,11 @@ class Image: with open(mp4_temp_path, 'rb') as mp4_temp: return mp4_temp.read() - def _execute(self, cli: List[str], program: str = 'ffmpeg') -> bytes: + def _execute( + self, + cli: List[str], + program: str = 'ffmpeg', + ignore_error_if_data: bool = False) -> bytes: extension = mime.get_extension(mime.get_mime_type(self.content)) assert extension with util.create_temp_file(suffix='.' + extension) as handle: @@ -160,8 +164,11 @@ class Image: 'Failed to execute ffmpeg command (cli=%r, err=%r)', ' '.join(shlex.quote(arg) for arg in cli), err) - raise errors.ProcessingError( - 'Error while processing image.\n' + err.decode('utf-8')) + if ((len(out) > 0 and not ignore_error_if_data) + or len(out) == 0): + raise errors.ProcessingError( + 'Error while processing image.\n' + + err.decode('utf-8')) return out def _reload_info(self) -> None: diff --git a/server/szurubooru/tests/api/test_user_creating.py b/server/szurubooru/tests/api/test_user_creating.py index b5f36e39..699bfefb 100644 --- a/server/szurubooru/tests/api/test_user_creating.py +++ b/server/szurubooru/tests/api/test_user_creating.py @@ -6,7 +6,7 @@ from szurubooru.func import users @pytest.fixture(autouse=True) def inject_config(config_injector): - config_injector({'privileges': {'users:create': 'regular'}}) + config_injector({'privileges': {'users:create:self': 'regular'}}) def test_creating_user(user_factory, context_factory, fake_datetime):