diff --git a/autograder/api/common.py b/autograder/api/common.py index 81eb8462..00186102 100644 --- a/autograder/api/common.py +++ b/autograder/api/common.py @@ -40,7 +40,7 @@ def send_api_request(endpoint, server = None, verbose = False, data = {}, files """ if ((server is None) or (server == '')): - raise autograder.api.error.APIError("No server provided.") + raise autograder.api.error.APIError(None, "No server provided.") server = server.rstrip('/') endpoint = endpoint.lstrip('/') @@ -51,8 +51,8 @@ def send_api_request(endpoint, server = None, verbose = False, data = {}, files for path in files: filename = os.path.basename(path) if (filename in post_files): - raise autograder.api.error.APIError("Cannot submit duplicate filenames ('%s')." % ( - filename)) + raise autograder.api.error.APIError(None, "Cannot submit duplicate filenames ('%s')." + % (filename)) post_files[filename] = open(path, 'rb') @@ -71,7 +71,7 @@ def send_api_request(endpoint, server = None, verbose = False, data = {}, files try: response = raw_response.json() except Exception as ex: - raise autograder.api.error.APIError("Autograder response does not contain valid JSON." + raise autograder.api.error.APIError(None, "Autograder response does not contain valid JSON." + " Contact a server admin with the following. Response:\n---\n%s\n---" % ( raw_response.text)) from ex diff --git a/autograder/api/config.py b/autograder/api/config.py index 4b67fae6..e6096e6a 100644 --- a/autograder/api/config.py +++ b/autograder/api/config.py @@ -21,11 +21,11 @@ def __init__(self, key, description, hash = False): self.key = str(key) if ((key is None) or (self.key == '')): - raise autograder.api.error.APIError("APIParam cannot have an empty key.") + raise autograder.api.error.APIError(None, "APIParam cannot have an empty key.") self.description = str(description) if ((description is None) or (self.description == '')): - raise autograder.api.error.APIError("APIParam cannot have an empty description.") + raise autograder.api.error.APIError(None, "APIParam cannot have an empty description.") self.config_key = config_key if (self.config_key is None): @@ -68,7 +68,7 @@ def _parse_api_config(config, params, additional_required_keys, additional_optio for param in params: if (param.config_key not in config): if (param.required): - raise autograder.api.error.APIError( + raise autograder.api.error.APIError(None, f"Required parameter '{param.config_key}' not set.") continue @@ -81,7 +81,7 @@ def _parse_api_config(config, params, additional_required_keys, additional_optio for key in additional_required_keys: if (key not in config): - raise autograder.api.error.APIError(f"Required parameter '{key}' not set.") + raise autograder.api.error.APIError(None, f"Required parameter '{key}' not set.") extra[key] = config[key] @@ -218,7 +218,7 @@ def get_argument_parser( PARAM_NEW_PASS = APIParam('new-pass', 'The new password to set for the user that is the target of this request.', - required = False, hash = True) + required = True, hash = True) PARAM_SKIP_EMAILS = APIParam('skip-emails', 'Skip sending any emails. Be aware that this may result in inaccessible information.', diff --git a/autograder/api/users/password/__init__.py b/autograder/api/users/password/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/autograder/api/users/password/change.py b/autograder/api/users/password/change.py new file mode 100644 index 00000000..eec691a5 --- /dev/null +++ b/autograder/api/users/password/change.py @@ -0,0 +1,21 @@ +import autograder.api.common +import autograder.api.config + +API_ENDPOINT = 'users/password/change' +API_PARAMS = [ + autograder.api.config.PARAM_USER_EMAIL, + autograder.api.config.PARAM_USER_PASS, + autograder.api.config.PARAM_NEW_PASS, +] + +DESCRIPTION = 'Change your password to the one provided.' + +def send(arguments, **kwargs): + return autograder.api.common.handle_api_request(arguments, API_PARAMS, API_ENDPOINT, **kwargs) + +def _get_parser(): + parser = autograder.api.config.get_argument_parser( + description = DESCRIPTION, + params = API_PARAMS) + + return parser diff --git a/autograder/cli/users/password/__init__.py b/autograder/cli/users/password/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/autograder/cli/users/password/__main__.py b/autograder/cli/users/password/__main__.py new file mode 100644 index 00000000..3e28bc3a --- /dev/null +++ b/autograder/cli/users/password/__main__.py @@ -0,0 +1,14 @@ +""" +The `autograder.cli.users.password` package contains tools to manage user passwords. +""" + +import sys + +import autograder.util.cli + +def main(): + autograder.util.cli.auto_list() + return 0 + +if (__name__ == '__main__'): + sys.exit(main()) diff --git a/autograder/cli/users/password/change.py b/autograder/cli/users/password/change.py new file mode 100644 index 00000000..6dfd422e --- /dev/null +++ b/autograder/cli/users/password/change.py @@ -0,0 +1,26 @@ +import sys + +import autograder.api.users.password.change + +def run(arguments): + result = autograder.api.users.password.change.send(arguments, exit_on_error = True) + + if (result['duplicate']): + print("Your new password must be different from your previous password.") + return 0 + + if (result['success']): + print("You have successfully changed your password.") + return 0 + + return 1 + +def main(): + return run(_get_parser().parse_args()) + +def _get_parser(): + parser = autograder.api.users.password.change._get_parser() + return parser + +if (__name__ == '__main__'): + sys.exit(main()) diff --git a/tests/api/data/test_password_change_duplicate.json b/tests/api/data/test_password_change_duplicate.json new file mode 100644 index 00000000..e0d5b8f2 --- /dev/null +++ b/tests/api/data/test_password_change_duplicate.json @@ -0,0 +1,11 @@ +{ + "endpoint": "users/pass/change", + "module": "autograder.api.users.password.change", + "arguments": { + "new-pass": "admin" + }, + "output": { + "success": true, + "duplicate": true + } +} diff --git a/tests/api/data/test_password_change_success.json b/tests/api/data/test_password_change_success.json new file mode 100644 index 00000000..995218e2 --- /dev/null +++ b/tests/api/data/test_password_change_success.json @@ -0,0 +1,13 @@ +{ + "endpoint": "users/pass/change", + "module": "autograder.api.users.password.change", + "arguments": { + "user": "student@test.com", + "pass": "student", + "new-pass": "spooky" + }, + "output": { + "success": true, + "duplicate": false + } +}