def main(args): """ The main sequence of steps :param args: The argparse args :return: """ # Authenticate logging.getLogger().info("Authenticating...") shh = workforcehelpers.get_security_handler(args) # Get the assignments feature layer logging.getLogger().info("Getting assignments feature layer...") assignment_fl = workforcehelpers.get_assignments_feature_layer(shh, args.projectId) # Get the target feature layer logging.getLogger().info("Getting target feature layer...") target_fl = arcrest.agol.FeatureLayer(args.targetFL, shh.securityhandler) # Check that the layer was loaded properly if target_fl.hasError(): logging.getLogger().critical("Error with target feature layer: {}".format(target_fl.error)) return # Open the field mappings config file logging.getLogger().info("Reading field mappings...") with open(args.configFile, 'r') as f: field_mappings = json.load(f) logging.getLogger().info("Validating field mappings...") if validate_config(field_mappings, target_fl): # Copy the assignments copy_assignments(assignment_fl, target_fl, field_mappings) logging.getLogger().info("Completed") else: logging.getLogger().critical("Invalid field mappings detected")
def main(args): """ The main sequence of steps :param args: The argparse args :return: """ # Authenticate logging.getLogger().info("Authenticating...") shh = workforcehelpers.get_security_handler(args) # Get the assignments feature layer logging.getLogger().info("Getting assignments feature layer...") assignment_fl = workforcehelpers.get_assignments_feature_layer(shh, args.projectId) # Get the target feature layer logging.getLogger().info("Getting target feature layer...") target_fl = arcrest.agol.FeatureLayer(args.targetFL, shh.securityhandler) # Check that the layer was loaded properly if target_fl.hasError(): logging.getLogger().critical("Error with target feature layer: {}".format(target_fl.error)) return # Open the field mappings config file logging.getLogger().info("Reading field mappings...") with open(args.configFile, 'r') as f: field_mappings = json.load(f) logging.getLogger().info("Validating field mappings...") if validate_config(field_mappings, target_fl): # Copy the assignments copy_assignments(assignment_fl, target_fl, field_mappings, where=args.where) logging.getLogger().info("Completed") else: logging.getLogger().critical("Invalid field mappings detected")
def validate_assignments(shh, projectId, assignments): """ Validates the provided values against the codedValues specified in the FS :param shh: The security handler helper :param projectId: The project Id :param assignments: The list of assignments to check :return: True if valid, False if not """ # Grab the item logger = logging.getLogger() assignment_fl = workforcehelpers.get_assignments_feature_layer( shh, projectId) dispatcher_fl = workforcehelpers.get_dispatchers_feature_layer( shh, projectId) statuses = [] priorities = [] assignmentTypes = [] dispatcherIds = [] # Get the dispatcherIds for dispatcher in dispatcher_fl.query().features: dispatcherIds.append(dispatcher.asDictionary["attributes"]["OBJECTID"]) # Get the codes of the domains for field in assignment_fl.fields: if field["name"] == "status": statuses = [cv["code"] for cv in field["domain"]["codedValues"]] if field["name"] == "priority": priorities = [cv["code"] for cv in field["domain"]["codedValues"]] if field["name"] == "assignmentType": assignmentTypes = [ cv["code"] for cv in field["domain"]["codedValues"] ] logger.debug("Validating assignments...") # check the values against the fields that have domains for assignment in assignments: if assignment["data"]["attributes"]["status"] not in statuses: logging.getLogger().critical( "Invalid Status for: {}".format(assignment)) return False if "priority" in assignment["data"]["attributes"] and assignment[ "data"]["attributes"]["priority"] not in priorities: logging.getLogger().critical( "Invalid Priority for: {}".format(assignment)) return False if assignment["data"]["attributes"][ "assignmentType"] not in assignmentTypes: logging.getLogger().critical( "Invalid Assignment Type for: {}".format(assignment)) return False if assignment["data"]["attributes"][ "dispatcherId"] not in dispatcherIds: logging.getLogger().critical( "Invalid Dispatcher Id for: {}".format(assignment)) return False return True
def main(args): logging.getLogger().info("Authenticating...") shh = workforcehelpers.get_security_handler(args) logging.getLogger().info("Getting assignment feature layer...") assignment_fl = workforcehelpers.get_assignments_feature_layer(shh, args.projectId) logging.getLogger().info("Deleting assignments...") response = assignment_fl.deleteFeatures(objectIds=",".join(args.objectIDs), where=args.where) logging.getLogger().info(response) logging.getLogger().info("Completed")
def main(args): logging.getLogger().info("Authenticating...") shh = workforcehelpers.get_security_handler(args) logging.getLogger().info("Getting assignment feature layer...") assignment_fl = workforcehelpers.get_assignments_feature_layer( shh, args.projectId) logging.getLogger().info("Deleting assignments...") response = assignment_fl.deleteFeatures(objectIds=",".join(args.objectIDs), where=args.where) logging.getLogger().info(response) logging.getLogger().info("Completed")
def add_attachments(shh, projectId, assignments): """ Add attachments to the assignments that were added :param shh: The security handler helper :param projectId: The project Id of the workforce project :param assignments: The list of assignments (dictionaries) :return: """ assignment_fl = workforcehelpers.get_assignments_feature_layer(shh, projectId) logging.getLogger().debug("Adding Attachments...") for assignment in assignments: if assignment["attachmentFile"] and assignment["attachmentFile"] != "": response = assignment_fl.addAttachment(assignment["OBJECTID"], os.path.abspath(assignment["attachmentFile"])) logging.getLogger().info(response)
def validate_assignments(shh, projectId, assignments): """ Validates the provided values against the codedValues specified in the FS :param shh: The security handler helper :param projectId: The project Id :param assignments: The list of assignments to check :return: True if valid, False if not """ # Grab the item logger = logging.getLogger() assignment_fl = workforcehelpers.get_assignments_feature_layer(shh, projectId) dispatcher_fl = workforcehelpers.get_dispatchers_feature_layer(shh, projectId) statuses = [] priorities = [] assignmentTypes = [] dispatcherIds = [] # Get the dispatcherIds for dispatcher in dispatcher_fl.query().features: dispatcherIds.append(dispatcher.asDictionary["attributes"]["OBJECTID"]) # Get the codes of the domains for field in assignment_fl.fields: if field["name"] == "status": statuses = [cv["code"] for cv in field["domain"]["codedValues"]] if field["name"] == "priority": priorities = [cv["code"] for cv in field["domain"]["codedValues"]] if field["name"] == "assignmentType": assignmentTypes = [cv["code"] for cv in field["domain"]["codedValues"]] logger.debug("Validating assignments...") # check the values against the fields that have domains for assignment in assignments: if assignment["data"]["attributes"]["status"] not in statuses: logging.getLogger().critical("Invalid Status for: {}".format(assignment)) return False if "priority" in assignment["data"]["attributes"] and assignment["data"]["attributes"][ "priority"] not in priorities: logging.getLogger().critical("Invalid Priority for: {}".format(assignment)) return False if assignment["data"]["attributes"]["assignmentType"] not in assignmentTypes: logging.getLogger().critical("Invalid Assignment Type for: {}".format(assignment)) return False if assignment["data"]["attributes"]["dispatcherId"] not in dispatcherIds: logging.getLogger().critical("Invalid Dispatcher Id for: {}".format(assignment)) return False return True
def main(args): # First step is to authenticate and get a valid token logging.getLogger().info("Authenticating...") shh = workforcehelpers.get_security_handler(args) # Get the assignment feature layer logging.getLogger().info("Getting assignment feature layer...") assignment_fl = workforcehelpers.get_assignments_feature_layer( shh, args.projectId) # Query the assignment feature layer to get certain assignments logging.getLogger().info("Querying assignments...") assignments = assignment_fl.query(where=args.where, out_fields="*", outSR=args.outSR).features # Write the assignments to the csv file logging.getLogger().info("Writing to CSV...") write_assignments_to_csv(args.outCSV, assignments, args.dateFormat) logging.getLogger().info("Completed")
def main(args): """ The main sequence of steps :type args: object :param args: The argparse args :return: """ # Authenticate logging.getLogger().info("Authenticating...") shh = workforcehelpers.get_security_handler(args) # Get the target feature layer logging.getLogger().info("Getting target feature layer...") target_fl = arcrest.agol.FeatureLayer(args.targetFL, shh.securityhandler) # Check that the layer was loaded properly if target_fl.hasError(): logging.getLogger().critical("Error with target feature layer: {}".format(target_fl.error)) return logging.getLogger().info("Getting assignments feature layer...") assignment_fl = workforcehelpers.get_assignments_feature_layer(shh, args.projectId) # if a specific workers weren't specified, let's use all workers if not args.workers: features = workforcehelpers.get_workers_feature_layer(shh, args.projectId).query(where="1=1").features workers = [feature.asDictionary["attributes"]["userId"] for feature in features] else: workers = args.workers # Open the field mappings config file logging.getLogger().info("Reading field mappings...") with open(args.configFile, 'r') as f: field_mappings = json.load(f) # Check the mapping to the target feature service is valid logging.getLogger().info("Validating field mappings...") if validate_config(field_mappings, target_fl): for worker in workers: # Get the query string that represents the invalid assignment completions query_string = get_invalid_completions(shh, args.projectId, worker, args.timeTol, args.distTol, args.minAccuracy) # Use that query to copy the assignments to feature service (if they don't already exist) copy_assignments(assignment_fl, target_fl, field_mappings, where=query_string) else: logging.getLogger().critical("Invalid field mappings detected") return
def add_assignments(shh, projectId, assignments): """ Adds the assignments to project :param shh: The security handler helper :param projectId: The project Id :param assignments: The list of assignments to add :return: The json response of the addFeatures REST API Call """ logger = logging.getLogger() assignment_fl = workforcehelpers.get_assignments_feature_layer(shh, projectId) features = [arcrest.common.general.Feature(x["data"]) for x in assignments] logger.debug("Adding Assignments...") response = assignment_fl.addFeature(features) logger.debug(response) # Assign the returned object ids to the assignment dictionary object for i in range(len(response["addResults"])): assignments[i]["OBJECTID"] = response["addResults"][i]["objectId"] # Add the attachments if len(assignments) > 0 and "attachmentFile" in assignments[0]: add_attachments(shh, projectId, assignments) return response
def get_invalid_completions(shh, projectId, worker, time_tolerance, distance_tolerance, min_accuracy): """ Generates a query string that represents the assignments that were completed either outside of the specified time window or outside of the specified distance :param shh: The ArcREST security handler helper :param projectID: The projectId to use :param worker: (string) The userId (name) of the worker to use :param time_tolerance: (int) The number of minutes to use as a tolerance :param distance_tolerance: (float or int) The distance tolerance to use :param min_accuracy: (int or float) The minimum accuracy to require when querying points :return: (string) A query that uses the OBJECTID to identify invalid assignment completions """ logging.getLogger().info("Getting assignments feature layer...") assignment_fl = workforcehelpers.get_assignments_feature_layer(shh, projectId) # Get the locations feature layer logging.getLogger().info("Getting location feature layer...") location_fl = workforcehelpers.get_location_feature_layer(shh, projectId) # Get workerId logging.getLogger().info("Getting workerId for {}".format(worker)) worker_id = get_worker_id(shh, projectId, worker) if not worker_id: logging.critical("Invalid worker detected") return # Get the completed assignments by the specified worker completed_assignments = assignment_fl.query( where="workerId = {} AND completedDate is not NULL".format(worker_id)).features invalid_assignment_oids = [] # Iterate over the assignments and check to see if they were completed within the specified distance for assignment in completed_assignments: # The coordinates of the assignment start_coords = (assignment.asDictionary["geometry"]["x"], assignment.asDictionary["geometry"]["y"]) # When the assignment was completed completion_date = datetime.datetime.utcfromtimestamp( int(assignment.asDictionary["attributes"]["completedDate"])/1000) # Add/Subtract some minutes to give a little leeway start_date = completion_date - datetime.timedelta(minutes=time_tolerance) end_date = completion_date + datetime.timedelta(minutes=time_tolerance) # Make a query string to select location by the worker during the time period loc_query_string = "Editor = '{}' AND CreationDate >= '{}' AND CreationDate <= '{}' AND Accuracy <= {}"\ .format(worker, start_date.strftime('%Y-%m-%d %H:%M:%S'), end_date.strftime('%Y-%m-%d %H:%M:%S'), min_accuracy) # Query the feature layer locations_to_check = location_fl.query(where=loc_query_string).features # Bool to see if this assignment is valid or not is_valid=False for location in locations_to_check: # Make a list of coordinate pairs to get the distance of coords = [] # If we include the accuracy, we need to make four variations (+- the accuracy) accuracy = float(location.asDictionary["attributes"]["Accuracy"]) coords.append((location.asDictionary["geometry"]["x"]+accuracy, location.asDictionary["geometry"]["y"]+accuracy)) coords.append((location.asDictionary["geometry"]["x"]+accuracy, location.asDictionary["geometry"]["y"]-accuracy)) coords.append((location.asDictionary["geometry"]["x"]-accuracy, location.asDictionary["geometry"]["y"]+accuracy)) coords.append((location.asDictionary["geometry"]["x"]-accuracy, location.asDictionary["geometry"]["y"]-accuracy)) distances = [get_simple_distance(start_coords, coordinates) for coordinates in coords] # if any of the distances is less than the threshold then this assignment is valid if any(distance < distance_tolerance for distance in distances): is_valid = True break # if it's not valid add the OBJECTID to the list of invalid assignment OBJECTIDS if not is_valid: logging.debug("Location Query: {}".format(loc_query_string)) invalid_assignment_oids.append(str(assignment.asDictionary["attributes"]["OBJECTID"])) if invalid_assignment_oids: return "OBJECTID in ({})".format(",".join(invalid_assignment_oids)) else: logging.getLogger().info( "All assignments were completed within the specified time and distance. Nothing to copy.") return "1=0"