def validator(request): """Respond to the "/validator" URL. """ if not request.user.is_authenticated: return HttpResponseRedirect(reverse(settings.ADMIN_HOME_VIEW)) # Display a "please wait" message while waiting for the results to be # calculated. if not pleasewait.shown(request): return pleasewait.message(request, "Whenua Admin", "Polygon Validator", "Validating location outlines, " + "please wait...") # Process each outline in turn. bad_locs = [] for i,outline in enumerate(Outline.objects.all()): if i % 100 == 0: print " %d" % i loc = outline.location mpoly = outline.outline if mpoly == None: continue if is_geometry_valid(mpoly): continue fixed_polygon = fix_geometry(mpoly) if fixed_polygon != None: mpoly = wrap_geometry(fixed_polygon) if mpoly != None: outline.outline = mpoly outline.save() status = "Fixed" else: status = "Unable to fix" bad_locs.append({'level' : loc.level.name, 'code' : loc.code, 'name' : loc.name, 'status' : status}) # Finally, show the user the results of the validation. return render_to_response( "polygon_editor/templates/validation_results.html", {'bad_locs' : bad_locs}, context_instance=RequestContext(request))
def check(request): """ Respond to the "/check" URL. We display a "please wait" message while performing the sanity check, and then finally display the results back to the caller. """ if not request.user.is_authenticated: return HttpResponseRedirect(reverse(settings.ADMIN_HOME_VIEW)) # Display a "please wait" message while waiting for the results to be # calculated. if not pleasewait.shown(request): return pleasewait.message(request, "Whenua Admin", "Location Sanity-Checker", "Checking locations, please wait...") # Get a connection to our database. cursor = connections['geo_shared'].cursor() # Load the list of Level records into memory. levelIDToNumber = {} # Maps Level record ID to level number. levelNumberToName = {} # Maps Level number to name. for level in Level.objects.all(): levelIDToNumber[level.id] = level.level levelNumberToName[level.level] = level.name # Load the list of Location records into memory. locations = {} # Maps record ID to a (code, level_num, name, display_name) # tuple. cursor.execute("SELECT id,code,level_id,name,display_name " + "FROM shared_location") row = cursor.fetchone() while row != None: id,code,level_id,name,display_name = row level_num = levelIDToNumber[level_id] locations[id] = (code, level_num, name, display_name) row = cursor.fetchone() # Load the list of location parents into memory. location_parents = {} # Maps record ID to a set of parent record IDs. cursor.execute("SELECT from_location_id,to_location_id " + "FROM shared_location_parents") row = cursor.fetchone() while row != None: from_loc_id,to_loc_id = row try: location_parents[from_loc_id].add(to_loc_id) except KeyError: location_parents[from_loc_id] = set([to_loc_id]) row = cursor.fetchone() # Load the list of location children into memory. location_children = {} # Maps record ID to set of child record IDs. cursor.execute("SELECT from_location_id,to_location_id " + "FROM shared_location_children") row = cursor.fetchone() while row != None: from_loc_id,to_loc_id = row try: location_children[from_loc_id].add(to_loc_id) except KeyError: location_children[from_loc_id] = set([to_loc_id]) row = cursor.fetchone() # Load the list of location neighbours into memory. location_neighbours = {} # Maps record ID to set of neighbour record IDs. cursor.execute("SELECT from_location_id,to_location_id " + "FROM shared_location_neighbors") row = cursor.fetchone() while row != None: from_loc_id,to_loc_id = row try: location_neighbours[from_loc_id].add(to_loc_id) except KeyError: location_neighbours[from_loc_id] = set([to_loc_id]) row = cursor.fetchone() # Load the list of names into memory. names = {} # Maps record ID to name. cursor.execute("SELECT id,name FROM shared_name") row = cursor.fetchone() while row != None: id,name = row names[id] = name row = cursor.fetchone() # Load the list of names used by each location into memory. location_names = {} # Maps location record ID to set of name record IDs. cursor.execute("select location_id,name_id FROM shared_locationname") row = cursor.fetchone() while row != None: loc_id,name_id = row try: location_names[loc_id].add(name_id) except KeyError: location_names[loc_id] = set([name_id]) row = cursor.fetchone() # Now that we've got all the information we need in memory, start looking # for potentially bad locations. bad_locs = [] # List of potentially bad locations. Each list item is a # dictionary with the following entries: # # 'code' # # The location's code. # # 'level' # # A descriptive name for this location's level # # 'name' # # The name for this location. # # 'problem' # # A string describing what was wrong with the # location. # Find any locations that aren't countries and lack parents. for loc_id in locations.keys(): level_num = locations[loc_id][1] if level_num == 1: continue # ignore countries. if len(location_parents.get(loc_id, [])) == 0: # This location has no parents -> flag it as a bad location. code,level_num,name,display_name = locations[loc_id] bad_locs.append({'code' : code, 'level' : levelNumberToName[level_num], 'name' : name, 'problem' : "lacks a parent"}) # Find any locations which lack a name. for loc_id in locations.keys(): level_num = locations[loc_id][1] if level_num == 8: continue # ZIP codes don't have names. if len(location_names.get(loc_id, [])) == 0: # This location has no name -> flag it as a bad location. code,level_num,name,display_name = locations[loc_id] bad_locs.append({'code' : code, 'level' : levelNumberToName[level_num], 'name' : name, 'problem' : "has no names"}) # Find any locations which have names ending or starting with a space. bad_name_ids = set() # Set of name IDs which have bad values. for name_id,name in names.items(): badName = False if name.startswith(" "): badName = True if name.endswith(" "): badName = True if badName: bad_name_ids.add(name_id) for loc_id,name_ids_for_loc in location_names.items(): for bad_name_id in name_ids_for_loc.intersection(bad_name_ids): code,level_num,name,display_name = locations[loc_id] bad_name = names[bad_name_id] bad_locs.append({'code' : code, 'level' : levelNumberToName[level_num], 'name' : name, 'problem' : "has a name (" + bad_name + ") " + "starting or ending with a space"}) # Find any locations which have been "disowned" by their parents. That is, # location A lists location B as a parent, but location B doesn't list # location A as a child. for loc_id in locations.keys(): if loc_id not in location_parents: continue # No parents. for parent_id in location_parents[loc_id]: disowned = False if parent_id not in location_children: disowned = True elif loc_id not in location_children[parent_id]: disowned = True if disowned: code,level_num,name,display_name = locations[loc_id] parent_code = locations[parent_id][0] parent_name = locations[parent_id][2] bad_locs.append({'code' : code, 'level' : levelNumberToName[level_num], 'name' : name, 'problem' : "has been disowned by parent " + parent_name+" ("+parent_code+")", }) # Find any locations which have been "disowned" by their children. That # is, location A lists location B as a child, but location B doesn't list # location A as a parent. for loc_id in locations.keys(): if loc_id not in location_children: continue # No children. for child_id in location_children[loc_id]: disowned = False if child_id not in location_parents: disowned = True elif loc_id not in location_parents[child_id]: disowned = True if disowned: code,level_num,name,display_name = locations[loc_id] child_code = locations[child_id][0] child_name = locations[child_id][2] bad_locs.append({'code' : code, 'level' : levelNumberToName[level_num], 'name' : name, 'problem' : "has been disowned by child " + child_name+" ("+child_code+")", }) # Find any locations which are "disowned" by their neighbours. That is, # location A lists location B as a neighbour, but location B doesn't list # location A as a neighbour. for loc_id in locations.keys(): if loc_id not in location_neighbours: continue # No neighbours. for neighbour_id in location_neighbours[loc_id]: disowned = False if neighbour_id not in location_neighbours: disowned = True elif loc_id not in location_neighbours[neighbour_id]: disowned = True if disowned: code,level_num,name,display_name = locations[loc_id] neighbour_code = locations[neighbour_id][0] neighbour_name = locations[neighbour_id][2] bad_locs.append({'code' : code, 'level' : levelNumberToName[level_num], 'name' : name, 'problem' : "has been disowned by neighbor " + neighbour_name + " (" + neighbour_code + ")", }) # Find any locations which lack a default tableau. cursor.execute("SELECT id FROM shared_location WHERE NOT EXISTS (" + "SELECT * FROM shared_tableau WHERE shared_location.id=" + "shared_tableau.location_id AND shared_tableau.name=" + '"DEFAULT")') row = cursor.fetchone() while row != None: loc_id = row[0] code,level_num,name,display_name = locations[loc_id] bad_locs.append({'code' : code, 'level' : levelNumberToName[level_num], 'name' : name, 'problem' : "is missing a default tableau"}) row = cursor.fetchone() # Finally, display the potentially-bad locations to the user. admin_home_url = reverse(settings.ADMIN_HOME_VIEW) menu_html = menus.generate(request, "sanity_checker", "main") return render_to_response("sanity_checker/templates/results.html", {'menu_html' : menu_html, 'bad_locs' : bad_locs, 'admin_home_url' : admin_home_url}, context_instance=RequestContext(request))
def fix_disowned(request): """ Respond to the "/fixdisowned" URL. We fix any "disowned" locations -- locations where the parent/child, child/parent, or neighbour/neighbour relations aren't symmetrical. In particular: * If a location has a parent which doesn't list the locaiton as a child, a child entry will be added to the parent. * If a location has a child which doesn't list the location as a parent, a parent entry will be added to the child. * If a location has a neighbour which doesn't list the location as a neighbour, a neighbour entry will be added to the neighbour. """ # Display a "please wait" message while we work. if not pleasewait.shown(request): return pleasewait.message(request, "Whenua Admin", "Location Sanity-Checker", "Fixing disowned locations, please wait...") # Get a connection to our database. cursor = connections['geo_shared'].cursor() # Load the list of Level records into memory. levelIDToNumber = {} # Maps Level record ID to level number. for level in Level.objects.all(): levelIDToNumber[level.id] = level.level # Load the list of Location records into memory. locations = {} # Maps record ID to a (code, level_num, name, display_name) # tuple. cursor.execute("SELECT id,code,level_id,name,display_name " + "FROM shared_location") row = cursor.fetchone() while row != None: id,code,level_id,name,display_name = row level_num = levelIDToNumber[level_id] locations[id] = (code, level_num, name, display_name) row = cursor.fetchone() # Load the list of location parents into memory. location_parents = {} # Maps record ID to a set of parent record IDs. cursor.execute("SELECT from_location_id,to_location_id " + "FROM shared_location_parents") row = cursor.fetchone() while row != None: from_loc_id,to_loc_id = row try: location_parents[from_loc_id].add(to_loc_id) except KeyError: location_parents[from_loc_id] = set([to_loc_id]) row = cursor.fetchone() # Load the list of location children into memory. location_children = {} # Maps record ID to set of child record IDs. cursor.execute("SELECT from_location_id,to_location_id " + "FROM shared_location_children") row = cursor.fetchone() while row != None: from_loc_id,to_loc_id = row try: location_children[from_loc_id].add(to_loc_id) except KeyError: location_children[from_loc_id] = set([to_loc_id]) row = cursor.fetchone() # Load the list of location neighbours into memory. location_neighbours = {} # Maps record ID to set of neighbour record IDs. cursor.execute("SELECT from_location_id,to_location_id " + "FROM shared_location_neighbors") row = cursor.fetchone() while row != None: from_loc_id,to_loc_id = row try: location_neighbours[from_loc_id].add(to_loc_id) except KeyError: location_neighbours[from_loc_id] = set([to_loc_id]) row = cursor.fetchone() # Fix any locations which have been "disowned" by their parents. That is, # location A lists location B as a parent, but location B doesn't list # location A as a child. num_parents_fixed = 0 for loc_id in locations.keys(): if loc_id not in location_parents: continue # No parents. for parent_id in location_parents[loc_id]: disowned = False if parent_id not in location_children: disowned = True elif loc_id not in location_children[parent_id]: disowned = True if disowned: location = Location.objects.get(id=loc_id) parent = Location.objects.get(id=parent_id) parent.children.add(location) num_parents_fixed = num_parents_fixed + 1 # Fix any locations which have been "disowned" by their children. That is, # location A lists location B as a child, but location B doesn't list # location A as a parent. num_children_fixed = 0 for loc_id in locations.keys(): if loc_id not in location_children: continue # No children. for child_id in location_children[loc_id]: disowned = False if child_id not in location_parents: disowned = True elif loc_id not in location_parents[child_id]: disowned = True if disowned: location = Location.objects.get(id=loc_id) child = Location.objects.get(id=child_id) child.parents.add(location) num_children_fixed = num_children_fixed + 1 # Fix any locations which are "disowned" by their neighbours. That is, # location A lists location B as a neighbour, but location B doesn't list # location A as a neighbour. num_neighbours_fixed = 0 for loc_id in locations.keys(): if loc_id not in location_neighbours: continue # No neighbours. for neighbour_id in location_neighbours[loc_id]: disowned = False if neighbour_id not in location_neighbours: disowned = True elif loc_id not in location_neighbours[neighbour_id]: disowned = True if disowned: location = Location.objects.get(id=loc_id) neighbour = Location.objects.get(id=neighbour_id) neighbour.neighbors.add(location) num_neighbours_fixed = num_neighbours_fixed + 1 # Finally, tell the user the results. admin_home_url = reverse(settings.ADMIN_HOME_VIEW) menu_html = menus.generate(request, "sanity_checker", "main") return render_to_response("sanity_checker/templates/disowned_fixed.html", {'menu_html' : menu_html, 'num_parents_fixed' : num_parents_fixed, 'num_children_fixed' : num_children_fixed, 'num_neighbours_fixed' : num_neighbours_fixed, 'admin_home_url' : admin_home_url}, context_instance=RequestContext(request))