diff --git a/autograder/api/config.py b/autograder/api/config.py index 38fa9e9d..9dadfc79 100644 --- a/autograder/api/config.py +++ b/autograder/api/config.py @@ -211,7 +211,7 @@ def get_argument_parser( 'Only show results from users with this role (all roles if unknown (default)).', required = False, parser_options = {'action': 'store', 'default': 'unknown', - 'choices': autograder.api.constants.ROLES}) + 'choices': autograder.api.constants.COURSE_ROLES}) PARAM_FORCE = APIParam('force', 'Force the operation, overwriting and existing resources.', diff --git a/autograder/api/constants.py b/autograder/api/constants.py index bce70616..7f243c8c 100644 --- a/autograder/api/constants.py +++ b/autograder/api/constants.py @@ -6,7 +6,14 @@ API_RESPONSE_KEY_MESSAGE = 'message' API_RESPONSE_KEY_CONTENT = API_REQUEST_JSON_KEY -ROLES = [ +SERVER_ROLES = [ + 'user', + 'creator', + 'admin', + 'owner', +] + +COURSE_ROLES = [ 'unknown', 'other', 'student', diff --git a/autograder/api/users/upsert.py b/autograder/api/users/upsert.py new file mode 100644 index 00000000..251a4d36 --- /dev/null +++ b/autograder/api/users/upsert.py @@ -0,0 +1,40 @@ +import autograder.api.common +import autograder.api.config + +API_ENDPOINT = 'users/upsert' +API_PARAMS = [ + autograder.api.config.PARAM_USER_EMAIL, + autograder.api.config.PARAM_USER_PASS, + + autograder.api.config.PARAM_DRY_RUN, + + autograder.api.config.APIParam('skip-inserts', + 'Skip inserts (default: False).', + required = False, + parser_options = {'action': 'store_true', 'default': False}), + + autograder.api.config.APIParam('skip-updates', + 'Skip updates (default: False).', + required = False, + parser_options = {'action': 'store_true', 'default': False}), + + autograder.api.config.APIParam('send-emails', + 'Send any emails.', + required = True, cli_param = False), + + autograder.api.config.APIParam('raw-users', + 'A list of users to upsert.', + required = True, cli_param = False), +] + +DESCRIPTION = 'Upsert one or more users to the server (update if exists, insert otherwise).' + +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/common.py b/autograder/cli/common.py index 0a9c7bfd..73681bc7 100644 --- a/autograder/cli/common.py +++ b/autograder/cli/common.py @@ -10,6 +10,8 @@ COURSE_USER_INFO_TYPE = 'course' SERVER_USER_INFO_TYPE = 'server' +INDENT = ' ' + SYNC_USERS_KEYS = [ ('add-users', 'Added', 'add'), ('mod-users', 'Modified', 'mod'), @@ -17,6 +19,27 @@ ('skip-users', 'Skipped', 'skip'), ] +USER_OP_KEYS = [ + ('added', 'Added'), + ('modified', 'Modified'), + ('removed', 'Removed'), + ('skipped', 'Skipped'), + ('not-exists', 'Not Exists'), + ('emailed', 'Emailed'), + ('enrolled', 'Enrolled'), + ('dopped', 'Dropped'), +] + +USER_OP_ERROR_KEYS = [ + ('validation-error', 'Validation Error'), + ('system-error', 'System Error'), + ('communication-error', 'Communication Error'), +] + +ALL_USER_OP_KEYS = [ + ('email', 'Email'), +] + USER_OP_KEYS + USER_OP_ERROR_KEYS + # Set course_users to True if listing course users, False for server users. # An error will be raised if a user of a different type is found. def list_users(users, course_users, table = False, normalize = False): @@ -150,13 +173,50 @@ def _list_sync_users_table(sync_users): def list_add_users(result, table = False): errors = result['errors'] if ((errors is not None) and (len(errors) > 0)): - print("Encounted %d errors." % (len(errors))) + print("Encountered %d errors." % (len(errors))) for error in errors: print(" Index: %d, Email: '%s', Message: '%s'." % ( error['index'], error['email'], error['message'])) list_sync_users(result, table = table) +def _list_user_op_responses(results): + error_count = 0 + for result in results: + print(result['email']) + for op_key, label in USER_OP_KEYS: + if (result.get(op_key, None) is not None): + print(INDENT + label) + if (isinstance(result[op_key], list)): + for value in result[op_key]: + print(INDENT + INDENT + value) + + for error_key, label in USER_OP_ERROR_KEYS: + if (result.get(error_key, None) is not None): + error_count += 1 + print(INDENT + label) + print(INDENT + INDENT + result[error_key]['message']) + + print() + print("Processed %d users. Encountered %d errors." % (len(results), error_count)) + +def _list_user_op_responses_table(results, header = True, keys = ALL_USER_OP_KEYS): + rows = [] + for result in results: + for error_key, _ in USER_OP_ERROR_KEYS: + if (result.get(error_key, None) is not None): + result[error_key] = result[error_key]['message'] + + rows.append([result.get(key, '') for key, _ in keys]) + + _print_tsv(rows, header, [header_key for _, header_key in keys]) + +def list_user_op_responses(results, table = False): + if (table): + _list_user_op_responses_table(results) + else: + _list_user_op_responses(results) + def _print_tsv(rows, header, header_keys): lines = [] if (header): diff --git a/autograder/cli/users/upsert-file.py b/autograder/cli/users/upsert-file.py new file mode 100644 index 00000000..ed620a0e --- /dev/null +++ b/autograder/cli/users/upsert-file.py @@ -0,0 +1,120 @@ +import sys + +import autograder.api.constants +import autograder.api.users.upsert +import autograder.cli.common +import autograder.util.hash + +def run(arguments): + arguments = vars(arguments) + + arguments['raw-users'] = _load_users(arguments['path']) + arguments['send-emails'] = not arguments['skip-emails'] + + result = autograder.api.users.upsert.send(arguments, exit_on_error = True) + + autograder.cli.common.list_user_op_responses(result['results'], table = arguments['table']) + return 0 + +def _load_users(path): + users = [] + + with open(path, 'r') as file: + lineno = 0 + for line in file: + lineno += 1 + + line = line.strip() + if (line == ""): + continue + + parts = line.split("\t") + parts = [part.strip() for part in parts] + + if (len(parts) > 7): + raise ValueError( + "File ('%s') line (%d) has too many values. Max is 7, found %d." % ( + path, lineno, len(parts))) + + email = parts.pop(0) + + password = '' + if (len(parts) > 0): + password = parts.pop(0) + if (password != ''): + password = autograder.util.hash.sha256_hex(password) + + name = '' + if (len(parts) > 0): + name = parts.pop(0) + + role = 'user' + if (len(parts) > 0): + role = parts.pop(0) + role = role.lower() + + if (role not in autograder.api.constants.SERVER_ROLES): + raise ValueError( + "File ('%s') line (%d) has an invalid role '%s'." % ( + path, lineno, role)) + + course = '' + if (len(parts) > 0): + course = parts.pop(0) + + course_role = 'unknown' + if (len(parts) > 0): + course_role = parts.pop(0) + course_role = course_role.lower() + + if (course_role not in autograder.api.constants.COURSE_ROLES): + raise ValueError( + "File ('%s') line (%d) has an invalid course role '%s'." % ( + path, lineno, course_role)) + + course_lms_id = '' + if (len(parts) > 0): + course_lms_id = parts.pop(0) + + users.append({ + 'email': email, + 'pass': password, + 'name': name, + 'role': role, + 'course': course, + 'course-role': course_role, + 'course-lms-id': course_lms_id, + }) + + return users + +def main(): + return run(_get_parser().parse_args()) + +def _get_parser(): + parser = autograder.api.users.upsert._get_parser() + + parser.description = ('Upsert users to the course from a TSV file.' + + ' (Update if exists, otherwiese insert).') + + parser.add_argument('path', metavar = 'PATH', + action = 'store', type = str, + help = 'Path to a TSV file where each line contains up to seven columns:' + + ' [email, pass, name, role, course, course-role, lms-id].' + + ' Only the email is required. Leading and trailing whitespace is stripped' + + ' from all fields, including pass. If pass is empty, a password will be' + + ' randomly generated and emailed to the user.') + + parser.add_argument('--skip-emails', dest = 'skip-emails', + action = 'store_true', default = False, + help = 'Skip sending any emails. Be aware that this may result in inaccessible' + + ' information (default: %(default)s).') + + parser.add_argument('--table', dest = 'table', + action = 'store_true', default = False, + help = 'Output the results as a TSV table with a header (default: %(default)s).') + + return parser + +if (__name__ == '__main__'): + sys.exit(main()) diff --git a/autograder/cli/users/upsert.py b/autograder/cli/users/upsert.py new file mode 100644 index 00000000..fd415f2b --- /dev/null +++ b/autograder/cli/users/upsert.py @@ -0,0 +1,80 @@ +import sys + +import autograder.api.config +import autograder.api.users.upsert +import autograder.cli.common + +def run(arguments): + arguments = vars(arguments) + + password = arguments['new-pass'] + if (password != ''): + password = autograder.util.hash.sha256_hex(password) + + arguments['raw-users'] = [{ + 'email': arguments['new-email'], + 'name': arguments['new-name'], + 'role': arguments['new-role'], + 'pass': password, + 'course': arguments['new-course'], + 'course-role': arguments['new-course-role'], + 'course-lms-id': arguments['new-lms-id'], + }] + + arguments['send-emails'] = not arguments['skip-emails'] + + result = autograder.api.users.upsert.send(arguments, exit_on_error = True) + + autograder.cli.common.list_user_op_responses(result['results'], table = arguments['table']) + return 0 + +def main(): + return run(_get_parser().parse_args()) + +def _get_parser(): + parser = autograder.api.users.upsert._get_parser() + + parser.add_argument('--skip-emails', dest = 'skip-emails', + action = 'store_true', default = False, + help = 'Skip sending any emails. Be aware that this may result in inaccessible' + + ' information (default: %(default)s).') + + parser.add_argument('--new-email', dest = 'new-email', + action = 'store', type = str, required = True, + help = 'The email of the user to upsert.') + + parser.add_argument('--new-name', dest = 'new-name', + action = 'store', type = str, default = '', + help = 'The name of the user to upsert.') + + parser.add_argument('--new-role', dest = 'new-role', + action = 'store', type = str, default = 'user', + choices = autograder.api.constants.SERVER_ROLES, + help = 'The role of the user to upsert (default: %(default)s).') + + parser.add_argument('--new-pass', dest = 'new-pass', + action = 'store', type = str, default = '', + help = 'The password of the user to upsert.' + + ' If empty, the server will generate and email a password.') + + parser.add_argument('--new-course', dest = 'new-course', + action = 'store', type = str, default = '', + help = 'The course of the user to upsert.') + + parser.add_argument('--new-course-role', dest = 'new-course-role', + action = 'store', type = str, default = 'student', + choices = autograder.api.constants.COURSE_ROLES, + help = 'The course role of the user to upsert (default: %(default)s).') + + parser.add_argument('--new-lms-id', dest = 'new-lms-id', + action = 'store', type = str, default = '', + help = 'The lms id of the user to upsert.') + + parser.add_argument('--table', dest = 'table', + action = 'store_true', default = False, + help = 'Output the results as a TSV table with a header (default: %(default)s).') + + return parser + +if (__name__ == '__main__'): + sys.exit(main()) diff --git a/tests/api/testdata/users_upsert_add.json b/tests/api/testdata/users_upsert_add.json new file mode 100644 index 00000000..6ab8c83b --- /dev/null +++ b/tests/api/testdata/users_upsert_add.json @@ -0,0 +1,31 @@ +{ + "module": "autograder.api.users.upsert", + "arguments": { + "user": "server-admin@test.edulinq.org", + "pass": "server-admin", + "send-emails": true, + "skip-inserts": false, + "skip-updates": false, + "dry-run": false, + "raw-users": [ + { + "email": "new-user@test.edulinq.org", + "name": "", + "role": "user", + "pass": "", + "course": "", + "course-role": "student", + "course-lms-id": "" + } + ] + }, + "output": { + "results": [ + { + "email": "new-user@test.edulinq.org", + "added": true, + "emailed": true + } + ] + } +} diff --git a/tests/api/testdata/users_upsert_file_add.json b/tests/api/testdata/users_upsert_file_add.json new file mode 100644 index 00000000..f0341f51 --- /dev/null +++ b/tests/api/testdata/users_upsert_file_add.json @@ -0,0 +1,60 @@ +{ + "module": "autograder.api.users.upsert", + "endpoint": "users/upsert-file", + "arguments": { + "user": "server-admin@test.edulinq.org", + "pass": "server-admin", + "send-emails": true, + "skip-inserts": false, + "skip-updates": false, + "dry-run": false, + "raw-users": [ + { + "email": "file-new-user-1@test.edulinq.org", + "name": "", + "role": "user", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + }, + { + "email": "file-new-user-2@test.edulinq.org", + "name": "", + "role": "user", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + }, + { + "email": "file-new-user-3@test.edulinq.org", + "name": "", + "role": "user", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + } + ] + }, + "output": { + "results": [ + { + "email": "file-new-user-1@test.edulinq.org", + "added": true, + "emailed": true + }, + { + "email": "file-new-user-2@test.edulinq.org", + "added": true, + "emailed": true + }, + { + "email": "file-new-user-3@test.edulinq.org", + "added": true, + "emailed": true + } + ] + } +} diff --git a/tests/api/testdata/users_upsert_file_add_complex.json b/tests/api/testdata/users_upsert_file_add_complex.json new file mode 100644 index 00000000..712cff06 --- /dev/null +++ b/tests/api/testdata/users_upsert_file_add_complex.json @@ -0,0 +1,65 @@ +{ + "module": "autograder.api.users.upsert", + "endpoint": "users/upsert-file", + "arguments": { + "user": "server-admin@test.edulinq.org", + "pass": "server-admin", + "send-emails": true, + "skip-inserts": false, + "skip-updates": false, + "dry-run": false, + "raw-users": [ + { + "email": "first@test.edulinq.org", + "name": "first", + "role": "user", + "pass": "", + "course": "course101", + "course-role": "student", + "course-lms-id": "first-lms-id" + }, + { + "email": "second@test.edulinq.org", + "name": "second", + "role": "creator", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + }, + { + "email": "val-error@test.edulinq.org", + "name": "val-error", + "role": "owner", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + } + ] + }, + "output": { + "results": [ + { + "email": "first@test.edulinq.org", + "added": true, + "emailed": true, + "enrolled": [ + "course101" + ] + }, + { + "email": "second@test.edulinq.org", + "added": true, + "emailed": true + }, + { + "email": "val-error@test.edulinq.org", + "validation-error": { + "locator": "", + "message": "You have insufficient permissions for the requested operation." + } + } + ] + } +} diff --git a/tests/api/testdata/users_upsert_file_mod.json b/tests/api/testdata/users_upsert_file_mod.json new file mode 100644 index 00000000..95abd02e --- /dev/null +++ b/tests/api/testdata/users_upsert_file_mod.json @@ -0,0 +1,44 @@ +{ + "module": "autograder.api.users.upsert", + "endpoint": "users/upsert-file", + "arguments": { + "user": "server-admin@test.edulinq.org", + "pass": "server-admin", + "send-emails": true, + "skip-inserts": false, + "skip-updates": false, + "dry-run": false, + "raw-users": [ + { + "email": "server-user@test.edulinq.org", + "name": "sammy", + "role": "user", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + }, + { + "email": "server-creator@test.edulinq.org", + "name": "", + "role": "user", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + } + ] + }, + "output": { + "results": [ + { + "email": "server-creator@test.edulinq.org", + "modified": true + }, + { + "email": "server-user@test.edulinq.org", + "modified": true + } + ] + } +} diff --git a/tests/api/testdata/users_upsert_file_val_errors.json b/tests/api/testdata/users_upsert_file_val_errors.json new file mode 100644 index 00000000..a9eafe5b --- /dev/null +++ b/tests/api/testdata/users_upsert_file_val_errors.json @@ -0,0 +1,66 @@ +{ + "module": "autograder.api.users.upsert", + "endpoint": "users/upsert-file", + "arguments": { + "user": "server-admin@test.edulinq.org", + "pass": "server-admin", + "send-emails": true, + "skip-inserts": false, + "skip-updates": false, + "dry-run": false, + "raw-users": [ + { + "email": "error@test.edulinq.org", + "name": "", + "role": "owner", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + }, + { + "email": "server-user@test.edulinq.org", + "name": "", + "role": "owner", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + }, + { + "email": "server-owner@test.edulinq.org", + "name": "", + "role": "user", + "pass": "", + "course": "", + "course-role": "unknown", + "course-lms-id": "" + } + ] + }, + "output": { + "results": [ + { + "email": "error@test.edulinq.org", + "validation-error": { + "locator": "", + "message": "You have insufficient permissions for the requested operation." + } + }, + { + "email": "server-owner@test.edulinq.org", + "validation-error": { + "locator": "", + "message": "You have insufficient permissions for the requested operation." + } + }, + { + "email": "server-user@test.edulinq.org", + "validation-error": { + "locator": "", + "message": "You have insufficient permissions for the requested operation." + } + } + ] + } +} diff --git a/tests/api/testdata/users_upsert_mod.json b/tests/api/testdata/users_upsert_mod.json new file mode 100644 index 00000000..ac53d82b --- /dev/null +++ b/tests/api/testdata/users_upsert_mod.json @@ -0,0 +1,30 @@ +{ + "module": "autograder.api.users.upsert", + "arguments": { + "user": "server-admin@test.edulinq.org", + "pass": "server-admin", + "send-emails": true, + "skip-inserts": false, + "skip-updates": false, + "dry-run": false, + "raw-users": [ + { + "email": "server-user@test.edulinq.org", + "name": "", + "role": "creator", + "pass": "", + "course": "", + "course-role": "student", + "course-lms-id": "" + } + ] + }, + "output": { + "results": [ + { + "email": "server-user@test.edulinq.org", + "modified": true + } + ] + } +} diff --git a/tests/api/testdata/users_upsert_skip_inserts.json b/tests/api/testdata/users_upsert_skip_inserts.json new file mode 100644 index 00000000..9be449d7 --- /dev/null +++ b/tests/api/testdata/users_upsert_skip_inserts.json @@ -0,0 +1,30 @@ +{ + "module": "autograder.api.users.upsert", + "arguments": { + "user": "server-admin@test.edulinq.org", + "pass": "server-admin", + "send-emails": true, + "skip-inserts": true, + "skip-updates": false, + "dry-run": false, + "raw-users": [ + { + "email": "alt-new-user@test.edulinq.org", + "name": "", + "role": "user", + "pass": "", + "course": "", + "course-role": "student", + "course-lms-id": "" + } + ] + }, + "output": { + "results": [ + { + "email": "alt-new-user@test.edulinq.org", + "skipped": true + } + ] + } +} diff --git a/tests/api/testdata/users_upsert_skip_updates.json b/tests/api/testdata/users_upsert_skip_updates.json new file mode 100644 index 00000000..25bbfc7c --- /dev/null +++ b/tests/api/testdata/users_upsert_skip_updates.json @@ -0,0 +1,30 @@ +{ + "module": "autograder.api.users.upsert", + "arguments": { + "user": "server-admin@test.edulinq.org", + "pass": "server-admin", + "send-emails": true, + "skip-inserts": false, + "skip-updates": true, + "dry-run": false, + "raw-users": [ + { + "email": "server-user@test.edulinq.org", + "name": "", + "role": "creator", + "pass": "", + "course": "", + "course-role": "student", + "course-lms-id": "" + } + ] + }, + "output": { + "results": [ + { + "email": "server-user@test.edulinq.org", + "skipped": true + } + ] + } +} diff --git a/tests/api/testdata/users_upsert_val_error.json b/tests/api/testdata/users_upsert_val_error.json new file mode 100644 index 00000000..438bc180 --- /dev/null +++ b/tests/api/testdata/users_upsert_val_error.json @@ -0,0 +1,33 @@ +{ + "module": "autograder.api.users.upsert", + "arguments": { + "user": "server-admin@test.edulinq.org", + "pass": "server-admin", + "send-emails": true, + "skip-inserts": false, + "skip-updates": false, + "dry-run": false, + "raw-users": [ + { + "email": "server-user@test.edulinq.org", + "name": "", + "role": "owner", + "pass": "", + "course": "", + "course-role": "student", + "course-lms-id": "" + } + ] + }, + "output": { + "results": [ + { + "email": "server-user@test.edulinq.org", + "validation-error": { + "locator": "", + "message": "You have insufficient permissions for the requested operation." + } + } + ] + } +} diff --git a/tests/cli/data/users_upsert_file_add.txt b/tests/cli/data/users_upsert_file_add.txt new file mode 100644 index 00000000..90903bbb --- /dev/null +++ b/tests/cli/data/users_upsert_file_add.txt @@ -0,0 +1,3 @@ +file-new-user-1@test.edulinq.org +file-new-user-2@test.edulinq.org +file-new-user-3@test.edulinq.org diff --git a/tests/cli/data/users_upsert_file_add_complex.txt b/tests/cli/data/users_upsert_file_add_complex.txt new file mode 100644 index 00000000..eefea37d --- /dev/null +++ b/tests/cli/data/users_upsert_file_add_complex.txt @@ -0,0 +1,3 @@ +first@test.edulinq.org first user course101 student first-lms-id +second@test.edulinq.org second creator +val-error@test.edulinq.org val-error owner diff --git a/tests/cli/data/users_upsert_file_mod.txt b/tests/cli/data/users_upsert_file_mod.txt new file mode 100644 index 00000000..3f9dbe24 --- /dev/null +++ b/tests/cli/data/users_upsert_file_mod.txt @@ -0,0 +1,2 @@ +server-user@test.edulinq.org sammy +server-creator@test.edulinq.org user diff --git a/tests/cli/data/users_upsert_file_val_errors.txt b/tests/cli/data/users_upsert_file_val_errors.txt new file mode 100644 index 00000000..2e050993 --- /dev/null +++ b/tests/cli/data/users_upsert_file_val_errors.txt @@ -0,0 +1,3 @@ +error@test.edulinq.org owner +server-user@test.edulinq.org owner +server-owner@test.edulinq.org user diff --git a/tests/cli/testdata/users/users_upsert_add.txt b/tests/cli/testdata/users/users_upsert_add.txt new file mode 100644 index 00000000..7e4bbf1e --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_add.txt @@ -0,0 +1,14 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "new-user@test.edulinq.org" + ] +} +--- +new-user@test.edulinq.org + Added + Emailed + +Processed 1 users. Encountered 0 errors. diff --git a/tests/cli/testdata/users/users_upsert_add_table.txt b/tests/cli/testdata/users/users_upsert_add_table.txt new file mode 100644 index 00000000..3b7cc305 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_add_table.txt @@ -0,0 +1,12 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "new-user@test.edulinq.org", + "--table" + ] +} +--- +Email Added Modified Removed Skipped Not Exists Emailed Enrolled Dropped Validation Error System Error Communication Error +new-user@test.edulinq.org True True diff --git a/tests/cli/testdata/users/users_upsert_file_add.txt b/tests/cli/testdata/users/users_upsert_file_add.txt new file mode 100644 index 00000000..aa5a5b35 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_file_add.txt @@ -0,0 +1,20 @@ +{ + "cli": "autograder.cli.users.upsert-file", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "__DATA_DIR__(users_upsert_file_add.txt)" + ] +} +--- +file-new-user-1@test.edulinq.org + Added + Emailed +file-new-user-2@test.edulinq.org + Added + Emailed +file-new-user-3@test.edulinq.org + Added + Emailed + +Processed 3 users. Encountered 0 errors. diff --git a/tests/cli/testdata/users/users_upsert_file_add_complex.txt b/tests/cli/testdata/users/users_upsert_file_add_complex.txt new file mode 100644 index 00000000..878ff7b0 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_file_add_complex.txt @@ -0,0 +1,22 @@ +{ + "cli": "autograder.cli.users.upsert-file", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "__DATA_DIR__(users_upsert_file_add_complex.txt)" + ] +} +--- +first@test.edulinq.org + Added + Emailed + Enrolled + course101 +second@test.edulinq.org + Added + Emailed +val-error@test.edulinq.org + Validation Error + You have insufficient permissions for the requested operation. + +Processed 3 users. Encountered 1 errors. diff --git a/tests/cli/testdata/users/users_upsert_file_add_complex_table.txt b/tests/cli/testdata/users/users_upsert_file_add_complex_table.txt new file mode 100644 index 00000000..42053042 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_file_add_complex_table.txt @@ -0,0 +1,13 @@ +{ + "cli": "autograder.cli.users.upsert-file", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--table", + "__DATA_DIR__(users_upsert_file_add_complex.txt)" + ]} +--- +Email Added Modified Removed Skipped Not Exists Emailed Enrolled Dropped Validation Error System Error Communication Error +first@test.edulinq.org True True ['course101'] +second@test.edulinq.org True True +val-error@test.edulinq.org You have insufficient permissions for the requested operation. diff --git a/tests/cli/testdata/users/users_upsert_file_add_table.txt b/tests/cli/testdata/users/users_upsert_file_add_table.txt new file mode 100644 index 00000000..4fc1f11a --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_file_add_table.txt @@ -0,0 +1,13 @@ +{ + "cli": "autograder.cli.users.upsert-file", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--table", + "__DATA_DIR__(users_upsert_file_add.txt)" + ]} +--- +Email Added Modified Removed Skipped Not Exists Emailed Enrolled Dropped Validation Error System Error Communication Error +file-new-user-1@test.edulinq.org True True +file-new-user-2@test.edulinq.org True True +file-new-user-3@test.edulinq.org True True diff --git a/tests/cli/testdata/users/users_upsert_file_mod.txt b/tests/cli/testdata/users/users_upsert_file_mod.txt new file mode 100644 index 00000000..24b52bb1 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_file_mod.txt @@ -0,0 +1,15 @@ +{ + "cli": "autograder.cli.users.upsert-file", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "__DATA_DIR__(users_upsert_file_mod.txt)" + ] +} +--- +server-creator@test.edulinq.org + Modified +server-user@test.edulinq.org + Modified + +Processed 2 users. Encountered 0 errors. diff --git a/tests/cli/testdata/users/users_upsert_file_mod_table.txt b/tests/cli/testdata/users/users_upsert_file_mod_table.txt new file mode 100644 index 00000000..d854f165 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_file_mod_table.txt @@ -0,0 +1,12 @@ +{ + "cli": "autograder.cli.users.upsert-file", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--table", + "__DATA_DIR__(users_upsert_file_mod.txt)" + ]} +--- +Email Added Modified Removed Skipped Not Exists Emailed Enrolled Dropped Validation Error System Error Communication Error +server-creator@test.edulinq.org True +server-user@test.edulinq.org True diff --git a/tests/cli/testdata/users/users_upsert_file_val_errors.txt b/tests/cli/testdata/users/users_upsert_file_val_errors.txt new file mode 100644 index 00000000..f9a240d5 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_file_val_errors.txt @@ -0,0 +1,20 @@ +{ + "cli": "autograder.cli.users.upsert-file", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "__DATA_DIR__(users_upsert_file_val_errors.txt)" + ] +} +--- +error@test.edulinq.org + Validation Error + You have insufficient permissions for the requested operation. +server-owner@test.edulinq.org + Validation Error + You have insufficient permissions for the requested operation. +server-user@test.edulinq.org + Validation Error + You have insufficient permissions for the requested operation. + +Processed 3 users. Encountered 3 errors. diff --git a/tests/cli/testdata/users/users_upsert_file_val_errors_table.txt b/tests/cli/testdata/users/users_upsert_file_val_errors_table.txt new file mode 100644 index 00000000..75b634a5 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_file_val_errors_table.txt @@ -0,0 +1,13 @@ +{ + "cli": "autograder.cli.users.upsert-file", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--table", + "__DATA_DIR__(users_upsert_file_val_errors.txt)" + ]} +--- +Email Added Modified Removed Skipped Not Exists Emailed Enrolled Dropped Validation Error System Error Communication Error +error@test.edulinq.org You have insufficient permissions for the requested operation. +server-owner@test.edulinq.org You have insufficient permissions for the requested operation. +server-user@test.edulinq.org You have insufficient permissions for the requested operation. diff --git a/tests/cli/testdata/users/users_upsert_mod.txt b/tests/cli/testdata/users/users_upsert_mod.txt new file mode 100644 index 00000000..3b1a6248 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_mod.txt @@ -0,0 +1,14 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "server-user@test.edulinq.org", + "--new-role", "creator" + ] +} +--- +server-user@test.edulinq.org + Modified + +Processed 1 users. Encountered 0 errors. diff --git a/tests/cli/testdata/users/users_upsert_mod_table.txt b/tests/cli/testdata/users/users_upsert_mod_table.txt new file mode 100644 index 00000000..cf74045e --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_mod_table.txt @@ -0,0 +1,13 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "server-user@test.edulinq.org", + "--new-role", "creator", + "--table" + ] +} +--- +Email Added Modified Removed Skipped Not Exists Emailed Enrolled Dropped Validation Error System Error Communication Error +server-user@test.edulinq.org True diff --git a/tests/cli/testdata/users/users_upsert_skip_inserts.txt b/tests/cli/testdata/users/users_upsert_skip_inserts.txt new file mode 100644 index 00000000..4bee35ce --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_skip_inserts.txt @@ -0,0 +1,14 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "alt-new-user@test.edulinq.org", + "--skip-inserts" + ] +} +--- +alt-new-user@test.edulinq.org + Skipped + +Processed 1 users. Encountered 0 errors. diff --git a/tests/cli/testdata/users/users_upsert_skip_inserts_table.txt b/tests/cli/testdata/users/users_upsert_skip_inserts_table.txt new file mode 100644 index 00000000..84897fec --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_skip_inserts_table.txt @@ -0,0 +1,13 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "alt-new-user@test.edulinq.org", + "--skip-inserts", + "--table" + ] +} +--- +Email Added Modified Removed Skipped Not Exists Emailed Enrolled Dropped Validation Error System Error Communication Error +alt-new-user@test.edulinq.org True diff --git a/tests/cli/testdata/users/users_upsert_skip_updates.txt b/tests/cli/testdata/users/users_upsert_skip_updates.txt new file mode 100644 index 00000000..7cfdc6bb --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_skip_updates.txt @@ -0,0 +1,15 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "server-user@test.edulinq.org", + "--new-role", "creator", + "--skip-updates" + ] +} +--- +server-user@test.edulinq.org + Skipped + +Processed 1 users. Encountered 0 errors. diff --git a/tests/cli/testdata/users/users_upsert_skip_updates_table.txt b/tests/cli/testdata/users/users_upsert_skip_updates_table.txt new file mode 100644 index 00000000..2cdb8bec --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_skip_updates_table.txt @@ -0,0 +1,14 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "server-user@test.edulinq.org", + "--new-role", "creator", + "--skip-updates", + "--table" + ] +} +--- +Email Added Modified Removed Skipped Not Exists Emailed Enrolled Dropped Validation Error System Error Communication Error +server-user@test.edulinq.org True diff --git a/tests/cli/testdata/users/users_upsert_val_error.txt b/tests/cli/testdata/users/users_upsert_val_error.txt new file mode 100644 index 00000000..e2ad0373 --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_val_error.txt @@ -0,0 +1,15 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "server-user@test.edulinq.org", + "--new-role", "owner" + ] +} +--- +server-user@test.edulinq.org + Validation Error + You have insufficient permissions for the requested operation. + +Processed 1 users. Encountered 1 errors. diff --git a/tests/cli/testdata/users/users_upsert_val_error_table.txt b/tests/cli/testdata/users/users_upsert_val_error_table.txt new file mode 100644 index 00000000..395a2eea --- /dev/null +++ b/tests/cli/testdata/users/users_upsert_val_error_table.txt @@ -0,0 +1,13 @@ +{ + "cli": "autograder.cli.users.upsert", + "arguments": [ + "--user", "server-admin@test.edulinq.org", + "--pass", "server-admin", + "--new-email", "server-user@test.edulinq.org", + "--new-role", "owner", + "--table" + ] +} +--- +Email Added Modified Removed Skipped Not Exists Emailed Enrolled Dropped Validation Error System Error Communication Error +server-user@test.edulinq.org You have insufficient permissions for the requested operation.