diff --git a/doc/INSTALL.md b/doc/INSTALL.md index 901ae62e..447b9f5e 100644 --- a/doc/INSTALL.md +++ b/doc/INSTALL.md @@ -67,7 +67,19 @@ and Docker Compose (version 1.6.0 or greater) already installed. ### Additional Features -1. **Using a seperate domain to host static files (image content)** +1. **CLI-level administrative tools** + + You can use the included `szuru-admin` script to perform various + administrative tasks such as changing or resetting a user password. To + run from docker: + + ```console + user@host:szuru$ docker-compose run api ./szuru-admin --help + ``` + + will give you a breakdown on all available commands. + +2. **Using a seperate domain to host static files (image content)** If you want to host your website on, (`http://example.com/`) but want to serve the images on a different domain, (`http://static.example.com/`) @@ -76,7 +88,7 @@ and Docker Compose (version 1.6.0 or greater) already installed. additional host has access contents to the `/data` volume mounted in the backend. -2. **Setting a specific base URI for proxying** +3. **Setting a specific base URI for proxying** Some users may wish to access the service at a different base URI, such as `http://example.com/szuru/`, commonly when sharing multiple HTTP @@ -104,7 +116,7 @@ and Docker Compose (version 1.6.0 or greater) already installed. } ``` -3. **Preparing for production** +4. **Preparing for production** If you plan on using szurubooru in a production setting, you may opt to use a reverse proxy for added security and caching capabilities. Start diff --git a/server/recheck-post-audio b/server/recheck-post-audio deleted file mode 100755 index 8e5dfb25..00000000 --- a/server/recheck-post-audio +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -''' -Checks post audio and list disrepancies between the content and flags. -''' - -from szurubooru import db, model, errors -from szurubooru.func import files, images -from szurubooru.func import posts as postfuncs - - -def main(): - post_list = (db.session - .query(model.Post) - .filter(model.Post.type == model.Post.TYPE_VIDEO) - .order_by(model.Post.post_id) - .all()) - - for post in post_list: - print('Checking post %d ...' % post.post_id, end='\r') - content = files.get(postfuncs.get_post_content_path(post)) - - has_existing_flag = model.Post.FLAG_SOUND in post.flags - try: - has_sound_data = images.Image(content).check_for_sound() - except errors.ProcessingError: - print('Post %d caused an error when checking for sound' % post.post_id) - - if has_sound_data and not has_existing_flag: - print('Post %d has sound data but is not flagged' % post.post_id) - if not has_sound_data and has_existing_flag: - print('Post %d has no sound data but is flagged' % post.post_id) - - -if __name__ == '__main__': - main() diff --git a/server/reset-password b/server/reset-password deleted file mode 100755 index fb4cb35c..00000000 --- a/server/reset-password +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python3 - -''' -If the automatic email-based password reset is not enabled, system -administrators can still manually reset passwords with the help of -this script. -''' - -from sys import stderr -from getpass import getpass -from szurubooru import db -from szurubooru.func import users as userfuncs - - -def main(): - username = input('Enter username or email: ') - - try: - user = userfuncs.get_user_by_name_or_email(username) - except userfuncs.UserNotFoundError as e: - print(e, file=stderr) - return - - new_password = getpass('Enter new password for \'%s\': ' % user.name) - check_password = getpass('Re-enter password: ') - - if check_password != new_password: - print('Passwords do not match.', file=stderr) - return - - try: - userfuncs.update_user_password(user, new_password) - except userfuncs.InvalidPasswordError as e: - print(e, file=stderr) - return - - db.get_session().commit() - print('Sucessfully changed password for \'%s\'' % user.name) - - -if __name__ == '__main__': - main() diff --git a/server/szuru-admin b/server/szuru-admin new file mode 100755 index 00000000..5fe54c16 --- /dev/null +++ b/server/szuru-admin @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +''' +Collection of CLI commands for an administrator to use +''' + +import logging +import time +from argparse import ArgumentParser +from getpass import getpass +from sys import stderr + +from szurubooru import db, errors, model +from szurubooru.func import files, images, posts as postfuncs, users as userfuncs + + +def reset_password(username: str) -> None: + user = userfuncs.get_user_by_name_or_email(username) + + new_password = getpass('Enter new password for \'%s\': ' % user.name) + check_password = getpass('Re-enter password: ') + + if check_password != new_password: + raise errors.ValidationError('Passwords do not match') + + userfuncs.update_user_password(user, new_password) + db.get_session().commit() + print('Sucessfully changed password for \'%s\'' % user.name) + + +def check_audio() -> None: + post_list = (db.session + .query(model.Post) + .filter(model.Post.type == model.Post.TYPE_VIDEO) + .order_by(model.Post.post_id) + .all()) + + for post in post_list: + print('Checking post %d ...' % post.post_id, end='\r') + content = files.get(postfuncs.get_post_content_path(post)) + + has_existing_flag = model.Post.FLAG_SOUND in post.flags + try: + has_sound_data = images.Image(content).check_for_sound() + except errors.ProcessingError: + print('Post %d caused an error when checking for sound' % post.post_id) + + if has_sound_data and not has_existing_flag: + print('Post %d has sound data but is not flagged' % post.post_id) + if not has_sound_data and has_existing_flag: + print('Post %d has no sound data but is flagged' % post.post_id) + + +def main() -> None: + parser_top = ArgumentParser( + description='Collection of CLI commands for an administrator to use', + epilog='Look at README.md for more info') + parser = parser_top.add_mutually_exclusive_group(required=True) + parser.add_argument('--change-password', metavar='', + help='change the password of specified user') + parser.add_argument('--check-all-audio', action='store_true', + help='check the audio flags of all posts, noting discrepancies, without modifying posts') + command = parser_top.parse_args() + + try: + if command.change_password: + reset_password(command.change_password) + elif command.check_all_audio: + check_audio() + except errors.BaseError as e: + print(e, file=stderr) + + +if __name__ == '__main__': + main()