Skip to content

Commit

Permalink
- Add geo_apps utils method missing from 3.3.x
Browse files Browse the repository at this point in the history
  • Loading branch information
afabiani committed Jan 27, 2022
1 parent a6fa66a commit 5a43c4d
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 33 deletions.
7 changes: 5 additions & 2 deletions geonode/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ def ensure_string(payload_bytes):
# when payload is a byte-like object (e.g bytearray)
# primarily used in when _payload is an image
return _payload
if re.match(r'b\'(.*)\'', _payload):
_payload = re.match(r'b\'(.*)\'', _payload).groups()[0]
try:
if re.match(r'b\'(.*)\'', _payload):
_payload = re.match(r'b\'(.*)\'', _payload).groups()[0]
except TypeError:
pass
return _payload
2 changes: 2 additions & 0 deletions geonode/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#
#########################################################################

from geonode.utils import get_subclasses_by_model
import warnings
from django.conf import settings
from geonode import get_version
Expand Down Expand Up @@ -203,6 +204,7 @@ def resource_urls(request):
],
ADVANCED_EDIT_EXCLUDE_FIELD=getattr(settings, "ADVANCED_EDIT_EXCLUDE_FIELD", []),
PROFILE_EDIT_EXCLUDE_FIELD=getattr(settings, "PROFILE_EDIT_EXCLUDE_FIELD", []),
GEONODE_APPS_INSTALLED=get_subclasses_by_model('GeoApp'),
AVAILABLE_SOCIAL_APPS_COUNT=SocialApp.objects.count(),
)
return defaults
1 change: 0 additions & 1 deletion geonode/documents/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@

class DocumentFormMixin(object):


def generate_link_choices(self, resources=None):

if resources is None:
Expand Down
9 changes: 8 additions & 1 deletion geonode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2035,9 +2035,16 @@ def get_geonode_catalogue_service():
# 'class': 'geonode.thumbs.background.GenericXYZBackground',
# initialization parameters for generator instance, valid only for generic classes
'options': {
# 'url': URL for the generic xyz service
# 'url': URL for the generic xyz / tms service
# 'tms': False by default. Set to True if the service is TMS
# 'tile_size': tile size for the generic xyz service, default is 256
},
# example options for a TMS service
# 'class': 'geonode.thumbs.background.GenericXYZBackground',
# 'options': {
# 'url': 'http://maps.geosolutionsgroup.com/geoserver/gwc/service/tms/1.0.0/osm%3Aosm_simple_light@EPSG%3A900913@png/{z}/{x}/{y}.png',
# 'tms': True
# },
}

# define the urls after the settings are overridden
Expand Down
5 changes: 5 additions & 0 deletions geonode/social/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,15 @@ class SocialConfig(AppConfig):
def ready(self):
from django.apps import apps
from actstream import registry
from geonode.utils import get_geoapps_models
registry.register(apps.get_app_config('layers').get_model('Layer'))
registry.register(apps.get_app_config('maps').get_model('Map'))
registry.register(apps.get_app_config('documents').get_model('Document'))
registry.register(apps.get_app_config('services').get_model('Service'))
registry.register(apps.get_app_config('dialogos').get_model('Comment'))
_auth_user_model = settings.AUTH_USER_MODEL.split('.')
registry.register(apps.get_app_config(_auth_user_model[0]).get_model(_auth_user_model[1]))
# Get models which are of subclass 'GeoApp'
models = get_geoapps_models()
for m in models:
registry.register(apps.get_app_config(m.label).get_model(m.default_model))
16 changes: 15 additions & 1 deletion geonode/social/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from django.conf import settings
from django.db.models import signals
from django.utils.translation import ugettext_lazy as _
from geonode.geoapps.models import GeoApp

# from actstream.exceptions import ModelNotActionable

Expand All @@ -38,6 +39,7 @@
from geonode.notifications_helper import (send_notification, queue_notification,
has_notifications, get_notification_recipients,
get_comment_notification_recipients)
from geonode.utils import get_geoapps_models

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -109,6 +111,12 @@ def activity_post_modify_object(sender, instance, created=None, **kwargs):
except Exception as e:
logger.exception(e)

if obj_type not in ['document', 'layer', 'map', 'comment']:
try:
action_settings[obj_type].update(object_name=getattr(instance, 'title', None),)
except Exception as e:
logger.exception(e)

try:
action = action_settings[obj_type]
if created:
Expand All @@ -120,7 +128,8 @@ def activity_post_modify_object(sender, instance, created=None, **kwargs):
# object was saved.
if not isinstance(instance, Layer) and \
not isinstance(instance, Document) and \
not isinstance(instance, Map):
not isinstance(instance, Map) and \
not issubclass(type(instance), GeoApp):
verb = action.get('updated_verb')
raw_action = 'updated'

Expand Down Expand Up @@ -169,6 +178,11 @@ def relationship_post_save(instance, sender, created, **kwargs):

signals.post_save.connect(activity_post_modify_object, sender=Document)
signals.post_delete.connect(activity_post_modify_object, sender=Document)
models = get_geoapps_models()
for m in models:
sender = f'{m.label}.{m.default_model}'
signals.post_save.connect(activity_post_modify_object, sender=sender)
signals.post_delete.connect(activity_post_modify_object, sender=sender)


def rating_post_save(instance, sender, created, **kwargs):
Expand Down
16 changes: 16 additions & 0 deletions geonode/social/templates/social/activity_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ <h2>{% trans "Recent activity" %}</h2>
<li class="active"><a href="#all" data-toggle="tab"><i class=""></i>{% trans "All" %}</a></li>
<li><a href="#layers" data-toggle="tab"><i class="fa fa-square-o rotate-45"></i> {% trans "Layers" %}</a></li>
<li><a href="#maps" data-toggle="tab"><i class="fa fa-map-marker"></i> {% trans "Maps" %}</a></li>
{% for app in GEONODE_APPS_INSTALLED %}
<li><a href="#{{app|lower}}" data-toggle="tab"><i class="fa fa-gears"></i>
{% blocktrans %}{{app}}{% endblocktrans %}
</a></li>
{% endfor %}
<li><a href="#documents" data-toggle="tab"><i class="fa fa-newspaper-o"></i> {% trans "Documents" %}</a></li>
<li><a href="#comments" data-toggle="tab"><i class="fa fa-comment-o"></i> {% trans "Comments" %}</a></li>
</ul>
Expand Down Expand Up @@ -69,6 +74,17 @@ <h2>{% trans "Recent activity" %}</h2>
{% endfor %}
</ul>
</article>
{% for app_name, app_action_list in action_list_geoapps.items %}
<article id="{{app_name}}" class="tab-pane">
<ul class="no-style-list">
{% for action in app_action_list %}
{% activity_item action %}
{% empty %}
<p>{% trans "No actions yet" %}</p>
{% endfor %}
</ul>
</article>
{% endfor %}
</div>
</div>
</div>
Expand Down
7 changes: 7 additions & 0 deletions geonode/social/templatetags/social_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import logging
from django import template
from django.utils.translation import ugettext_lazy as _

from geonode.utils import get_subclasses_by_model

register = template.Library()
logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -71,6 +74,10 @@ def activity_item(action, **kwargs):

# Set the item's class based on the object.
if object:
geoapps = [app.lower() for app in get_subclasses_by_model('GeoApp')]
if object_type in geoapps:
activity_class = object_type

if object_type == 'comment':
activity_class = 'comment'
preposition = _("on")
Expand Down
22 changes: 18 additions & 4 deletions geonode/social/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,29 @@
"""
import json

from geonode.tests.base import GeoNodeBaseTestSupport
from rest_framework import status

from actstream import registry
from actstream.models import Action, actor_stream
from dialogos.models import Comment

from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext as _
from django.urls import reverse

from geonode.tests.base import GeoNodeBaseTestSupport
from geonode.layers.populate_layers_data import create_layer_data
from geonode.social.templatetags.social_tags import activity_item
from geonode.layers.models import Layer
from dialogos.models import Comment


class SimpleTest(GeoNodeBaseTestSupport):
class RecentActivityTest(GeoNodeBaseTestSupport):

integration = True

def setUp(self):
super(SimpleTest, self).setUp()
super(RecentActivityTest, self).setUp()

registry.register(Layer)
registry.register(Comment)
Expand Down Expand Up @@ -140,3 +144,13 @@ def test_layer_activity(self):

# Pre-fecthing actstream breaks the actor stream
self.assertIn(action, actor_stream(self.user))

def test_get_recent_activities(self):
url = reverse('recent-activity')
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIsNotNone(response.context_data['action_list_geoapps'])
self.assertIsNotNone(response.context_data['action_list_layers'])
self.assertIsNotNone(response.context_data['action_list_maps'])
self.assertIsNotNone(response.context_data['action_list_documents'])
self.assertIsNotNone(response.context_data['action_list_comments'])
69 changes: 45 additions & 24 deletions geonode/social/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from django.core.exceptions import PermissionDenied

from geonode.base.models import ResourceBase
from geonode.utils import get_subclasses_by_model

logger = logging.getLogger(__name__)

Expand All @@ -37,36 +38,32 @@ class RecentActivity(ListView):
template_name = 'social/activity_list.html'

def get_context_data(self, *args, **kwargs):
context = super(RecentActivity, self).get_context_data(*args, **kwargs)
context = super().get_context_data(*args, **kwargs)

def _filter_actions(action, request):
geoapps_actions = {}
if action == 'all':
_actions = Action.objects.filter(public=True)[:100]
elif action == 'geoapp':
# Create a dictionary mapping for each app
apps = [app.lower() for app in get_subclasses_by_model('GeoApp')]
for app in apps:
app_actions = Action.objects.filter(
public=True, action_object_content_type__model=app)[:100]
geoapps_actions[app] = app_actions
_actions = geoapps_actions
else:
_actions = Action.objects.filter(
public=True, action_object_content_type__model=action)[:100]
_filtered_actions = []
for _action in _actions:
if _action.target_object_id:
action_object_filter = {
'id': _action.target_object_id
}
elif _action.action_object_object_id:
action_object_filter = {
'id': _action.action_object_object_id
}
try:
obj = get_object_or_404(ResourceBase, **action_object_filter)
resource = obj.get_self_resource()
user = request.user
if user.has_perm('base.view_resourcebase', resource) or \
user.has_perm('view_resourcebase', resource):
_filtered_actions.append(_action.id)
except ResourceBase.DoesNotExist:
_filtered_actions.append(_action.id)
except (PermissionDenied, Exception) as e:
logger.debug(e)
return _filtered_actions
if isinstance(_actions, dict):
# For Geoapps, return a dict mapping of each app with its actions
_filtered_actions = {}
for app_name, actions, in _actions.items():
filtered = self.get_filtered_actions(request.user, actions)
_filtered_actions[app_name] = Action.objects.filter(id__in=filtered)[:15]
return _filtered_actions
else:
return self.get_filtered_actions(request.user, _actions)

context['action_list'] = Action.objects.filter(
id__in=_filter_actions('all', self.request))[:15]
Expand All @@ -78,8 +75,32 @@ def _filter_actions(action, request):
id__in=_filter_actions('document', self.request))[:15]
context['action_list_comments'] = Action.objects.filter(
id__in=_filter_actions('comment', self.request))[:15]
context['action_list_geoapps'] = _filter_actions('geoapp', self.request)
return context

def get_filtered_actions(self, user, _actions):
_filtered_actions = []
for _action in _actions:
if _action.target_object_id:
action_object_filter = {
'id': _action.target_object_id
}
elif _action.action_object_object_id:
action_object_filter = {
'id': _action.action_object_object_id
}
try:
obj = get_object_or_404(ResourceBase, **action_object_filter)
resource = obj.get_self_resource()
if user.has_perm('base.view_resourcebase', resource) or \
user.has_perm('view_resourcebase', resource):
_filtered_actions.append(_action.id)
except ResourceBase.DoesNotExist:
_filtered_actions.append(_action.id)
except (PermissionDenied, Exception) as e:
logger.debug(e)
return _filtered_actions


class UserActivity(ListView):
"""
Expand All @@ -95,6 +116,6 @@ def get_queryset(self):
if x and x.actor and x.actor.username == self.kwargs['actor']]

def get_context_data(self, *args, **kwargs):
context = super(UserActivity, self).get_context_data(*args, **kwargs)
context = super().get_context_data(*args, **kwargs)
context['actor'] = self.kwargs['actor']
return context
22 changes: 22 additions & 0 deletions geonode/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,28 @@ def verify_image(stream):
return False


def get_subclasses_by_model(model: str):
from django.apps import apps
_app_subclasses = []
for _model in apps.get_models():
if _model.__name__ == model:
models = [(y.name, y.default_model) for x, y in apps.app_configs.items() if hasattr(y, 'default_model')]
for m in models:
if m[0] in settings.INSTALLED_APPS:
_app_subclasses.append(m[1])
return _app_subclasses


def get_geoapps_models():
# Get models which are of subclass 'GeoApp'
models = []
for x, y in django_apps.app_configs.items():
if hasattr(y, 'type') and y.type == 'GEONODE_APP' and hasattr(y, 'default_model'):
if y.name in settings.INSTALLED_APPS:
models.append(y)
return models


def find_by_attr(lst, val, attr="id"):
""" Returns an object if the id matches in any list of objects """
for item in lst:
Expand Down

0 comments on commit 5a43c4d

Please sign in to comment.