def get_user_details(user_name, options, prompt_prefix): """ Get user details (email, first name, last name) Returns a dictionary of user details, including the supplied user_name. """ user_email_regex = r"^[A-Za-z0-9.+_-]+@([A-Za-z0-9_-]+)(\.[A-Za-z0-9_-]+)*$" user_email_prompt = "%s email: " % prompt_prefix user_first_name_prompt = "%s first name: " % prompt_prefix user_last_name_prompt = "%s last name: " % prompt_prefix # Get other values user_email = getargvalue(getarg(options.args, 1), user_email_prompt) while not re.match(user_email_regex, user_email): print("Invalid email address %s - re-enter" % user_email, file=sys.stderr) user_email = getargvalue(None, user_email_prompt) user_first_name = getargvalue(getarg(options.args, 2), user_first_name_prompt) user_last_name = getargvalue(getarg(options.args, 3), user_last_name_prompt) return ({ 'name': user_name, 'email': user_email, 'uri': "mailto:%s" % user_email, 'first_name': user_first_name, 'last_name': user_last_name })
def am_migratecollection(annroot, userhome, options): """ Apply migrations for a specified collection annalist_manager migratecollection coll Reads and writes every entity in a collection, thereby applying data migrations and saving them in the stored data. annroot is the root directory for the Annalist software installation. userhome is the home directory for the host system user issuing the command. options contains options parsed from the command line. returns 0 if all is well, or a non-zero status code. This value is intended to be used as an exit status code for the calling program. """ status, settings, site = get_settings_site(annroot, userhome, options) if status != am_errors.AM_SUCCESS: return status coll_id = getargvalue(getarg(options.args, 0), "Collection Id: ") coll = Collection.load(site, coll_id) if not (coll and coll.get_values()): print("Collection not found: %s" % (coll_id), file=sys.stderr) return am_errors.AM_NOCOLLECTION status = am_errors.AM_SUCCESS print("Apply data migrations in collection '%s'" % (coll_id, )) msgs = migrate_coll_data(coll) if msgs: for msg in msgs: print(msg) status = am_errors.AM_MIGRATECOLLFAIL return status
def am_migratecollection(annroot, userhome, options): """ Apply migrations for a specified collection annalist_manager migratecollection coll Reads and writes every entity in a collection, thereby applying data migrations and saving them in the stored data. annroot is the root directory for the Annalist software installation. userhome is the home directory for the host system user issuing the command. options contains options parsed from the command line. returns 0 if all is well, or a non-zero status code. This value is intended to be used as an exit status code for the calling program. """ status, settings, site = get_settings_site(annroot, userhome, options) if status != am_errors.AM_SUCCESS: return status coll_id = getargvalue(getarg(options.args, 0), "Collection Id: ") coll = Collection.load(site, coll_id) if not (coll and coll.get_values()): print("Collection not found: %s"%(coll_id), file=sys.stderr) return am_errors.AM_NOCOLLECTION status = am_errors.AM_SUCCESS print("Apply data migrations in collection '%s'"%(coll_id,)) msgs = migrate_coll_data(coll) if msgs: for msg in msgs: print(msg) status = am_errors.AM_MIGRATECOLLFAIL return status
def get_user_name(options, prompt_prefix): user_name_regex = r"^[a-zA-Z0-9@.+_-]+$" user_name_prompt = "%s name: "%prompt_prefix user_name = getargvalue(getarg(options.args, 0), user_name_prompt) while not re.match(user_name_regex, user_name): print("Invalid username %s - re-enter"%user_name, file=sys.stderr) user_name = getargvalue(None, user_name_prompt) return user_name
def am_copycollection(annroot, userhome, options): """ Copy collection data annalist_manager copycollection old_coll_id new_coll_id Copies data from an existing collection to a new collection. annroot is the root directory for the Annalist software installation. userhome is the home directory for the host system user issuing the command. options contains options parsed from the command line. returns 0 if all is well, or a non-zero status code. This value is intended to be used as an exit status code for the calling program. """ status, settings, site = get_settings_site(annroot, userhome, options) if status != am_errors.AM_SUCCESS: return status if len(options.args) > 2: print( "Unexpected arguments for %s: (%s)"% (options.command, " ".join(options.args)), file=sys.stderr ) return am_errors.AM_UNEXPECTEDARGS old_coll_id = getargvalue(getarg(options.args, 0), "Old collection Id: ") old_coll = Collection.load(site, old_coll_id) if not (old_coll and old_coll.get_values()): print("Old collection not found: %s"%(old_coll_id), file=sys.stderr) return am_errors.AM_NOCOLLECTION new_coll_id = getargvalue(getarg(options.args, 1), "New collection Id: ") new_coll = Collection.load(site, new_coll_id) if (new_coll and new_coll.get_values()): print("New collection already exists: %s"%(new_coll_id), file=sys.stderr) return am_errors.AM_COLLECTIONEXISTS # Copy collection now print("Copying collection '%s' to '%s'"%(old_coll_id, new_coll_id)) new_coll = site.add_collection(new_coll_id, old_coll.get_values()) msgs = copy_coll_data(old_coll, new_coll) if msgs: for msg in msgs: print(msg) status = am_errors.AM_COPYCOLLFAIL print("") return status
def am_copycollection(annroot, userhome, options): """ Copy collection data annalist_manager copycollection old_coll_id new_coll_id Copies data from an existing collection to a new collection. annroot is the root directory for the Annalist software installation. userhome is the home directory for the host system user issuing the command. options contains options parsed from the command line. returns 0 if all is well, or a non-zero status code. This value is intended to be used as an exit status code for the calling program. """ status, settings, site = get_settings_site(annroot, userhome, options) if status != am_errors.AM_SUCCESS: return status if len(options.args) > 2: print("Unexpected arguments for %s: (%s)" % (options.command, " ".join(options.args)), file=sys.stderr) return am_errors.AM_UNEXPECTEDARGS old_coll_id = getargvalue(getarg(options.args, 0), "Old collection Id: ") old_coll = Collection.load(site, old_coll_id) if not (old_coll and old_coll.get_values()): print("Old collection not found: %s" % (old_coll_id), file=sys.stderr) return am_errors.AM_NOCOLLECTION new_coll_id = getargvalue(getarg(options.args, 1), "New collection Id: ") new_coll = Collection.load(site, new_coll_id) if (new_coll and new_coll.get_values()): print("New collection already exists: %s" % (new_coll_id), file=sys.stderr) return am_errors.AM_COLLECTIONEXISTS # Copy collection now print("Copying collection '%s' to '%s'" % (old_coll_id, new_coll_id)) new_coll = site.add_collection(new_coll_id, old_coll.get_values()) msgs = copy_coll_data(old_coll, new_coll) if msgs: for msg in msgs: print(msg) status = am_errors.AM_COPYCOLLFAIL print("") return status
def am_installcollection(annroot, userhome, options): """ Install software-defined collection data annalist_manager installcollection coll_id Copies data from an existing collection to a new collection. annroot is the root directory for the Annalist software installation. userhome is the home directory for the host system user issuing the command. options contains options parsed from the command line. returns 0 if all is well, or a non-zero status code. This value is intended to be used as an exit status code for the calling program. """ status, settings, site = get_settings_site(annroot, userhome, options) if status != am_errors.AM_SUCCESS: return status if len(options.args) > 1: print("Unexpected arguments for %s: (%s)" % (options.command, " ".join(options.args)), file=sys.stderr) return am_errors.AM_UNEXPECTEDARGS coll_id = getargvalue(getarg(options.args, 0), "Collection Id to install: ") coll = Collection.load(site, coll_id) if (coll and coll.get_values()): print("Collection already exists: %s" % (coll_id), file=sys.stderr) return am_errors.AM_COLLECTIONEXISTS # Check collection Id if coll_id in installable_collections: src_dir_name = installable_collections[coll_id]['data_dir'] else: print("Collection name to install not known: %s" % (coll_id), file=sys.stderr) print("Available collection Ids are: %s" % (",".join(installable_collections.keys()))) return am_errors.AM_NOCOLLECTION # Install collection now src_dir = os.path.join(annroot, "annalist/data", src_dir_name) print("Installing collection '%s' from data directory '%s'" % (coll_id, src_dir)) coll_metadata = installable_collections[coll_id]['coll_meta'] date_time_now = datetime.datetime.now().replace(microsecond=0) coll_metadata[ANNAL.CURIE.comment] = ( "Initialized at %s by `annalist-manager installcollection`" % date_time_now.isoformat()) coll = site.add_collection(coll_id, coll_metadata) msgs = initialize_coll_data(src_dir, coll) if msgs: for msg in msgs: print(msg) status = am_errors.AM_INSTALLCOLLFAIL return status
def am_installcollection(annroot, userhome, options): """ Install software-defined collection data annalist_manager installcollection coll_id Copies data from an existing collection to a new collection. annroot is the root directory for the Annalist software installation. userhome is the home directory for the host system user issuing the command. options contains options parsed from the command line. returns 0 if all is well, or a non-zero status code. This value is intended to be used as an exit status code for the calling program. """ status, settings, site = get_settings_site(annroot, userhome, options) if status != am_errors.AM_SUCCESS: return status if len(options.args) > 1: print( "Unexpected arguments for %s: (%s)"% (options.command, " ".join(options.args)), file=sys.stderr ) return am_errors.AM_UNEXPECTEDARGS coll_id = getargvalue(getarg(options.args, 0), "Collection Id to install: ") coll = Collection.load(site, coll_id) if (coll and coll.get_values()): print("Collection already exists: %s"%(coll_id), file=sys.stderr) return am_errors.AM_COLLECTIONEXISTS # Check collection Id if coll_id in installable_collections: src_dir_name = installable_collections[coll_id]['data_dir'] else: print("Collection name to install not known: %s"%(coll_id), file=sys.stderr) print("Available collection Ids are: %s"%(",".join(installable_collections.keys()))) return am_errors.AM_NOCOLLECTION # Install collection now src_dir = os.path.join(annroot, "annalist/data", src_dir_name) print("Installing collection '%s' from data directory '%s'"%(coll_id, src_dir)) coll_metadata = installable_collections[coll_id]['coll_meta'] date_time_now = datetime.datetime.now().replace(microsecond=0) coll_metadata[ANNAL.CURIE.comment] = ( "Initialized at %s by `annalist-manager installcollection`"% date_time_now.isoformat() ) coll = site.add_collection(coll_id, coll_metadata) msgs = initialize_coll_data(src_dir, coll) if msgs: for msg in msgs: print(msg) status = am_errors.AM_INSTALLCOLLFAIL return status
def get_user_permissions(options, pos, prompt_prefix): """ Get user permissions to apply """ user_permissions_regex = r"^([A-Za-z0-9_-]+(\s+[A-Za-z0-9_-]+)*)?$" user_permissions_prompt = "%s permissions: "%prompt_prefix user_permissions = getargvalue(getarg(options.args, pos), user_permissions_prompt) while not re.match(user_permissions_regex, user_permissions): print("Invalid permissions %s - re-enter"%user_permissions, file=sys.stderr) user_permissions = getargvalue(None, user_permissions_prompt) return user_permissions
def get_user_details(user_name, options, prompt_prefix): """ Get user details (email, first name, last name) Returns a dictionary of user details, including the supplied user_name. """ user_email_regex = r"^[A-Za-z0-9.+_-]+@([A-Za-z0-9_-]+)(\.[A-Za-z0-9_-]+)*$" user_email_prompt = "%s email: "%prompt_prefix user_first_name_prompt = "%s first name: "%prompt_prefix user_last_name_prompt = "%s last name: "%prompt_prefix # Get other values user_email = getargvalue(getarg(options.args, 1), user_email_prompt) while not re.match(user_email_regex, user_email): print("Invalid email address %s - re-enter"%user_email, file=sys.stderr) user_email = getargvalue(None, user_email_prompt) user_first_name = getargvalue(getarg(options.args, 2), user_first_name_prompt) user_last_name = getargvalue(getarg(options.args, 3), user_last_name_prompt) return ( { 'name': user_name , 'email': user_email , 'uri': "mailto:%s"%user_email , 'first_name': user_first_name , 'last_name': user_last_name })
def am_runtests(annroot, options): """ Run Annalist server tests. annroot is the root directory for the annalist software installation. options contains options parsed from the command line. returns 0 if all is well, or a non-zero status code. This value is intended to be used as an exit status code for the calling program. """ options.configuration = "runtests" testsettings = am_get_settings(annroot, "/nouser/", options) if not testsettings: print("Settings not found (%s)" % ("runtests"), file=sys.stderr) return am_errors.AM_NOSETTINGS if len(options.args) > 1: print("Unexpected arguments for %s: (%s)" % (options.command, " ".join(options.args)), file=sys.stderr) return am_errors.AM_UNEXPECTEDARGS status = am_errors.AM_SUCCESS log.debug("annalist_root: %s" % (annroot)) with ChangeCurrentDir(annroot): # For some reason, tests are not discovered unless run from here cmd = "test" testname = getarg(options.args, 0) or "" subprocess_command = ( "django-admin %s %s --pythonpath=%s --settings=%s --top-level-directory=%s" % (cmd, testname, annroot, testsettings.modulename, annroot)) log.debug("am_initialize subprocess: %s" % subprocess_command) # OLD: status = os.system(subprocess_command) status = subprocess.call(subprocess_command.split()) log.debug("am_initialize subprocess status: %s" % status) if testname: print("Log file name:\n%s" % (annroot + "/annalist.log")) return status
def am_migrationreport(annroot, userhome, options): """ Collection migration report helper annalist_manager migrationreport old_coll new_coll Generates a report of changes to data needed to match type and property URI changes moving from old_coll to new_coll. annroot is the root directory for the Annalist software installation. userhome is the home directory for the host system user issuing the command. options contains options parsed from the command line. returns 0 if all is well, or a non-zero status code. This value is intended to be used as an exit status code for the calling program. """ status, settings, site = get_settings_site(annroot, userhome, options) if status != am_errors.AM_SUCCESS: return status if len(options.args) > 2: print("Unexpected arguments for %s: (%s)" % (options.command, " ".join(options.args)), file=sys.stderr) return am_errors.AM_UNEXPECTEDARGS old_coll_id = getargvalue(getarg(options.args, 0), "Old collection Id: ") old_coll = Collection.load(site, old_coll_id) if not (old_coll and old_coll.get_values()): print("Old collection not found: %s" % (old_coll_id), file=sys.stderr) return am_errors.AM_NOCOLLECTION new_coll_id = getargvalue(getarg(options.args, 1), "New collection Id: ") new_coll = Collection.load(site, new_coll_id) if not (new_coll and new_coll.get_values()): print("New collection not found: %s" % (new_coll_id), file=sys.stderr) return am_errors.AM_NOCOLLECTION status = am_errors.AM_SUCCESS print("# Migration report from collection '%s' to '%s' #" % (old_coll_id, new_coll_id)) print("") # Scan and report on type URI changes for new_type in coll_types(new_coll): type_id = new_type.get_id() old_type = old_coll.get_type(type_id) if old_type: old_uri = old_type[ANNAL.CURIE.uri] new_uri = new_type[ANNAL.CURIE.uri] if old_uri != new_uri: print("* Type %s, URI changed from '%s' to '%s'" % (type_id, old_uri, new_uri)) supertype_uris = [ u[ANNAL.CURIE.supertype_uri] for u in new_type.get(ANNAL.CURIE.supertype_uris, []) ] if old_uri not in supertype_uris: print( " Consider adding supertype '%s' to type '%s' in collection '%s'" % (old_uri, type_id, new_coll_id)) report_type_references(new_coll, old_uri, " URI '%s'" % (old_uri)) # Scan and report on property URI changes in field definitions for new_field in coll_fields(new_coll): field_id = new_field.get_id() old_field = coll_field(old_coll, field_id) if old_field: old_uri = old_field[ANNAL.CURIE.property_uri] new_uri = new_field[ANNAL.CURIE.property_uri] if old_uri != new_uri: print("* Field %s, property URI changed from '%s' to '%s'" % (field_id, old_uri, new_uri)) type_ids = types_using_field(new_coll, field_id, old_uri) for tid in type_ids: print( " Consider adding property alias for '%s' to type %s in collection '%s'" % (old_uri, tid, new_coll_id)) # Scan and report on property URI changes in group definitions for new_group in coll_groups(new_coll): group_id = new_group.get_id() old_group = coll_group(old_coll, group_id) if old_group: compare_field_list(old_coll, new_coll, old_group[ANNAL.CURIE.group_fields], new_group[ANNAL.CURIE.group_fields], "Group %s" % group_id) # Scan and report on property URI changes in view definitions for new_view in coll_views(new_coll): view_id = new_view.get_id() old_view = coll_view(old_coll, view_id) if old_view: compare_field_list(old_coll, new_coll, old_view[ANNAL.CURIE.view_fields], new_view[ANNAL.CURIE.view_fields], "View %s" % view_id) # Scan and report on property URI changes in list definitions for new_list in coll_lists(new_coll): list_id = new_list.get_id() old_list = coll_list(old_coll, list_id) if old_list: compare_field_list(old_coll, new_coll, old_list[ANNAL.CURIE.list_fields], new_list[ANNAL.CURIE.list_fields], "List %s" % list_id) print("") return status
def am_migrationreport(annroot, userhome, options): """ Collection migration report helper annalist_manager migrationreport old_coll new_coll Generates a report of changes to data needed to match type and property URI changes moving from old_coll to new_coll. annroot is the root directory for the Annalist software installation. userhome is the home directory for the host system user issuing the command. options contains options parsed from the command line. returns 0 if all is well, or a non-zero status code. This value is intended to be used as an exit status code for the calling program. """ status, settings, site = get_settings_site(annroot, userhome, options) if status != am_errors.AM_SUCCESS: return status if len(options.args) > 2: print("Unexpected arguments for %s: (%s)"%(options.command, " ".join(options.args)), file=sys.stderr) return am_errors.AM_UNEXPECTEDARGS old_coll_id = getargvalue(getarg(options.args, 0), "Old collection Id: ") old_coll = Collection.load(site, old_coll_id) if not (old_coll and old_coll.get_values()): print("Old collection not found: %s"%(old_coll_id), file=sys.stderr) return am_errors.AM_NOCOLLECTION new_coll_id = getargvalue(getarg(options.args, 1), "New collection Id: ") new_coll = Collection.load(site, new_coll_id) if not (new_coll and new_coll.get_values()): print("New collection not found: %s"%(new_coll_id), file=sys.stderr) return am_errors.AM_NOCOLLECTION status = am_errors.AM_SUCCESS print("# Migration report from collection '%s' to '%s' #"%(old_coll_id, new_coll_id)) print("") # Scan and report on type URI changes for new_type in coll_types(new_coll): type_id = new_type.get_id() old_type = old_coll.get_type(type_id) if old_type: old_uri = old_type[ANNAL.CURIE.uri] new_uri = new_type[ANNAL.CURIE.uri] if old_uri != new_uri: print("* Type %s, URI changed from '%s' to '%s'"%(type_id, old_uri, new_uri)) supertype_uris = [ u[ANNAL.CURIE.supertype_uri] for u in new_type.get(ANNAL.CURIE.supertype_uris,[]) ] if old_uri not in supertype_uris: print( " Consider adding supertype '%s' to type '%s' in collection '%s'"% (old_uri, type_id, new_coll_id) ) report_type_references(new_coll, old_uri, " URI '%s'"%(old_uri)) # Scan and report on property URI changes in field definitions for new_field in coll_fields(new_coll): field_id = new_field.get_id() old_field = coll_field(old_coll, field_id) if old_field: old_uri = old_field[ANNAL.CURIE.property_uri] new_uri = new_field[ANNAL.CURIE.property_uri] if old_uri != new_uri: print("* Field %s, property URI changed from '%s' to '%s'"%(field_id, old_uri, new_uri)) type_ids = types_using_field(new_coll, field_id, old_uri) for tid in type_ids: print( " Consider adding property alias for '%s' to type %s in collection '%s'"% (old_uri, tid, new_coll_id) ) # Scan and report on property URI changes in group definitions for new_group in coll_groups(new_coll): group_id = new_group.get_id() old_group = coll_group(old_coll, group_id) if old_group: compare_field_list( old_coll, new_coll, old_group[ANNAL.CURIE.group_fields], new_group[ANNAL.CURIE.group_fields], "Group %s"%group_id) # Scan and report on property URI changes in view definitions for new_view in coll_views(new_coll): view_id = new_view.get_id() old_view = coll_view(old_coll, view_id) if old_view: compare_field_list( old_coll, new_coll, old_view[ANNAL.CURIE.view_fields], new_view[ANNAL.CURIE.view_fields], "View %s"%view_id) # Scan and report on property URI changes in list definitions for new_list in coll_lists(new_coll): list_id = new_list.get_id() old_list = coll_list(old_coll, list_id) if old_list: compare_field_list( old_coll, new_coll, old_list[ANNAL.CURIE.list_fields], new_list[ANNAL.CURIE.list_fields], "List %s"%list_id) print("") return status