Skip to content

Commit

Permalink
Merge branch 'master' of github.com:okfn/ckan
Browse files Browse the repository at this point in the history
  • Loading branch information
Sean Hammond committed Nov 27, 2012
2 parents 3b84c92 + a96757e commit bc17953
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 284 deletions.
2 changes: 1 addition & 1 deletion ckan/controllers/group.py
Expand Up @@ -342,7 +342,7 @@ def _force_reindex(self, grp):
appearing on the read page for the group (as they're connected via
the group name)'''
group = model.Group.get(grp['name'])
for dataset in group.active_packages().all():
for dataset in group.packages():
search.rebuild(dataset.name)

def _save_edit(self, id, context):
Expand Down
2 changes: 1 addition & 1 deletion ckan/lib/dictization/model_dictize.py
Expand Up @@ -32,7 +32,7 @@ def group_list_dictize(obj_list, context,
group_dict['display_name'] = obj.display_name

group_dict['packages'] = \
len(obj.active_packages(with_private=with_private).all())
len(obj.packages(with_private=with_private))

if context.get('for_view'):
for item in plugins.PluginImplementations(
Expand Down
53 changes: 9 additions & 44 deletions ckan/logic/action/get.py
Expand Up @@ -750,34 +750,22 @@ def group_package_show(context, data_dict):
:rtype: list of dictionaries
'''
model = context["model"]
user = context["user"]
id = _get_or_bust(data_dict, 'id')
limit = data_dict.get("limit")
model = context['model']
group_id = _get_or_bust(data_dict, 'id')

group = model.Group.get(id)
# FIXME: What if limit is not an int? Schema and validation needed.
limit = data_dict.get('limit')

group = model.Group.get(group_id)
context['group'] = group
if group is None:
raise NotFound

_check_access('group_show', context, data_dict)

query = model.Session.query(model.PackageRevision)\
.filter(model.PackageRevision.state=='active')\
.filter(model.PackageRevision.current==True)\
.join(model.Member, model.Member.table_id==model.PackageRevision.id)\
.join(model.Group, model.Group.id==model.Member.group_id)\
.filter_by(id=group.id)\
.order_by(model.PackageRevision.name)

if limit:
query = query.limit(limit)

if context.get('return_query'):
return query

result = []
for pkg_rev in query.all():
for pkg_rev in group.packages(limit=limit,
return_query=context.get('return_query')):
result.append(model_dictize.package_dictize(pkg_rev, context))

return result
Expand Down Expand Up @@ -1779,30 +1767,7 @@ def group_activity_list(context, data_dict):
group_show = logic.get_action('group_show')
group_id = group_show(context, {'id': group_id})['id']

# FIXME: The SQLAlchemy below should be moved into ckan/model/activity.py
# (to encapsulate SQLALchemy in the model and avoid using it from the
# logic) but it can't be because it requires the list of dataset_ids which
# comes from logic.group_package_show() (and I don't want to access the
# logic from the model). Need to change it to get the dataset_ids from the
# model instead. There seems to be multiple methods for getting a group's
# datasets, some in the logic and some in the model.

# Get a list of the IDs of the group's datasets.
group_package_show = logic.get_action('group_package_show')
datasets = group_package_show(context, {'id': group_id})
dataset_ids = [dataset['id'] for dataset in datasets]

# Get the group's activities.
query = model.Session.query(model.Activity)
if dataset_ids:
query = query.filter(_or_(model.Activity.object_id == group_id,
model.Activity.object_id.in_(dataset_ids)))
else:
query = query.filter(model.Activity.object_id == group_id)
query = query.order_by(_desc(model.Activity.timestamp))
query = query.limit(15)
activity_objects = query.all()

activity_objects = model.activity.group_activity_list(group_id)
return model_dictize.activity_list_dictize(activity_objects, context)

def recently_changed_packages_activity_list(context, data_dict):
Expand Down
94 changes: 88 additions & 6 deletions ckan/model/activity.py
@@ -1,6 +1,6 @@
import datetime

from sqlalchemy import orm, types, Column, Table, ForeignKey, desc
from sqlalchemy import orm, types, Column, Table, ForeignKey, desc, or_

import meta
import types as _types
Expand Down Expand Up @@ -69,6 +69,7 @@ def __init__(self, activity_id, object_id, object_type, activity_type,


def _most_recent_activities(q, limit):
'''Return the 'limit' most recent activites from activity query 'q'.'''
import ckan.model as model
q = q.order_by(desc(model.Activity.timestamp))
if limit:
Expand All @@ -77,30 +78,33 @@ def _most_recent_activities(q, limit):


def _activities_from_user_query(user_id):
'''Return an SQLAlchemy query for all activities from user_id.'''
import ckan.model as model
q = model.Session.query(model.Activity)
q = q.filter(model.Activity.user_id == user_id)
return q


def _activities_about_user_query(user_id):
'''Return an SQLAlchemy query for all activities about user_id.'''
import ckan.model as model
q = model.Session.query(model.Activity)
q = q.filter(model.Activity.object_id == user_id)
return q


def _user_activity_query(user_id):
'''Return an SQLAlchemy query for all activities from or about user_id.'''
q = _activities_from_user_query(user_id)
q = q.union(_activities_about_user_query(user_id))
return q


def user_activity_list(user_id, limit=15):
'''Return the given user's public activity stream.
'''Return user_id's public activity stream.
Returns all activities from or about the given user, i.e. where the given
user is the subject or object of the activity, e.g.:
Return a list of all activities from or about the given user, i.e. where
the given user is the subject or object of the activity, e.g.:
"{USER} created the dataset {DATASET}"
"{OTHER_USER} started following {USER}"
Expand All @@ -112,6 +116,9 @@ def user_activity_list(user_id, limit=15):


def _package_activity_query(package_id):
'''Return an SQLAlchemy query for all activities about package_id.
'''
import ckan.model as model
q = model.Session.query(model.Activity)
q = q.filter_by(object_id=package_id)
Expand All @@ -133,7 +140,44 @@ def package_activity_list(package_id, limit=15):
return _most_recent_activities(q, limit)


def _group_activity_query(group_id, limit=15):
'''Return an SQLAlchemy query for all activities about group_id.
Returns a query for all activities whose object is either the group itself
or one of the group's datasets.
'''
import ckan.model as model

group = model.Group.get(group_id)
dataset_ids = [dataset.id for dataset in group.packages()]

q = model.Session.query(model.Activity)
if dataset_ids:
q = q.filter(or_(model.Activity.object_id == group_id,
model.Activity.object_id.in_(dataset_ids)))
else:
q = q.filter(model.Activity.object_id == group_id)
return q


def group_activity_list(group_id, limit=15):
'''Return the given group's public activity stream.
Returns all activities where the given group or one of its datasets is the
object of the activity, e.g.:
"{USER} updated the group {GROUP}"
"{USER} updated the dataset {DATASET}"
etc.
'''
q = _group_activity_query(group_id)
return _most_recent_activities(q, limit)


def _activites_from_users_followed_by_user_query(user_id):
'''Return a query for all activities from users that user_id follows.'''
import ckan.model as model
q = model.Session.query(model.Activity)
q = q.join(model.UserFollowingUser,
Expand All @@ -143,6 +187,7 @@ def _activites_from_users_followed_by_user_query(user_id):


def _activities_from_datasets_followed_by_user_query(user_id):
'''Return a query for all activities from datasets that user_id follows.'''
import ckan.model as model
q = model.Session.query(model.Activity)
q = q.join(model.UserFollowingDataset,
Expand All @@ -151,9 +196,33 @@ def _activities_from_datasets_followed_by_user_query(user_id):
return q


def _activities_from_groups_followed_by_user_query(user_id):
'''Return a query for all activities about groups the given user follows.
Return a query for all activities about the groups the given user follows,
or about any of the group's datasets. This is the union of
_group_activity_query(group_id) for each of the groups the user follows.
'''
import ckan.model as model

# Get a list of the group's that the user is following.
follower_objects = model.UserFollowingGroup.followee_list(user_id)
if not follower_objects:
# Return a query with no results.
return model.Session.query(model.Activity).filter("0=1")

q = _group_activity_query(follower_objects[0].object_id)
q = q.union_all(*[_group_activity_query(follower.object_id)
for follower in follower_objects[1:]])
return q


def _activities_from_everything_followed_by_user_query(user_id):
'''Return a query for all activities from everything user_id follows.'''
q = _activites_from_users_followed_by_user_query(user_id)
q = q.union(_activities_from_datasets_followed_by_user_query(user_id))
q = q.union(_activities_from_groups_followed_by_user_query(user_id))
return q


Expand All @@ -169,6 +238,7 @@ def activities_from_everything_followed_by_user(user_id, limit=15):


def _dashboard_activity_query(user_id):
'''Return an SQLAlchemy query for user_id's dashboard activity stream.'''
q = _user_activity_query(user_id)
q = q.union(_activities_from_everything_followed_by_user_query(user_id))
return q
Expand All @@ -188,13 +258,25 @@ def dashboard_activity_list(user_id, limit=15):
return _most_recent_activities(q, limit)


def _recently_changed_packages_activity_query():
def _changed_packages_activity_query():
'''Return an SQLAlchemyu query for all changed package activities.
Return a query for all activities with activity_type '*package', e.g.
'new_package', 'changed_package', 'deleted_package'.
'''
import ckan.model as model
q = model.Session.query(model.Activity)
q = q.filter(model.Activity.activity_type.endswith('package'))
return q


def recently_changed_packages_activity_list(limit=15):
q = _recently_changed_packages_activity_query()
'''Return the site-wide stream of recently changed package activities.
This activity stream includes recent 'new package', 'changed package' and
'deleted package' activities for the whole site.
'''
q = _changed_packages_activity_query()
return _most_recent_activities(q, limit)
88 changes: 38 additions & 50 deletions ckan/model/group.py
Expand Up @@ -143,35 +143,6 @@ def set_approval_status(self, status):
if status == "denied":
pass

def members_of_type(self, object_type, capacity=None):
from ckan import model
object_type_string = object_type.__name__.lower()
query = meta.Session.query(object_type).\
filter(model.Group.id == self.id).\
filter(model.Member.state == 'active').\
filter(model.Member.table_name == object_type_string)

if hasattr(object_type, 'state'):
query = query.filter(object_type.state == 'active')

if capacity:
query = query.filter(model.Member.capacity == capacity)

query = query.join(model.Member, member_table.c.table_id ==
getattr(object_type, 'id')).\
join(model.Group, group_table.c.id == member_table.c.group_id)

return query

def add_child(self, object_instance):
object_type_string = object_instance.__class__.__name__.lower()
if not object_instance in self.members_of_type(
object_instance.__class__).all():
member = Member(group=self,
table_id=getattr(object_instance, 'id'),
table_name=object_type_string)
meta.Session.add(member)

def get_children_groups(self, type='group'):
# Returns a list of dicts where each dict contains "id", "name",
# and "title" When querying with a CTE specifying a model in the
Expand All @@ -184,20 +155,48 @@ def get_children_groups(self, type='group'):
return [{"id":idf, "name": name, "title": title}
for idf, name, title in results]

def active_packages(self, load_eager=True, with_private=False):
query = meta.Session.query(_package.Package).\
filter_by(state=vdm.sqlalchemy.State.ACTIVE).\
filter(group_table.c.id == self.id).\
filter(member_table.c.state == 'active')
def packages(self, with_private=False, limit=None,
return_query=False):
'''Return this group's active and pending packages.
Returns all packages in this group with VDM revision state ACTIVE or
PENDING.
:param with_private: if True, include the group's private packages
:type with_private: boolean
:param limit: the maximum number of packages to return
:type limit: int
:param return_query: if True, return the SQLAlchemy query object
instead of the list of Packages resulting from the query
:type return_query: boolean
:returns: a list of this group's packages
:rtype: list of ckan.model.package.Package objects
'''
query = meta.Session.query(_package.Package)
query = query.filter(
or_(_package.Package.state == vdm.sqlalchemy.State.ACTIVE,
_package.Package.state == vdm.sqlalchemy.State.PENDING))
query = query.filter(group_table.c.id == self.id)

if not with_private:
query = query.filter(member_table.c.capacity == 'public')

query = query.join(member_table, member_table.c.table_id ==
_package.Package.id).\
join(group_table, group_table.c.id == member_table.c.group_id)
query = query.join(member_table,
member_table.c.table_id == _package.Package.id)
query = query.join(group_table,
group_table.c.id == member_table.c.group_id)

if limit is not None:
query = query.limit(limit)

return query
if return_query:
return query
else:
return query.all()

@classmethod
def search_by_name_or_title(cls, text_query, group_type=None):
Expand All @@ -209,23 +208,12 @@ def search_by_name_or_title(cls, text_query, group_type=None):
q = q.filter(cls.type == group_type)
return q.order_by(cls.title)

def as_dict(self, ref_package_by='name'):
_dict = domain_object.DomainObject.as_dict(self)
_dict['packages'] = [getattr(package, ref_package_by)
for package in self.packages]
_dict['extras'] = dict([(key, value) for key, value
in self.extras.items()])
if (self.type == 'organization'):
_dict['users'] = [getattr(user, "name")
for user in self.members_of_type(_user.User)]
return _dict

def add_package_by_name(self, package_name):
if not package_name:
return
package = _package.Package.by_name(package_name)
assert package
if not package in self.members_of_type(package.__class__).all():
if not package in self.packages():
member = Member(group=self, table_id=package.id,
table_name='package')
meta.Session.add(member)
Expand Down

0 comments on commit bc17953

Please sign in to comment.