Skip to content

Commit

Permalink
Merge branch '2375-demo-theme-development' into 2618-nested-resources
Browse files Browse the repository at this point in the history
Conflicts:
	ckan/controllers/home.py

trivial merge

	ckan/templates/snippets/scripts.html

extra module added
  • Loading branch information
tobes committed Aug 15, 2012
2 parents 987dde5 + 36bd991 commit abfd030
Show file tree
Hide file tree
Showing 112 changed files with 2,389 additions and 1,036 deletions.
2 changes: 1 addition & 1 deletion ckan/__init__.py
@@ -1,4 +1,4 @@
__version__ = '1.9a'
__version__ = '2.0a'
__description__ = 'Comprehensive Knowledge Archive Network (CKAN) Software'
__long_description__ = \
'''CKAN software provides a hub for datasets. The flagship site running CKAN
Expand Down
5 changes: 3 additions & 2 deletions ckan/config/environment.py
Expand Up @@ -175,6 +175,8 @@ def find_controller(self, controller):

config['routes.map'] = routing.make_map()
config['pylons.app_globals'] = app_globals.app_globals
# initialise the globals
config['pylons.app_globals']._init()

# add helper functions
restrict_helpers = asbool(
Expand Down Expand Up @@ -296,8 +298,7 @@ def genshi_lookup_attr(cls, obj, key):

# Create Jinja2 environment
env = lib.jinja_extensions.Environment(
loader=lib.jinja_extensions.CkanFileSystemLoader(template_paths,
ckan_base_path=paths['templates'][0]),
loader=lib.jinja_extensions.CkanFileSystemLoader(template_paths),
autoescape=True,
extensions=['jinja2.ext.i18n', 'jinja2.ext.do', 'jinja2.ext.with_',
lib.jinja_extensions.SnippetExtension,
Expand Down
4 changes: 2 additions & 2 deletions ckan/config/middleware.py
Expand Up @@ -201,10 +201,10 @@ def __call__(self, environ, start_response):
path_info = '/'.join(urllib.quote(pce,'') for pce in path_info.split('/'))

qs = environ.get('QUERY_STRING')
# sort out weird encodings
qs = urllib.quote(qs, '')

if qs:
# sort out weird encodings
#qs = urllib.quote(qs, '')
environ['CKAN_CURRENT_URL'] = '%s?%s' % (path_info, qs)
else:
environ['CKAN_CURRENT_URL'] = path_info
Expand Down
4 changes: 2 additions & 2 deletions ckan/config/routing.py
Expand Up @@ -330,8 +330,8 @@ def make_map():
with SubMapper(map, controller='util') as m:
m.connect('/i18n/strings_{lang}.js', action='i18n_js_strings')
m.connect('/util/redirect', action='redirect')
m.connect('/test/primer', action='primer')
m.connect('/test/markup', action='markup')
m.connect('/testing/primer', action='primer')
m.connect('/testing/markup', action='markup')

for plugin in routing_plugins:
map = plugin.after_map(map)
Expand Down
11 changes: 8 additions & 3 deletions ckan/controllers/group.py
Expand Up @@ -34,7 +34,7 @@ def _form_to_db_schema(self, group_type=None):
def _db_to_form_schema(self, group_type=None):
'''This is an interface to manipulate data from the database
into a format suitable for the form (optional)'''
return lookup_group_plugin(group_type).form_to_db_schema()
return lookup_group_plugin(group_type).db_to_form_schema()

def _setup_template_variables(self, context, data_dict, group_type=None):
return lookup_group_plugin(group_type).\
Expand Down Expand Up @@ -100,7 +100,7 @@ def read(self, id):
group_type = self._get_group_type(id.split('@')[0])
context = {'model': model, 'session': model.Session,
'user': c.user or c.author,
'schema': self._form_to_db_schema(group_type=group_type),
'schema': self._db_to_form_schema(group_type=group_type),
'for_view': True, 'extras_as_string': True}
data_dict = {'id': id}
# unicode format (decoded from utf8)
Expand Down Expand Up @@ -139,6 +139,7 @@ def read(self, id):
# most search operations should reset the page counter:
params_nopage = [(k, v) for k, v in request.params.items()
if k != 'page']
sort_by = request.params.get('sort', 'name asc')

def search_url(params):
url = h.url_for(controller='group', action='read',
Expand Down Expand Up @@ -171,7 +172,7 @@ def pager_url(q=None, page=None):
c.fields = []
search_extras = {}
for (param, value) in request.params.items():
if not param in ['q', 'page'] \
if not param in ['q', 'page', 'sort'] \
and len(value) and not param.startswith('_'):
if not param.startswith('ext_'):
c.fields.append((param, value))
Expand All @@ -189,6 +190,7 @@ def pager_url(q=None, page=None):
'fq': fq,
'facet.field': g.facets,
'rows': limit,
'sort': sort_by,
'start': (page - 1) * limit,
'extras': search_extras
}
Expand Down Expand Up @@ -218,6 +220,9 @@ def pager_url(q=None, page=None):
limit = int(request.params.get('_%s_limit' % facet, 10))
c.search_facets_limits[facet] = limit
c.page.items = query['results']

c.sort_by_selected = sort_by

except SearchError, se:
log.error('Group search error: %r', se.args)
c.query_error = True
Expand Down
48 changes: 35 additions & 13 deletions ckan/controllers/home.py
Expand Up @@ -121,37 +121,59 @@ def _get_group_type(id):
return None
return group.type

def _form_to_db_schema(group_type=None):
def db_to_form_schema(group_type=None):
from ckan.lib.plugins import lookup_group_plugin
return lookup_group_plugin(group_type).form_to_db_schema()
return lookup_group_plugin(group_type).db_to_form_schema()

group_type = _get_group_type(id.split('@')[0])
context = {'model': model, 'session': model.Session,
'ignore_auth': True,
'user': c.user or c.author,
'schema': _form_to_db_schema(group_type=group_type),
'schema': db_to_form_schema(group_type=group_type),
'for_view': True}
data_dict = {'id': id}

try:
group_dict = ckan.logic.get_action('group_show')(context, data_dict)
except ckan.logic.NotFound:
return {'group_dict' :{}}
return None

# We get all the packages or at least too many so
# limit it to just 2
group_dict['packages'] = group_dict['packages'][:2]
return {'group_dict': group_dict}
return {'group_dict' :group_dict}

global dirty_cached_group_stuff
if not dirty_cached_group_stuff:
# ARON
# uncomment the first for testing
# the second for demo - different data
#dirty_cached_group_stuff = [get_group('access-to-medicines'), get_group('archaeology')]
dirty_cached_group_stuff = [get_group('data-explorer'), get_group('geo-examples')]
groups_data = []
groups = config.get('demo.featured_groups', '').split()

for group_name in groups:
group = get_group(group_name)
if group:
groups_data.append(group)
if len(groups_data) == 2:
break

# c.groups is from the solr query above
if len(groups_data) < 2 and len(c.groups) > 0:
group = get_group(c.groups[0]['name'])
if group:
groups_data.append(group)
if len(groups_data) < 2 and len(c.groups) > 1:
group = get_group(c.groups[1]['name'])
if group:
groups_data.append(group)
# We get all the packages or at least too many so
# limit it to just 2
for group in groups_data:
group['group_dict']['packages'] = group['group_dict']['packages'][:2]
#now add blanks so we have two
while len(groups_data) < 2:
groups_data.append({'group_dict' :{}})
# cache for later use
dirty_cached_group_stuff = groups_data


c.group_package_stuff = dirty_cached_group_stuff

# END OF DIRTYNESS

return render('home/index.html', cache_force=True)
Expand Down
2 changes: 1 addition & 1 deletion ckan/controllers/storage.py
Expand Up @@ -270,7 +270,7 @@ def get_metadata(self, label):
qualified=False
)
if url.startswith('/'):
url = config.get('ckan.site_url','') + url
url = config.get('ckan.site_url','').rstrip('/') + '/' + url

if not self.ofs.exists(bucket, label):
abort(404)
Expand Down
8 changes: 7 additions & 1 deletion ckan/controllers/user.py
Expand Up @@ -399,12 +399,18 @@ def request_reset(self):

def perform_reset(self, id):
context = {'model': model, 'session': model.Session,
'user': c.user}
'user': c.user,
'keep_sensitive_data': True}

data_dict = {'id': id}

try:
user_dict = get_action('user_show')(context, data_dict)

# Be a little paranoid, and get rid of sensitive data that's
# not needed.
user_dict.pop('apikey', None)
user_dict.pop('reset_key', None)
user_obj = context['user_obj']
except NotFound, e:
abort(404, _('User not found'))
Expand Down
191 changes: 191 additions & 0 deletions ckan/lib/activity_streams.py
@@ -0,0 +1,191 @@
import re

from pylons.i18n import _
from webhelpers.html import literal

import ckan.lib.helpers as h
import ckan.lib.base as base
import ckan.logic as logic

# get_snippet_*() functions replace placeholders like {user}, {dataset}, etc.
# in activity strings with HTML representations of particular users, datasets,
# etc.

def get_snippet_actor(activity, detail):
return h.linked_user(activity['user_id'])

def get_snippet_user(activity, detail):
return h.linked_user(activity['data']['user']['name'])

def get_snippet_dataset(activity, detail):
data = activity['data']
return h.dataset_link(data.get('package') or data.get('dataset'))

def get_snippet_tag(activity, detail):
return h.tag_link(detail['data']['tag'])

def get_snippet_group(activity, detail):
return h.group_link(activity['data']['group'])

def get_snippet_extra(activity, detail):
return '"%s"' % detail['data']['package_extra']['key']

def get_snippet_resource(activity, detail):
return h.resource_link(detail['data']['resource'],
activity['data']['package']['id'])

def get_snippet_related_item(activity, detail):
return h.related_item_link(activity['data']['related'])

def get_snippet_related_type(activity, detail):
# FIXME this needs to be translated
return activity['data']['related']['type']

# activity_stream_string_*() functions return translatable string
# representations of activity types, the strings contain placeholders like
# {user}, {dataset} etc. to be replaced with snippets from the get_snippet_*()
# functions above.

def activity_stream_string_added_tag():
return _("{actor} added the tag {tag} to the dataset {dataset}")

def activity_stream_string_changed_group():
return _("{actor} updated the group {group}")

def activity_stream_string_changed_package():
return _("{actor} updated the dataset {dataset}")

def activity_stream_string_changed_package_extra():
return _("{actor} changed the extra {extra} of the dataset {dataset}")

def activity_stream_string_changed_resource():
return _("{actor} updated the resource {resource} in the dataset {dataset}")

def activity_stream_string_changed_user():
return _("{actor} updated their profile")

def activity_stream_string_deleted_group():
return _("{actor} deleted the group {group}")

def activity_stream_string_deleted_package():
return _("{actor} deleted the dataset {dataset}")

def activity_stream_string_deleted_package_extra():
return _("{actor} deleted the extra {extra} from the dataset {dataset}")

def activity_stream_string_deleted_resource():
return _("{actor} deleted the resource {resource} from the dataset {dataset}")

def activity_stream_string_new_group():
return _("{actor} created the group {group}")

def activity_stream_string_new_package():
return _("{actor} created the dataset {dataset}")

def activity_stream_string_new_package_extra():
return _("{actor} added the extra {extra} to the dataset {dataset}")

def activity_stream_string_new_resource():
return _("{actor} added the resource {resource} to the dataset {dataset}")

def activity_stream_string_new_user():
return _("{actor} signed up")

def activity_stream_string_removed_tag():
return _("{actor} removed the tag {tag} from the dataset {dataset}")

def activity_stream_string_deleted_related_item():
return _("{actor} deleted the related item {related_item}")

def activity_stream_string_follow_dataset():
return _("{actor} started following {dataset}")

def activity_stream_string_follow_user():
return _("{actor} started following {user}")

def activity_stream_string_new_related_item():
return _("{actor} created the link to related {related_type} {related_item}")

# A dictionary mapping activity snippets to functions that expand the snippets.
activity_snippet_functions = {
'actor': get_snippet_actor,
'user': get_snippet_user,
'dataset': get_snippet_dataset,
'tag': get_snippet_tag,
'group': get_snippet_group,
'extra': get_snippet_extra,
'resource': get_snippet_resource,
'related_item': get_snippet_related_item,
'related_type': get_snippet_related_type,
}

# A dictionary mapping activity types to functions that return translatable
# string descriptions of the activity types.
activity_stream_string_functions = {
'added tag': activity_stream_string_added_tag,
'changed group': activity_stream_string_changed_group,
'changed package': activity_stream_string_changed_package,
'changed package_extra': activity_stream_string_changed_package_extra,
'changed resource': activity_stream_string_changed_resource,
'changed user': activity_stream_string_changed_user,
'deleted group': activity_stream_string_deleted_group,
'deleted package': activity_stream_string_deleted_package,
'deleted package_extra': activity_stream_string_deleted_package_extra,
'deleted resource': activity_stream_string_deleted_resource,
'new group': activity_stream_string_new_group,
'new package': activity_stream_string_new_package,
'new package_extra': activity_stream_string_new_package_extra,
'new resource': activity_stream_string_new_resource,
'new user': activity_stream_string_new_user,
'removed tag': activity_stream_string_removed_tag,
'deleted related item': activity_stream_string_deleted_related_item,
'follow dataset': activity_stream_string_follow_dataset,
'follow user': activity_stream_string_follow_user,
'new related item': activity_stream_string_new_related_item,
}

# A list of activity types that may have details
activity_stream_actions_with_detail = ['changed package']

def activity_list_to_html(context, activity_stream):
'''Return the given activity stream as a snippet of HTML.'''

activity_list = [] # These are the activity stream messages.
for activity in activity_stream:
detail = None
activity_type = activity['activity_type']
# Some activity types may have details.
if activity_type in activity_stream_actions_with_detail:
details = logic.get_action('activity_detail_list')(context=context,
data_dict={'id': activity['id']})
# If an activity has just one activity detail then render the
# detail instead of the activity.
if len(details) == 1:
detail = details[0]
object_type = detail['object_type']

if object_type == 'PackageExtra':
object_type = 'package_extra'

new_activity_type = '%s %s' % (detail['activity_type'],
object_type.lower())
if new_activity_type in activity_stream_string_functions:
activity_type = new_activity_type

if not activity_type in activity_stream_string_functions:
raise NotImplementedError("No activity renderer for activity "
"type '%s'" % str(activity_type))

activity_msg = activity_stream_string_functions[activity_type]()

# Get the data needed to render the message.
matches = re.findall('\{([^}]*)\}', activity_msg)
data = {}
for match in matches:
snippet = activity_snippet_functions[match](activity, detail)
data[str(match)] = snippet
activity_list.append({'msg': activity_msg,
'data': data,
'timestamp': activity['timestamp']})
return literal(base.render('activity_streams/activity_stream_items.html',
extra_vars={'activities': activity_list}))
File renamed without changes.

0 comments on commit abfd030

Please sign in to comment.