def get_instance_permissions(self, resource_instance): permission_order = ["view_resourceinstance", "change_resourceinstance", "delete_resourceinstance", "no_access_to_resourceinstance"] perms = json.loads( JSONSerializer().serialize( {p.codename: p for p in get_perms_for_model(resource_instance) if p.codename != "add_resourceinstance"} ) ) ordered_perms = [] for p in permission_order: ordered_perms.append(perms[p]) identities = [ { "name": user.username, "id": user.id, "type": "user", "default_permissions": self.get_perms(user, "user", resource_instance, ordered_perms), "is_editor_or_reviewer": bool(user_is_resource_editor(user) or user_is_resource_reviewer(user)), } for user in User.objects.all() ] identities += [ { "name": group.name, "id": group.id, "type": "group", "default_permissions": self.get_perms(group, "group", resource_instance, ordered_perms), } for group in Group.objects.all() ] result = {"identities": identities} result["permissions"] = ordered_perms result["limitedaccess"] = (len(get_users_with_perms(resource_instance)) + len(get_groups_with_perms(resource_instance))) > 1 instance_creator = get_instance_creator(resource_instance) result["creatorid"] = instance_creator["creatorid"] return result
def handle_reviewer_edits(self, user, tile): if hasattr(user, "userprofile") is not True: models.UserProfile.objects.create(user=user) if user_is_resource_reviewer(user): user_id = str(user.id) if user_id in tile.provisionaledits: tile.provisionaledits.pop(user_id, None)
def get_provisional_type(request): """ Parses the provisional filter data to determine if a search results will include provisional (True) exclude provisional (False) or inlude only provisional 'only provisional' """ result = False provisional_filter = JSONDeserializer().deserialize( request.GET.get("provisional-filter", "[]")) user_is_reviewer = user_is_resource_reviewer(request.user) if user_is_reviewer is not False: if len(provisional_filter) == 0: result = True else: inverted = provisional_filter[0]["inverted"] if provisional_filter[0]["provisionaltype"] == "Provisional": if inverted is False: result = "only provisional" else: result = False if provisional_filter[0]["provisionaltype"] == "Authoritative": if inverted is False: result = False else: result = "only provisional" return result
def delete(self, *args, **kwargs): se = SearchEngineFactory().create() request = kwargs.pop("request", None) provisional_edit_log_details = kwargs.pop("provisional_edit_log_details", None) for tile in self.tiles: tile.delete(*args, request=request, **kwargs) try: user = request.user user_is_reviewer = user_is_resource_reviewer(user) except AttributeError: # no user user = None user_is_reviewer = True if user_is_reviewer is True or self.user_owns_provisional(user): query = Query(se) bool_query = Bool() bool_query.filter(Terms(field="tileid", terms=[self.tileid])) query.add_query(bool_query) results = query.search(index="terms")["hits"]["hits"] for result in results: se.delete(index="terms", id=result["_id"]) self.__preDelete(request) self.save_edit( user=request.user, edit_type="tile delete", old_value=self.data, provisional_edit_log_details=provisional_edit_log_details ) super(Tile, self).delete(*args, **kwargs) resource = Resource.objects.get(resourceinstanceid=self.resourceinstance.resourceinstanceid) resource.index() else: self.apply_provisional_edit(user, data={}, action="delete") super(Tile, self).save(*args, **kwargs)
def get(self, request): map_layers = models.MapLayer.objects.all() map_markers = models.MapMarker.objects.all() map_sources = models.MapSource.objects.all() resource_graphs = (models.GraphModel.objects.exclude( pk=settings.SYSTEM_SETTINGS_RESOURCE_MODEL_ID).exclude( isresource=False).exclude(isactive=False)) geocoding_providers = models.Geocoder.objects.all() search_components = models.SearchComponent.objects.all() datatypes = models.DDataType.objects.all() widgets = models.Widget.objects.all() templates = models.ReportTemplate.objects.all() card_components = models.CardComponent.objects.all() context = self.get_context_data( map_layers=map_layers, map_markers=map_markers, map_sources=map_sources, geocoding_providers=geocoding_providers, search_components=search_components, widgets=widgets, report_templates=templates, card_components=card_components, main_script="views/search", resource_graphs=resource_graphs, datatypes=datatypes, user_is_reviewer=user_is_resource_reviewer(request.user), ) graphs = JSONSerializer().serialize( context["resource_graphs"], exclude=[ "functions", "author", "deploymentdate", "deploymentfile", "version", "subtitle", "description", "disable_instance_creation", "ontology_id", ], ) context["graphs"] = graphs context["nav"]["title"] = _("Search") context["nav"]["icon"] = "fa-search" context["nav"]["search"] = False context["nav"]["help"] = { "title": _("Searching the Database"), "template": "search-help", } context["celery_running"] = task_management.check_if_celery_available() context[ "export_html_templates"] = HtmlWriter.get_graphids_with_export_template( ) return render(request, "views/search.htm", context)
def delete(self, user={}, note=""): """ Deletes a single resource and any related indexed data """ permit_deletion = False graph = models.GraphModel.objects.get(graphid=self.graph_id) if graph.isactive is False: message = _("This model is not yet active; unable to delete.") raise ModelInactiveError(message) if user != {}: user_is_reviewer = user_is_resource_reviewer(user) if user_is_reviewer is False: tiles = list(models.TileModel.objects.filter(resourceinstance=self)) resource_is_provisional = True if sum([len(t.data) for t in tiles]) == 0 else False if resource_is_provisional is True: permit_deletion = True else: permit_deletion = True else: permit_deletion = True if permit_deletion is True: related_resources = self.get_related_resources(lang="en-US", start=0, limit=1000, page=0) for rr in related_resources["resource_relationships"]: # delete any related resource entries, also reindex the resource that references this resource that's being deleted try: resourceXresource = models.ResourceXResource.objects.get(pk=rr["resourcexid"]) resource_to_reindex = ( resourceXresource.resourceinstanceidfrom_id if resourceXresource.resourceinstanceidto_id == self.resourceinstanceid else resourceXresource.resourceinstanceidto_id ) resourceXresource.delete(deletedResourceId=self.resourceinstanceid) res = Resource.objects.get(pk=resource_to_reindex) res.load_tiles() res.index() except ObjectDoesNotExist: se.delete(index=RESOURCE_RELATIONS_INDEX, id=rr["resourcexid"]) query = Query(se) bool_query = Bool() bool_query.filter(Terms(field="resourceinstanceid", terms=[self.resourceinstanceid])) query.add_query(bool_query) results = query.search(index=TERMS_INDEX)["hits"]["hits"] for result in results: se.delete(index=TERMS_INDEX, id=result["_id"]) se.delete(index=RESOURCES_INDEX, id=self.resourceinstanceid) try: self.save_edit(edit_type="delete", user=user, note=self.displayname) except: pass super(Resource, self).delete() return permit_deletion
def get_context_data(self, **kwargs): context = super(BaseManagerView, self).get_context_data(**kwargs) context[ "system_settings_graphid"] = settings.SYSTEM_SETTINGS_RESOURCE_MODEL_ID context["graph_models"] = [] context["graphs"] = "[]" context["plugins"] = [] for plugin in models.Plugin.objects.all().order_by("sortorder"): if self.request.user.has_perm("view_plugin", plugin): context["plugins"].append(plugin) createable = get_createable_resource_types(self.request.user) createable.sort(key=lambda x: x.name.lower()) context["createable_resources"] = JSONSerializer().serialize( createable, exclude=[ "functions", "ontology", "isactive", "isresource", "version", "deploymentdate", "deploymentfile", "author", ], ) context["notifications"] = models.UserXNotification.objects.filter( recipient=self.request.user, isread=False) context["nav"] = { "icon": "fa fa-chevron-circle-right", "title": "", "help": { # title:'',template:'' (leave this commented out) }, "menu": False, "search": True, "notifs": True, "res_edit": False, "login": True, "print": False, } context["user_is_reviewer"] = user_is_resource_reviewer( self.request.user) context["user_can_edit"] = len( get_editable_resource_types(self.request.user)) > 0 context["user_can_read"] = (len( get_resource_types_by_perm(self.request.user, [ "models.write_nodegroup", "models.delete_nodegroup", "models.read_nodegroup" ])) > 0) context["app_name"] = settings.APP_NAME context["show_language_swtich"] = settings.SHOW_LANGUAGE_SWITCH return context
def get_tile_data(self, user_id=None): data = self.data if user_id is not None: user_id = str(user_id) user = User.objects.get(pk=user_id) user_is_reviewer = user_is_resource_reviewer(user) if user_is_reviewer is False and self.provisionaledits is not None and user_id in self.provisionaledits: data = self.provisionaledits[user_id]["value"] return data
def post(self, request): if self.action == "get_user_names": data = {} if self.request.user.is_authenticated and user_is_resource_reviewer(request.user): userids = json.loads(request.POST.get("userids", "[]")) data = {u.id: u.username for u in User.objects.filter(id__in=userids)} return JSONResponse(data) if self.request.user.is_authenticated and self.request.user.username != "anonymous": user_details = self.get_user_details(request.user) context = self.get_context_data( main_script="views/user-profile-manager", ) context["errors"] = [] context["nav"]["icon"] = "fa fa-user" context["nav"]["title"] = _("Profile Manager") context["nav"]["login"] = True context["nav"]["help"] = { "title": _("Profile Editing"), "template": "profile-manager-help", } context["validation_help"] = validation.password_validators_help_texts() context["user_surveys"] = JSONSerializer().serialize(user_details["user_surveys"]) context["identities"] = JSONSerializer().serialize(user_details["identities"]) context["resources"] = JSONSerializer().serialize(user_details["resources"]) user_info = request.POST.copy() user_info["id"] = request.user.id user_info["username"] = request.user.username user_info["password1"] = request.user.password user_info["password2"] = request.user.password form = ArchesUserProfileForm(user_info) if form.is_valid(): user = form.save() try: admin_info = settings.ADMINS[0][1] if settings.ADMINS else None message = ( f"Your {settings.APP_NAME} profile was just changed. If this was unexpected, please contact your " f"{settings.APP_NAME} administrator{f' at {admin_info}.' if (admin_info and not str.isspace(admin_info)) else '.'}" ) message = _(message) user.email_user(_("Your " + settings.APP_NAME + " Profile Has Changed"), message) except: logger.error("Error sending email", exc_info=True) request.user = user context["form"] = form return render(request, "views/user-profile-manager.htm", context)
def delete(self, user={}, note=""): """ Deletes a single resource and any related indexed data """ permit_deletion = False graph = models.GraphModel.objects.get(graphid=self.graph_id) if graph.isactive is False: message = _("This model is not yet active; unable to delete.") raise ModelInactiveError(message) if user != {}: user_is_reviewer = user_is_resource_reviewer(user) if user_is_reviewer is False: tiles = list( models.TileModel.objects.filter(resourceinstance=self)) resource_is_provisional = True if sum( [len(t.data) for t in tiles]) == 0 else False if resource_is_provisional is True: permit_deletion = True else: permit_deletion = True else: permit_deletion = True if permit_deletion is True: se = SearchEngineFactory().create() related_resources = self.get_related_resources(lang="en-US", start=0, limit=1000, page=0) for rr in related_resources["resource_relationships"]: models.ResourceXResource.objects.get( pk=rr["resourcexid"]).delete() query = Query(se) bool_query = Bool() bool_query.filter( Terms(field="resourceinstanceid", terms=[self.resourceinstanceid])) query.add_query(bool_query) results = query.search(index="terms")["hits"]["hits"] for result in results: se.delete(index="terms", id=result["_id"]) se.delete(index="resources", id=self.resourceinstanceid) self.save_edit(edit_type="delete", user=user, note=self.displayname) super(Resource, self).delete() return permit_deletion
def delete(self, user={}, index=True, transaction_id=None): """ Deletes a single resource and any related indexed data """ # note that deferring index will require: # - that any resources related to the to-be-deleted resource get re-indexed # - that the index for the to-be-deleted resource gets deleted permit_deletion = False graph = models.GraphModel.objects.get(graphid=self.graph_id) if graph.isactive is False: message = _("This model is not yet active; unable to delete.") raise ModelInactiveError(message) if user != {}: user_is_reviewer = user_is_resource_reviewer(user) if user_is_reviewer is False: tiles = list( models.TileModel.objects.filter(resourceinstance=self)) resource_is_provisional = True if sum( [len(t.data) for t in tiles]) == 0 else False if resource_is_provisional is True: permit_deletion = True else: permit_deletion = True else: permit_deletion = True if permit_deletion is True: for related_resource in models.ResourceXResource.objects.filter( Q(resourceinstanceidfrom=self.resourceinstanceid) | Q(resourceinstanceidto=self.resourceinstanceid)): related_resource.delete( deletedResourceId=self.resourceinstanceid, index=False) if index: self.delete_index() try: self.save_edit(edit_type="delete", user=user, note=self.displayname, transaction_id=transaction_id) except: pass super(Resource, self).delete() return permit_deletion
def datatype_post_save_actions(self, request=None): userid = None user_is_reviewer = True if request is not None: userid = str(request.user.id) if hasattr(request.user, "userprofile") is not True: models.UserProfile.objects.create(user=request.user) user_is_reviewer = user_is_resource_reviewer(request.user) tile_data = self.get_tile_data(user_is_reviewer, userid) for nodeid, value in list(tile_data.items()): datatype_factory = DataTypeFactory() node = models.Node.objects.get(nodeid=nodeid) datatype = datatype_factory.get_instance(node.datatype) if request is not None: datatype.handle_request(self, request, node)
def delete(self, request): json = request.body if json is not None: ret = [] data = JSONDeserializer().deserialize(json) resource_instance = models.ResourceInstance.objects.get(pk=data["resourceinstance_id"]) is_active = resource_instance.graph.isactive with transaction.atomic(): try: tile = Tile.objects.get(tileid=data["tileid"]) except ObjectDoesNotExist: return JSONErrorResponse(_("This tile is no longer available"), _("It was likely already deleted by another user")) user_is_reviewer = user_is_resource_reviewer(request.user) if (user_is_reviewer or tile.is_provisional() is True) and is_active is True: if tile.filter_by_perm(request.user, "delete_nodegroup"): nodegroup = models.NodeGroup.objects.get(pk=tile.nodegroup_id) if tile.is_provisional() is True and len(list(tile.provisionaledits.keys())) == 1: provisional_editor_id = list(tile.provisionaledits.keys())[0] edit = tile.provisionaledits[provisional_editor_id] provisional_editor = User.objects.get(pk=provisional_editor_id) reviewer = request.user tile.delete( request=request, provisional_edit_log_details={ "user": reviewer, "action": "delete edit", "edit": edit, "provisional_editor": provisional_editor, }, ) else: tile.delete(request=request) tile.after_update_all() update_system_settings_cache(tile) return JSONResponse(tile) else: return JSONErrorResponse(_("Request Failed"), _("Permission Denied")) elif is_active is False: response = {"status": "false", "message": [_("Request Failed"), _("Unable to delete. Verify model status is active")]} return JSONResponse(response, status=500) else: return JSONErrorResponse( _("Request Failed"), _("You do not have permissions to delete a tile with authoritative data.") ) return HttpResponseNotFound()
def delete(self, *args, **kwargs): se = SearchEngineFactory().create() request = kwargs.pop("request", None) index = kwargs.pop("index", True) transaction_id = kwargs.pop("index", None) provisional_edit_log_details = kwargs.pop( "provisional_edit_log_details", None) for tile in self.tiles: tile.delete(*args, request=request, **kwargs) try: user = request.user user_is_reviewer = user_is_resource_reviewer(user) except AttributeError: # no user user = None user_is_reviewer = True if user_is_reviewer is True or self.user_owns_provisional(user): if index: query = Query(se) bool_query = Bool() bool_query.filter(Terms(field="tileid", terms=[self.tileid])) query.add_query(bool_query) results = query.delete(index=TERMS_INDEX) self.__preDelete(request) self.save_edit( user=user, edit_type="tile delete", old_value=self.data, provisional_edit_log_details=provisional_edit_log_details, transaction_id=transaction_id, ) try: super(Tile, self).delete(*args, **kwargs) for nodeid in self.data.keys(): node = models.Node.objects.get(nodeid=nodeid) datatype = self.datatype_factory.get_instance( node.datatype) datatype.post_tile_delete(self, nodeid, index=index) if index: self.index() except IntegrityError as e: logger.error(e) else: self.apply_provisional_edit(user, data={}, action="delete") super(Tile, self).save(*args, **kwargs)
def post_search_hook(self, search_results_object, results, permitted_nodegroups): user_is_reviewer = user_is_resource_reviewer(self.request.user) # only reuturn points and geometries a user is allowed to view geojson_nodes = get_nodegroups_by_datatype_and_perm(self.request, "geojson-feature-collection", "read_nodegroup") for result in results["hits"]["hits"]: result["_source"]["points"] = select_geoms_for_results(result["_source"]["points"], geojson_nodes, user_is_reviewer) result["_source"]["geometries"] = select_geoms_for_results(result["_source"]["geometries"], geojson_nodes, user_is_reviewer) try: permitted_tiles = [] for tile in result["_source"]["tiles"]: if tile["nodegroup_id"] in permitted_nodegroups: permitted_tiles.append(tile) result["_source"]["tiles"] = permitted_tiles except KeyError: pass
def post(self, request): username = request.POST.get("username", None) password = request.POST.get("password", None) user = authenticate(username=username, password=password) if user: if hasattr(user, "userprofile") is not True: models.UserProfile.objects.create(user=user) userDict = JSONSerializer().serializeToPython(user) userDict["password"] = None userDict["is_reviewer"] = user_is_resource_reviewer(user) userDict["viewable_nodegroups"] = user.userprofile.viewable_nodegroups userDict["editable_nodegroups"] = user.userprofile.editable_nodegroups userDict["deletable_nodegroups"] = user.userprofile.deletable_nodegroups response = JSONResponse(userDict) else: response = Http401Response() return response
def post(self, request): username = request.POST.get("username", None) password = request.POST.get("password", None) user = authenticate(username=username, password=password) if settings.MOBILE_OAUTH_CLIENT_ID == "": message = _("Make sure to set your MOBILE_OAUTH_CLIENT_ID in settings.py") response = HttpResponse(message, status=500) logger.warning(message) else: if user: if hasattr(user, "userprofile") is not True: models.UserProfile.objects.create(user=user) is_reviewer = user_is_resource_reviewer(user) user = JSONSerializer().serializeToPython(user) user["password"] = None user["is_reviewer"] = is_reviewer response = JSONResponse({"user": user, "clientid": settings.MOBILE_OAUTH_CLIENT_ID}) else: response = Http401Response() return response
def get(self, request, resourceid): try: resource_instance = Resource.objects.get(pk=resourceid) graph = resource_instance.graph except Resource.DoesNotExist: graph = models.GraphModel.objects.get(pk=resourceid) resourceid = None resource_instance = None pass nodes = graph.node_set.all() nodegroups = [] editable_nodegroups = [] for node in nodes: if node.is_collector: added = False if request.user.has_perm("write_nodegroup", node.nodegroup): editable_nodegroups.append(node.nodegroup) nodegroups.append(node.nodegroup) added = True if not added and request.user.has_perm("read_nodegroup", node.nodegroup): nodegroups.append(node.nodegroup) nodes = nodes.filter(nodegroup__in=nodegroups) cards = graph.cardmodel_set.order_by("sortorder").filter(nodegroup__in=nodegroups).prefetch_related("cardxnodexwidget_set") cardwidgets = [ widget for widgets in [card.cardxnodexwidget_set.order_by("sortorder").all() for card in cards] for widget in widgets ] datatypes = models.DDataType.objects.all() user_is_reviewer = user_is_resource_reviewer(request.user) widgets = models.Widget.objects.all() card_components = models.CardComponent.objects.all() if resource_instance is None: tiles = [] displayname = _("New Resource") else: displayname = resource_instance.displayname if displayname == "undefined": displayname = _("Unnamed Resource") if str(resource_instance.graph_id) == settings.SYSTEM_SETTINGS_RESOURCE_MODEL_ID: displayname = _("System Settings") tiles = resource_instance.tilemodel_set.order_by("sortorder").filter(nodegroup__in=nodegroups) provisionaltiles = [] for tile in tiles: append_tile = True isfullyprovisional = False if tile.provisionaledits is not None: if len(list(tile.provisionaledits.keys())) > 0: if len(tile.data) == 0: isfullyprovisional = True if user_is_reviewer is False: if str(request.user.id) in tile.provisionaledits: tile.provisionaledits = {str(request.user.id): tile.provisionaledits[str(request.user.id)]} tile.data = tile.provisionaledits[str(request.user.id)]["value"] else: if isfullyprovisional is True: # if the tile IS fully provisional and the current user is not the owner, # we don't send that tile back to the client. append_tile = False else: # if the tile has authoritaive data and the current user is not the owner, # we don't send the provisional data of other users back to the client. tile.provisionaledits = None if append_tile is True: provisionaltiles.append(tile) tiles = provisionaltiles cards = JSONSerializer().serializeToPython(cards) editable_nodegroup_ids = [str(nodegroup.pk) for nodegroup in editable_nodegroups] for card in cards: card["is_writable"] = False if str(card["nodegroup_id"]) in editable_nodegroup_ids: card["is_writable"] = True context = { "resourceid": resourceid, "displayname": displayname, "tiles": tiles, "cards": cards, "nodegroups": nodegroups, "nodes": nodes, "cardwidgets": cardwidgets, "datatypes": datatypes, "userisreviewer": user_is_reviewer, "widgets": widgets, "card_components": card_components, } return JSONResponse(context, indent=4)
def search_results(request, returnDsl=False): for_export = request.GET.get("export") pages = request.GET.get("pages", None) total = int(request.GET.get("total", "0")) resourceinstanceid = request.GET.get("id", None) load_tiles = request.GET.get("tiles", False) if load_tiles: try: load_tiles = json.loads(load_tiles) except TypeError: pass se = SearchEngineFactory().create() permitted_nodegroups = get_permitted_nodegroups(request.user) include_provisional = get_provisional_type(request) search_filter_factory = SearchFilterFactory(request) search_results_object = {"query": Query(se)} try: for filter_type, querystring in list( request.GET.items()) + [("search-results", "")]: search_filter = search_filter_factory.get_filter(filter_type) if search_filter: search_filter.append_dsl(search_results_object, permitted_nodegroups, include_provisional) append_instance_permission_filter_dsl(request, search_results_object) except Exception as err: logger.exception(err) return JSONErrorResponse(message=err) dsl = search_results_object.pop("query", None) if returnDsl: return dsl dsl.include("graph_id") dsl.include("root_ontology_class") dsl.include("resourceinstanceid") dsl.include("points") dsl.include("permissions.users_without_read_perm") dsl.include("permissions.users_without_edit_perm") dsl.include("permissions.users_without_delete_perm") dsl.include("permissions.users_with_no_access") dsl.include("geometries") dsl.include("displayname") dsl.include("displaydescription") dsl.include("map_popup") dsl.include("provisional_resource") if load_tiles: dsl.include("tiles") if for_export or pages: results = dsl.search(index=RESOURCES_INDEX, scroll="1m") scroll_id = results["_scroll_id"] if not pages: if total <= settings.SEARCH_EXPORT_LIMIT: pages = (total // settings.SEARCH_RESULT_LIMIT) + 1 if total > settings.SEARCH_EXPORT_LIMIT: pages = int(settings.SEARCH_EXPORT_LIMIT // settings.SEARCH_RESULT_LIMIT) - 1 for page in range(int(pages)): results_scrolled = dsl.se.es.scroll(scroll_id=scroll_id, scroll="1m") results["hits"]["hits"] += results_scrolled["hits"]["hits"] else: results = dsl.search(index=RESOURCES_INDEX, id=resourceinstanceid) ret = {} if results is not None: if "hits" not in results: if "docs" in results: results = {"hits": {"hits": results["docs"]}} else: results = {"hits": {"hits": [results]}} # allow filters to modify the results for filter_type, querystring in list( request.GET.items()) + [("search-results", "")]: search_filter = search_filter_factory.get_filter(filter_type) if search_filter: search_filter.post_search_hook(search_results_object, results, permitted_nodegroups) ret["results"] = results for key, value in list(search_results_object.items()): ret[key] = value ret["reviewer"] = user_is_resource_reviewer(request.user) ret["timestamp"] = datetime.now() ret["total_results"] = dsl.count(index=RESOURCES_INDEX) ret["userid"] = request.user.id return JSONResponse(ret) else: ret = { "message": _("There was an error retrieving the search results") } return JSONResponse(ret, status=500)
def get( self, request, graphid=None, resourceid=None, view_template="views/resource/editor.htm", main_script="views/resource/editor", nav_menu=True, ): if self.action == "copy": return self.copy(request, resourceid) creator = None user_created_instance = None if resourceid is None: resource_instance = None graph = models.GraphModel.objects.get(pk=graphid) resourceid = "" else: resource_instance = Resource.objects.get(pk=resourceid) graph = resource_instance.graph creator, user_created_instance = get_instance_creator(resource_instance, request.user) nodes = graph.node_set.all() resource_graphs = ( models.GraphModel.objects.exclude(pk=settings.SYSTEM_SETTINGS_RESOURCE_MODEL_ID) .exclude(isresource=False) .exclude(isactive=False) ) ontologyclass = [node for node in nodes if node.istopnode is True][0].ontologyclass relationship_type_values = get_resource_relationship_types() nodegroups = [] editable_nodegroups = [] for node in nodes: if node.is_collector: added = False if request.user.has_perm("write_nodegroup", node.nodegroup): editable_nodegroups.append(node.nodegroup) nodegroups.append(node.nodegroup) added = True if not added and request.user.has_perm("read_nodegroup", node.nodegroup): nodegroups.append(node.nodegroup) nodes = nodes.filter(nodegroup__in=nodegroups) cards = graph.cardmodel_set.order_by("sortorder").filter(nodegroup__in=nodegroups).prefetch_related("cardxnodexwidget_set") cardwidgets = [ widget for widgets in [card.cardxnodexwidget_set.order_by("sortorder").all() for card in cards] for widget in widgets ] widgets = models.Widget.objects.all() card_components = models.CardComponent.objects.all() applied_functions = JSONSerializer().serialize(models.FunctionXGraph.objects.filter(graph=graph)) datatypes = models.DDataType.objects.all() user_is_reviewer = user_is_resource_reviewer(request.user) is_system_settings = False if resource_instance is None: tiles = [] displayname = _("New Resource") else: displayname = resource_instance.displayname if displayname == "undefined": displayname = _("Unnamed Resource") if str(resource_instance.graph_id) == settings.SYSTEM_SETTINGS_RESOURCE_MODEL_ID: is_system_settings = True displayname = _("System Settings") tiles = resource_instance.tilemodel_set.order_by("sortorder").filter(nodegroup__in=nodegroups) provisionaltiles = [] for tile in tiles: append_tile = True isfullyprovisional = False if tile.provisionaledits is not None: if len(list(tile.provisionaledits.keys())) > 0: if len(tile.data) == 0: isfullyprovisional = True if user_is_reviewer is False: if str(request.user.id) in tile.provisionaledits: tile.provisionaledits = {str(request.user.id): tile.provisionaledits[str(request.user.id)]} tile.data = tile.provisionaledits[str(request.user.id)]["value"] else: if isfullyprovisional is True: # if the tile IS fully provisional and the current user is not the owner, # we don't send that tile back to the client. append_tile = False else: # if the tile has authoritaive data and the current user is not the owner, # we don't send the provisional data of other users back to the client. tile.provisionaledits = None if append_tile is True: provisionaltiles.append(tile) tiles = provisionaltiles map_layers = models.MapLayer.objects.all() map_markers = models.MapMarker.objects.all() map_sources = models.MapSource.objects.all() geocoding_providers = models.Geocoder.objects.all() templates = models.ReportTemplate.objects.all() cards = JSONSerializer().serializeToPython(cards) editable_nodegroup_ids = [str(nodegroup.pk) for nodegroup in editable_nodegroups] for card in cards: card["is_writable"] = False if str(card["nodegroup_id"]) in editable_nodegroup_ids: card["is_writable"] = True context = self.get_context_data( main_script=main_script, resourceid=resourceid, displayname=displayname, graphid=graph.graphid, graphiconclass=graph.iconclass, graphname=graph.name, ontologyclass=ontologyclass, resource_graphs=resource_graphs, relationship_types=relationship_type_values, widgets=widgets, widgets_json=JSONSerializer().serialize(widgets), card_components=card_components, card_components_json=JSONSerializer().serialize(card_components), tiles=JSONSerializer().serialize(tiles), cards=JSONSerializer().serialize(cards), applied_functions=applied_functions, nodegroups=JSONSerializer().serialize(nodegroups), nodes=JSONSerializer().serialize(nodes), cardwidgets=JSONSerializer().serialize(cardwidgets), datatypes_json=JSONSerializer().serialize(datatypes, exclude=["iconclass", "modulename", "classname"]), map_layers=map_layers, map_markers=map_markers, map_sources=map_sources, geocoding_providers=geocoding_providers, user_is_reviewer=json.dumps(user_is_reviewer), creator=json.dumps(creator), user_created_instance=json.dumps(user_created_instance), report_templates=templates, templates_json=JSONSerializer().serialize(templates, sort_keys=False, exclude=["name", "description"]), graph_json=JSONSerializer().serialize(graph), is_system_settings=is_system_settings, ) context["nav"]["title"] = "" context["nav"]["menu"] = nav_menu if resourceid == settings.RESOURCE_INSTANCE_ID: context["nav"]["help"] = {"title": _("Managing System Settings"), "template": "system-settings-help"} else: context["nav"]["help"] = {"title": _("Using the Resource Editor"), "template": "resource-editor-help"} return render(request, view_template, context)
def search_results(request): for_export = request.GET.get("export") total = int(request.GET.get("total", "0")) se = SearchEngineFactory().create() search_results_object = {"query": Query(se)} include_provisional = get_provisional_type(request) permitted_nodegroups = get_permitted_nodegroups(request.user) search_filter_factory = SearchFilterFactory(request) try: for filter_type, querystring in list( request.GET.items()) + [("search-results", "")]: search_filter = search_filter_factory.get_filter(filter_type) if search_filter: search_filter.append_dsl(search_results_object, permitted_nodegroups, include_provisional) except Exception as err: return JSONErrorResponse(message=err) dsl = search_results_object.pop("query", None) dsl.include("graph_id") dsl.include("root_ontology_class") dsl.include("resourceinstanceid") dsl.include("points") dsl.include("geometries") dsl.include("displayname") dsl.include("displaydescription") dsl.include("map_popup") dsl.include("provisional_resource") if request.GET.get("tiles", None) is not None: dsl.include("tiles") if for_export is True: results = dsl.search(index="resources", scroll="1m") scroll_id = results["_scroll_id"] if total <= settings.SEARCH_EXPORT_LIMIT: pages = (total // settings.SEARCH_RESULT_LIMIT) + 1 if total > settings.SEARCH_EXPORT_LIMIT: pages = int(settings.SEARCH_EXPORT_LIMIT // settings.SEARCH_RESULT_LIMIT) - 1 for page in range(pages): results_scrolled = dsl.se.es.scroll(scroll_id=scroll_id, scroll="1m") results["hits"]["hits"] += results_scrolled["hits"]["hits"] else: results = dsl.search(index="resources") ret = {} if results is not None: # allow filters to modify the results for filter_type, querystring in list( request.GET.items()) + [("search-results", "")]: search_filter = search_filter_factory.get_filter(filter_type) if search_filter: search_filter.post_search_hook(search_results_object, results, permitted_nodegroups) ret["results"] = results for key, value in list(search_results_object.items()): ret[key] = value ret["reviewer"] = user_is_resource_reviewer(request.user) ret["timestamp"] = datetime.now() ret["total_results"] = dsl.count(index="resources") return JSONResponse(ret) else: ret = { "message": _("There was an error retrieving the search results") } return JSONResponse(ret, status=500)
def search_terms(request): lang = request.GET.get("lang", settings.LANGUAGE_CODE) se = SearchEngineFactory().create() searchString = request.GET.get("q", "") user_is_reviewer = user_is_resource_reviewer(request.user) i = 0 ret = {} for index in ["terms", "concepts"]: query = Query(se, start=0, limit=0) boolquery = Bool() boolquery.should( Match(field="value", query=searchString.lower(), type="phrase_prefix")) boolquery.should( Match(field="value.folded", query=searchString.lower(), type="phrase_prefix")) boolquery.should( Match(field="value.folded", query=searchString.lower(), fuzziness="AUTO", prefix_length=settings.SEARCH_TERM_SENSITIVITY)) if user_is_reviewer is False and index == "terms": boolquery.filter(Terms(field="provisional", terms=["false"])) query.add_query(boolquery) base_agg = Aggregation(name="value_agg", type="terms", field="value.raw", size=settings.SEARCH_DROPDOWN_LENGTH, order={"max_score": "desc"}) nodegroupid_agg = Aggregation(name="nodegroupid", type="terms", field="nodegroupid") top_concept_agg = Aggregation(name="top_concept", type="terms", field="top_concept") conceptid_agg = Aggregation(name="conceptid", type="terms", field="conceptid") max_score_agg = MaxAgg(name="max_score", script="_score") top_concept_agg.add_aggregation(conceptid_agg) base_agg.add_aggregation(max_score_agg) base_agg.add_aggregation(top_concept_agg) base_agg.add_aggregation(nodegroupid_agg) query.add_aggregation(base_agg) ret[index] = [] results = query.search(index=index) if results is not None: for result in results["aggregations"]["value_agg"]["buckets"]: if len(result["top_concept"]["buckets"]) > 0: for top_concept in result["top_concept"]["buckets"]: top_concept_id = top_concept["key"] top_concept_label = get_preflabel_from_conceptid( top_concept["key"], lang)["value"] for concept in top_concept["conceptid"]["buckets"]: ret[index].append({ "type": "concept", "context": top_concept_id, "context_label": top_concept_label, "id": i, "text": result["key"], "value": concept["key"], }) i = i + 1 else: ret[index].append({ "type": "term", "context": "", "context_label": get_resource_model_label(result), "id": i, "text": result["key"], "value": result["key"], }) i = i + 1 return JSONResponse(ret)
def get( self, request, graphid=None, resourceid=None, view_template="views/resource/editor.htm", main_script="views/resource/editor", nav_menu=True, ): if self.action == "copy": return self.copy(request, resourceid) resource_instance_exists = False try: resource_instance = Resource.objects.get(pk=resourceid) resource_instance_exists = True graphid = resource_instance.graph_id except ObjectDoesNotExist: resource_instance = Resource() resource_instance.resourceinstanceid = resourceid resource_instance.graph_id = graphid if resourceid is not None: resource_graphs = (models.GraphModel.objects.exclude( pk=settings.SYSTEM_SETTINGS_RESOURCE_MODEL_ID).exclude( isresource=False).exclude(isactive=False)) graph = Graph.objects.get(graphid=graphid) relationship_type_values = get_resource_relationship_types() datatypes = models.DDataType.objects.all() widgets = models.Widget.objects.all() map_layers = models.MapLayer.objects.all() map_markers = models.MapMarker.objects.all() map_sources = models.MapSource.objects.all() geocoding_providers = models.Geocoder.objects.all() required_widgets = [] widget_datatypes = [v.datatype for k, v in graph.nodes.items()] widgets = widgets.filter(datatype__in=widget_datatypes) if resource_instance_exists == True: displayname = Resource.objects.get(pk=resourceid).displayname if displayname == "undefined": displayname = "Unnamed Resource" else: displayname = "Unnamed Resource" date_nodes = models.Node.objects.filter(datatype="date", graph__isresource=True, graph__isactive=True) searchable_datatypes = [ d.pk for d in models.DDataType.objects.filter(issearchable=True) ] searchable_nodes = models.Node.objects.filter( graph__isresource=True, graph__isactive=True, datatype__in=searchable_datatypes, issearchable=True) resource_cards = models.CardModel.objects.filter( graph__isresource=True, graph__isactive=True) context = self.get_context_data( main_script=main_script, resource_type=graph.name, relationship_types=relationship_type_values, iconclass=graph.iconclass, datatypes_json=JSONSerializer().serialize( datatypes, exclude=["iconclass", "modulename", "classname"]), datatypes=datatypes, widgets=widgets, date_nodes=date_nodes, map_layers=map_layers, map_markers=map_markers, map_sources=map_sources, geocoding_providers=geocoding_providers, widgets_json=JSONSerializer().serialize(widgets), resourceid=resourceid, resource_graphs=resource_graphs, graph_json=JSONSerializer().serialize( graph, exclude=[ "iconclass", "functions", "functions_x_graphs", "name", "description", "deploymentfile", "author", "deploymentdate", "version", "isresource", "isactive", "iconclass", "ontology", ], ), displayname=displayname, resource_cards=JSONSerializer().serialize(resource_cards, exclude=[ "description", "instructions", "active", "isvisible" ]), searchable_nodes=JSONSerializer().serialize( searchable_nodes, exclude=[ "description", "ontologyclass", "isrequired", "issearchable", "istopnode" ]), saved_searches=JSONSerializer().serialize( settings.SAVED_SEARCHES), resource_instance_exists=resource_instance_exists, user_is_reviewer=json.dumps( user_is_resource_reviewer(request.user)), userid=request.user.id, ) if graph.iconclass: context["nav"]["icon"] = graph.iconclass context["nav"]["title"] = graph.name context["nav"]["menu"] = nav_menu if resourceid == settings.RESOURCE_INSTANCE_ID: context["nav"]["help"] = (_("Managing System Settings"), "help/base-help.htm") context["help"] = "system-settings-help" else: context["nav"]["help"] = (_("Using the Resource Editor"), "help/base-help.htm") context["help"] = "resource-editor-help" return render(request, view_template, context) return HttpResponseNotFound()
def save(self, *args, **kwargs): request = kwargs.pop("request", None) index = kwargs.pop("index", True) user = kwargs.pop("user", None) log = kwargs.pop("log", True) provisional_edit_log_details = kwargs.pop("provisional_edit_log_details", None) missing_nodes = [] creating_new_tile = True user_is_reviewer = False newprovisionalvalue = None oldprovisionalvalue = None try: if user is None and request is not None: user = request.user user_is_reviewer = user_is_resource_reviewer(user) except AttributeError: # no user - probably importing data user = None # if user is not None: # self.validate([]) with transaction.atomic(): for nodeid, value in self.data.items(): node = models.Node.objects.get(nodeid=nodeid) datatype = self.datatype_factory.get_instance(node.datatype) datatype.pre_tile_save(self, nodeid) self.__preSave(request) self.check_for_missing_nodes(request) self.check_for_constraint_violation(request) creating_new_tile = models.TileModel.objects.filter(pk=self.tileid).exists() is False edit_type = "tile create" if (creating_new_tile is True) else "tile edit" if creating_new_tile is False: existing_model = models.TileModel.objects.get(pk=self.tileid) # this section moves the data over from self.data to self.provisionaledits if certain users permissions are in force # then self.data is restored from the previously saved tile data if user is not None and user_is_reviewer is False: if creating_new_tile is True: self.apply_provisional_edit(user, data=self.data, action="create") newprovisionalvalue = self.data self.data = {} else: # the user has previously edited this tile self.apply_provisional_edit(user, self.data, action="update", existing_model=existing_model) newprovisionalvalue = self.data self.data = existing_model.data oldprovisional = self.get_provisional_edit(existing_model, user) if oldprovisional is not None: oldprovisionalvalue = oldprovisional["value"] if provisional_edit_log_details is None: provisional_edit_log_details = { "user": user, "provisional_editor": user, "action": "create tile" if creating_new_tile else "add edit", } if user is not None: self.validate([]) super(Tile, self).save(*args, **kwargs) # We have to save the edit log record after calling save so that the # resource's displayname changes are avaliable user = {} if user is None else user self.datatype_post_save_actions(request) self.__postSave(request) if creating_new_tile is True: self.save_edit( user=user, edit_type=edit_type, old_value={}, new_value=self.data, newprovisionalvalue=newprovisionalvalue, provisional_edit_log_details=provisional_edit_log_details, ) else: self.save_edit( user=user, edit_type=edit_type, old_value=existing_model.data, new_value=self.data, newprovisionalvalue=newprovisionalvalue, oldprovisionalvalue=oldprovisionalvalue, provisional_edit_log_details=provisional_edit_log_details, ) if index: self.index() for tile in self.tiles: tile.resourceinstance = self.resourceinstance tile.parenttile = self tile.save(*args, request=request, index=index, **kwargs)
def save(self, *args, **kwargs): request = kwargs.pop("request", None) index = kwargs.pop("index", True) user = kwargs.pop("user", None) log = kwargs.pop("log", True) provisional_edit_log_details = kwargs.pop( "provisional_edit_log_details", None) self.__preSave(request) missing_nodes = [] creating_new_tile = True user_is_reviewer = False newprovisionalvalue = None oldprovisionalvalue = None self.check_for_missing_nodes(request) self.check_for_constraint_violation(request) try: if user is None and request is not None: user = request.user user_is_reviewer = user_is_resource_reviewer(user) except AttributeError: # no user - probably importing data user = None creating_new_tile = models.TileModel.objects.filter( pk=self.tileid).exists() is False edit_type = "tile create" if ( creating_new_tile is True) else "tile edit" if creating_new_tile is False: existing_model = models.TileModel.objects.get(pk=self.tileid) if user is not None: if user_is_reviewer is False and creating_new_tile is False: self.apply_provisional_edit(user, self.data, action="update", existing_model=existing_model) newprovisionalvalue = self.data oldprovisional = self.get_provisional_edit( existing_model, user) if oldprovisional is not None: oldprovisionalvalue = oldprovisional["value"] self.data = existing_model.data if provisional_edit_log_details is None: provisional_edit_log_details = { "user": user, "action": "add edit", "provisional_editor": user } if creating_new_tile is True: if self.is_provisional( ) is False and user_is_reviewer is False: self.apply_provisional_edit(user, data=self.data, action="create") newprovisionalvalue = self.data self.data = {} if provisional_edit_log_details is None: provisional_edit_log_details = { "user": user, "action": "create tile", "provisional_editor": user } if user is not None: self.validate([]) super(Tile, self).save(*args, **kwargs) # We have to save the edit log record after calling save so that the # resource's displayname changes are avaliable if log is True: user = {} if user is None else user self.datatype_post_save_actions(request) if creating_new_tile is True: self.save_edit( user=user, edit_type=edit_type, old_value={}, new_value=self.data, newprovisionalvalue=newprovisionalvalue, provisional_edit_log_details=provisional_edit_log_details, ) else: self.save_edit( user=user, edit_type=edit_type, old_value=existing_model.data, new_value=self.data, newprovisionalvalue=newprovisionalvalue, oldprovisionalvalue=oldprovisionalvalue, provisional_edit_log_details=provisional_edit_log_details, ) if index: self.index() for tile in self.tiles: tile.resourceinstance = self.resourceinstance tile.parenttile = self tile.save(*args, request=request, index=index, **kwargs)