diff --git a/ckan/controllers/tag.py b/ckan/controllers/tag.py
index bc45347db75..a736c17e8d0 100644
--- a/ckan/controllers/tag.py
+++ b/ckan/controllers/tag.py
@@ -1,5 +1,5 @@
from pylons.i18n import _
-from pylons import request, c
+from pylons import request, c, config
import ckan.logic as logic
import ckan.model as model
@@ -65,4 +65,7 @@ def read(self, id):
except logic.NotFound:
base.abort(404, _('Tag not found'))
- return base.render('tag/read.html')
+ if h.asbool(config.get('ckan.legacy_templates', False)):
+ return base.render('tag/read.html')
+ else:
+ h.redirect_to(controller='package', action='search', tags=c.tag.get('name'))
diff --git a/ckan/lib/activity_streams_session_extension.py b/ckan/lib/activity_streams_session_extension.py
index 08a6e37756c..e1945657462 100644
--- a/ckan/lib/activity_streams_session_extension.py
+++ b/ckan/lib/activity_streams_session_extension.py
@@ -1,7 +1,11 @@
+from pylons import config
from sqlalchemy.orm.session import SessionExtension
+from paste.deploy.converters import asbool
import logging
+
logger = logging.getLogger(__name__)
+
def activity_stream_item(obj, activity_type, revision, user_id):
method = getattr(obj, "activity_stream_item", None)
if callable(method):
@@ -11,6 +15,7 @@ def activity_stream_item(obj, activity_type, revision, user_id):
"activity_stream_item() method, it must not be a package.")
return None
+
def activity_stream_detail(obj, activity_id, activity_type):
method = getattr(obj, "activity_stream_detail",
None)
@@ -21,6 +26,7 @@ def activity_stream_detail(obj, activity_id, activity_type):
"activity_stream_detail() method.")
return None
+
class DatasetActivitySessionExtension(SessionExtension):
"""Session extension that emits activity stream activities for packages
and related objects.
@@ -36,6 +42,8 @@ class DatasetActivitySessionExtension(SessionExtension):
"""
def before_commit(self, session):
+ if not asbool(config.get('ckan.activity_streams_enabled', 'true')):
+ return
session.flush()
diff --git a/ckan/lib/app_globals.py b/ckan/lib/app_globals.py
index 18ea4610e30..ecd2847b072 100644
--- a/ckan/lib/app_globals.py
+++ b/ckan/lib/app_globals.py
@@ -109,9 +109,15 @@ def get_config_value(key, default=''):
value = model.get_system_info(key)
else:
value = None
+ config_value = config.get(key)
+ # sort encodeings if needed
+ if isinstance(config_value, str):
+ try:
+ config_value = config_value.decode('utf-8')
+ except UnicodeDecodeError:
+ config_value = config_value.decode('latin-1')
# we want to store the config the first time we get here so we can
# reset them if needed
- config_value = config.get(key)
if key not in _CONFIG_CACHE:
_CONFIG_CACHE[key] = config_value
if value is not None:
diff --git a/ckan/lib/dictization/model_dictize.py b/ckan/lib/dictization/model_dictize.py
index 70f9023f478..d61c68e73b1 100644
--- a/ckan/lib/dictization/model_dictize.py
+++ b/ckan/lib/dictization/model_dictize.py
@@ -399,15 +399,25 @@ def tag_dictize(tag, context):
tag_dict = d.table_dictize(tag, context)
query = search.PackageSearchQuery()
- q = {'q': '+tags:"%s" +capacity:public' % tag.name, 'fl': 'data_dict',
- 'wt': 'json', 'rows': 1000}
+ tag_query = u'+capacity:public '
+ vocab_id = tag_dict.get('vocabulary_id')
- package_dicts = [h.json.loads(result['data_dict']) for result in query.run(q)['results']]
+ if vocab_id:
+ model = context['model']
+ vocab = model.Vocabulary.get(vocab_id)
+ tag_query += u'+vocab_{0}:"{1}"'.format(vocab.name, tag.name)
+ else:
+ tag_query += u'+tags:"{0}"'.format(tag.name)
+
+ q = {'q': tag_query, 'fl': 'data_dict', 'wt': 'json', 'rows': 1000}
+
+ package_dicts = [h.json.loads(result['data_dict'])
+ for result in query.run(q)['results']]
# Add display_names to tags. At first a tag's display_name is just the
# same as its name, but the display_name might get changed later (e.g.
# translated into another language by the multilingual extension).
- assert not tag_dict.has_key('display_name')
+ assert 'display_name' not in tag_dict
tag_dict['display_name'] = tag_dict['name']
if context.get('for_view'):
diff --git a/ckan/lib/helpers.py b/ckan/lib/helpers.py
index 4c6be063221..840393fc2d8 100644
--- a/ckan/lib/helpers.py
+++ b/ckan/lib/helpers.py
@@ -1129,13 +1129,16 @@ def add_url_param(alternative_url=None, controller=None, action=None,
return _create_url_with_params(params=params, controller=controller,
action=action, extras=extras)
-
def remove_url_param(key, value=None, replace=None, controller=None,
action=None, extras=None, alternative_url=None):
- ''' Remove a key from the current parameters. A specific key/value
- pair can be removed by passing a second value argument otherwise all
- pairs matching the key will be removed. If replace is given then a
- new param key=replace will be added.
+ ''' Remove one or multiple keys from the current parameters.
+ The first parameter can be either a string with the name of the key to
+ remove or a list of keys to remove.
+ A specific key/value pair can be removed by passing a second value
+ argument otherwise all pairs matching the key will be removed. If replace
+ is given then a new param key=replace will be added.
+ Note that the value and replace parameters only apply to the first key
+ provided (or the only one provided if key is a string).
controller action & extras (dict) are used to create the base url
via url_for(controller=controller, action=action, **extras)
@@ -1144,14 +1147,20 @@ def remove_url_param(key, value=None, replace=None, controller=None,
This can be overriden providing an alternative_url, which will be used
instead.
'''
+ if isinstance(key, basestring):
+ keys = [key]
+ else:
+ keys = key
+
params_nopage = [(k, v) for k, v in request.params.items() if k != 'page']
params = list(params_nopage)
if value:
- params.remove((key, value))
+ params.remove((keys[0], value))
else:
- [params.remove((k, v)) for (k, v) in params[:] if k == key]
+ for key in keys:
+ [params.remove((k, v)) for (k, v) in params[:] if k == key]
if replace is not None:
- params.append((key, replace))
+ params.append((keys[0], replace))
if alternative_url:
return _url_with_params(alternative_url, params)
@@ -1441,6 +1450,26 @@ def resource_preview(resource, pkg_id):
resource_url=url,
raw_resource_url=resource.get('url'))
+def list_dict_filter(list_, search_field, output_field, value):
+ ''' Takes a list of dicts and returns the value of a given key if the
+ item has a matching value for a supplied key
+
+ :param list_: the list to search through for matching items
+ :type list_: list of dicts
+
+ :param search_field: the key to use to find matching items
+ :type search_field: string
+
+ :param output_field: the key to use to output the value
+ :type output_field: string
+
+ :param value: the value to search for
+ '''
+
+ for item in list_:
+ if item.get(search_field) == value:
+ return item.get(output_field, value)
+ return value
def SI_number_span(number):
''' outputs a span with the number in SI unit eg 14700 -> 14.7k '''
@@ -1539,6 +1568,7 @@ def SI_number_span(number):
'localised_SI_number',
'localised_nice_date',
'localised_filesize',
+ 'list_dict_filter',
# imported into ckan.lib.helpers
'literal',
'link_to',
diff --git a/ckan/lib/search/index.py b/ckan/lib/search/index.py
index d77d7cbfa12..9b50031df4b 100644
--- a/ckan/lib/search/index.py
+++ b/ckan/lib/search/index.py
@@ -157,12 +157,11 @@ def index_package(self, pkg_dict, defer_commit=False):
# if there is an owner_org we want to add this to groups for index
# purposes
- if pkg_dict['owner_org'] and pkg_dict.get('organization'):
+ if pkg_dict.get('organization'):
pkg_dict['organization'] = pkg_dict['organization']['name']
else:
pkg_dict['organization'] = None
-
# tracking
tracking_summary = pkg_dict.pop('tracking_summary', None)
if tracking_summary:
diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py
index f469333e2a8..323c5365214 100644
--- a/ckan/logic/action/create.py
+++ b/ckan/logic/action/create.py
@@ -1,7 +1,9 @@
import logging
+from pylons import config
from pylons.i18n import _
import ckan.new_authz as new_authz
+import ckan.lib.helpers as h
import ckan.lib.plugins as lib_plugins
import ckan.logic as logic
import ckan.rating as ratings
@@ -422,13 +424,14 @@ def member_create(context, data_dict=None):
filter(model.Member.table_name == obj_type).\
filter(model.Member.table_id == obj_id).\
filter(model.Member.group_id == group.id).\
- filter(model.Member.state == "active").first()
+ filter(model.Member.state == "active").first()
if member:
member.capacity = capacity
else:
member = model.Member(table_name = obj_type,
table_id = obj_id,
group_id = group.id,
+ state = 'active',
capacity=capacity)
model.Session.add(member)
@@ -888,6 +891,9 @@ def activity_create(context, activity_dict, ignore_auth=False):
:rtype: dictionary
'''
+ if not h.asbool(config.get('ckan.activity_streams_enabled', 'true')):
+ return
+
model = context['model']
# Any revision_id that the caller attempts to pass in the activity_dict is
diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
index c834b30cd1d..9340a7b0c9c 100644
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -262,6 +262,9 @@ def member_list(context, data_dict=None):
model = context['model']
group = model.Group.get(_get_or_bust(data_dict, 'id'))
+ if not group:
+ raise NotFound
+
obj_type = data_dict.get('object_type', None)
capacity = data_dict.get('capacity', None)
@@ -269,33 +272,23 @@ def member_list(context, data_dict=None):
_check_access('group_show', context, data_dict)
q = model.Session.query(model.Member).\
- filter(model.Member.group_id == group.id).\
- filter(model.Member.state == "active")
+ filter(model.Member.group_id == group.id).\
+ filter(model.Member.state == "active")
if obj_type:
q = q.filter(model.Member.table_name == obj_type)
if capacity:
q = q.filter(model.Member.capacity == capacity)
- lookup = {}
- def type_lookup(name):
- if name in lookup:
- return lookup[name]
- if hasattr(model, name.title()):
- lookup[name] = getattr(model,name.title())
- return lookup[name]
- return None
-
trans = new_authz.roles_trans()
+
def translated_capacity(capacity):
try:
return trans[capacity]
except KeyError:
return capacity
- return [(m.table_id,
- type_lookup(m.table_name),
- translated_capacity(m.capacity),)
+ return [(m.table_id, m.table_name, translated_capacity(m.capacity))
for m in q.all()]
def _group_or_org_list(context, data_dict, is_org=False):
diff --git a/ckan/logic/validators.py b/ckan/logic/validators.py
index dad232a2318..4b448168670 100644
--- a/ckan/logic/validators.py
+++ b/ckan/logic/validators.py
@@ -18,7 +18,7 @@ def owner_org_validator(key, data, errors, context):
value = data.get(key)
- if value is missing or value is None:
+ if value is missing or not value:
if not ckan.new_authz.check_config_permission('create_unowned_dataset'):
raise Invalid(_('A organization must be supplied'))
data.pop(key, None)
diff --git a/ckan/migration/versions/067_turn_extras_to_strings.py b/ckan/migration/versions/067_turn_extras_to_strings.py
index e6c0f1a26f0..4659cbc6cb4 100644
--- a/ckan/migration/versions/067_turn_extras_to_strings.py
+++ b/ckan/migration/versions/067_turn_extras_to_strings.py
@@ -7,7 +7,7 @@ def upgrade(migrate_engine):
revision_tables = 'package_extra_revision group_extra_revision'
for table in tables.split():
- sql = """select id, value from {table} where substr(value,0,1) = '"' """.format(table=table)
+ sql = """select id, value from {table} where substr(value,1,1) = '"' """.format(table=table)
results = connection.execute(sql)
for result in results:
id, value = result
@@ -16,7 +16,7 @@ def upgrade(migrate_engine):
json.loads(value), id)
for table in revision_tables.split():
- sql = """select id, revision_id, value from {table} where substr(value,0,1) = '"' """.format(table=table)
+ sql = """select id, revision_id, value from {table} where substr(value,1,1) = '"' """.format(table=table)
results = connection.execute(sql)
for result in results:
diff --git a/ckan/misc.py b/ckan/misc.py
index 4820379d2e9..29f3ae6447b 100644
--- a/ckan/misc.py
+++ b/ckan/misc.py
@@ -35,8 +35,8 @@ class MarkdownFormat(TextFormat):
normal_link = re.compile('<(http:[^>]+)>')
html_whitelist = 'b center li ol p table td tr ul'.split(' ')
- whitelist_elem = re.compile(r'<(\/?(%s)[^>]*)>' % "|".join(html_whitelist), re.IGNORECASE)
- whitelist_escp = re.compile(r'\\xfc\\xfd(\/?(%s)[^>]*?)\\xfd\\xfc' % "|".join(html_whitelist), re.IGNORECASE)
+ whitelist_elem = re.compile(r'<(\/?((%s)(\s[^>]*)?))>' % "|".join(html_whitelist), re.IGNORECASE)
+ whitelist_escp = re.compile(r'\\xfc\\xfd(\/?((%s)(\s[^>]*?)?))\\xfd\\xfc' % "|".join(html_whitelist), re.IGNORECASE)
normal_link = re.compile(r']*?href="([^"]*?)"[^>]*?>', re.IGNORECASE)
abbrev_link = re.compile(r'<(http://[^>]*)>', re.IGNORECASE)
any_link = re.compile(r' ]*?>', re.IGNORECASE)
diff --git a/ckan/new_authz.py b/ckan/new_authz.py
index 197d6ab35cf..f1bc0e8c5ed 100644
--- a/ckan/new_authz.py
+++ b/ckan/new_authz.py
@@ -49,6 +49,7 @@ def get_group_or_org_admin_ids(group_id):
q = model.Session.query(model.Member) \
.filter(model.Member.group_id == group_id) \
.filter(model.Member.table_name == 'user') \
+ .filter(model.Member.state == 'active') \
.filter(model.Member.capacity == 'admin')
return [a.table_id for a in q.all()]
@@ -135,6 +136,7 @@ def has_user_permission_for_group_or_org(group_id, user_name, permission):
q = model.Session.query(model.Member) \
.filter(model.Member.group_id == group_id) \
.filter(model.Member.table_name == 'user') \
+ .filter(model.Member.state == 'active') \
.filter(model.Member.table_id == user_id)
# see if any role has the required permission
# admin permission allows anything for the group
@@ -158,6 +160,7 @@ def users_role_for_group_or_org(group_id, user_name):
q = model.Session.query(model.Member) \
.filter(model.Member.group_id == group_id) \
.filter(model.Member.table_name == 'user') \
+ .filter(model.Member.state == 'active') \
.filter(model.Member.table_id == user_id)
# return the first role we find
for row in q.all():
@@ -176,6 +179,7 @@ def has_user_permission_for_some_org(user_name, permission):
# get any groups the user has with the needed role
q = model.Session.query(model.Member) \
.filter(model.Member.table_name == 'user') \
+ .filter(model.Member.state == 'active') \
.filter(model.Member.capacity.in_(roles)) \
.filter(model.Member.table_id == user_id)
group_ids = []
diff --git a/ckan/public/base/css/main.css b/ckan/public/base/css/main.css
index 0e9b5a7cd59..055f36eb1a6 100644
--- a/ckan/public/base/css/main.css
+++ b/ckan/public/base/css/main.css
@@ -4783,13 +4783,15 @@ a.tag:hover {
box-shadow: inset 0 1px 0 #3d97b3;
}
.pill {
- background-color: #8ca0a6;
+ display: inline-block;
+ background-color: #6f8890;
color: #ffffff;
- padding: 1px 5px 1px 8px;
+ padding: 2px 10px 1px 10px;
margin-right: 5px;
- -webkit-border-radius: 7px;
- -moz-border-radius: 7px;
- border-radius: 7px;
+ font-weight: normal;
+ -webkit-border-radius: 100px;
+ -moz-border-radius: 100px;
+ border-radius: 100px;
}
.pill a {
color: #ffffff;
@@ -4872,6 +4874,7 @@ a.tag:hover {
margin: 20px 0;
}
.module-heading {
+ *zoom: 1;
margin: 0;
padding: 7px 25px;
font-size: 14px;
@@ -4880,12 +4883,25 @@ a.tag:hover {
border-top: 1px solid #dddddd;
border-bottom: 1px solid #dddddd;
}
+.module-heading:before,
+.module-heading:after {
+ display: table;
+ content: "";
+ line-height: 0;
+}
+.module-heading:after {
+ clear: both;
+}
.module-heading .action {
float: right;
color: #888888;
- font-size: 11px;
+ font-size: 12px;
+ line-height: 20px;
text-decoration: underline;
}
+.module-heading .action:hover {
+ color: #444444;
+}
.module-content {
padding: 0 25px;
margin: 20px 0;
@@ -4928,11 +4944,16 @@ a.tag:hover {
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
border: 0;
}
.module .pagination li a {
border-top: none;
border-bottom: none;
+ padding-top: 7px;
+ padding-bottom: 7px;
}
.module .pagination li:first-child a,
.module .pagination li:last-child a {
@@ -5042,10 +5063,17 @@ a.tag:hover {
background-color: #ffffff;
border-bottom: 1px solid #dddddd;
margin-top: 0;
+ margin-bottom: 0;
-webkit-border-radius: 3px 3px 0 0;
-moz-border-radius: 3px 3px 0 0;
border-radius: 3px 3px 0 0;
}
+.module-resource .actions {
+ position: relative;
+ float: right;
+ top: -10px;
+ right: -15px;
+}
.module .module-tags {
padding-bottom: 8px;
}
@@ -5251,10 +5279,6 @@ ol.media-grid:after {
overflow: hidden;
display: block;
}
-.nav-item [class^=icon] {
- font-size: 1.2em;
- margin: -1px 0 -1px -1px;
-}
.module-narrow .nav-item > a {
padding-left: 15px;
padding-right: 15px;
@@ -5319,6 +5343,14 @@ ol.media-grid:after {
-moz-border-radius: 100px;
border-radius: 100px;
}
+.nav-simple > .nav-btn {
+ padding-left: 0;
+ padding-right: 0;
+ text-align: center;
+}
+.nav-simple > .nav-btn .btn {
+ display: inline-block;
+}
.js .js-hide {
display: none;
}
@@ -5339,7 +5371,6 @@ label {
label {
cursor: pointer;
font-size: 14px;
- line-height: 2;
}
label:after {
content: ":";
@@ -5348,13 +5379,6 @@ label.radio:after,
label.checkbox:after {
content: "";
}
-input,
-textarea,
-select,
-.uneditable-input {
- font-size: 14px;
- padding: 8px 10px;
-}
input[type=radio],
input[type=checkbox] {
position: relative;
@@ -5367,7 +5391,6 @@ input[type=checkbox].checkbox-onown {
top: 0;
}
select {
- margin-top: 6px;
padding: 4px;
}
textarea {
@@ -5393,7 +5416,8 @@ textarea {
}
.control-large input,
.control-large .control-label {
- font-size: 18px;
+ font-size: 17.5px;
+ line-height: 30px;
}
.form-actions {
background: none;
@@ -5417,16 +5441,6 @@ textarea {
}
.form-horizontal .control-label {
width: 120px;
- line-height: 1.3;
- padding-top: 9px;
-}
-.form-horizontal .control-large input,
-.form-horizontal .control-large .control-label {
- font-size: 18px;
- line-height: 2;
-}
-.form-horizontal .control-large .control-label {
- padding-top: 10px;
}
.form-horizontal .controls {
margin-left: 130px;
@@ -5695,24 +5709,23 @@ textarea {
background: #c6898b;
margin: -3px 0 0;
color: #ffffff;
- width: 216px;
+ width: 208px;
}
.control-medium .error-block {
- width: 326px;
+ width: 318px;
}
.control-full .error-block {
width: auto;
}
.control-group.error .input-prepend .error-block,
.control-custom.error .error-block {
- margin-left: -1px;
width: auto;
}
.control-custom.error .error-block {
- width: 409px;
+ width: 401px;
}
.control-select.error .error-block {
- width: 204px;
+ width: 196px;
}
.stages {
margin: 0;
@@ -5890,7 +5903,7 @@ textarea {
padding-left: 10px;
}
.select2-container {
- margin-top: 5px;
+ margin-top: 1px;
}
.select2-container-multi {
margin-top: 0;
@@ -6015,7 +6028,6 @@ textarea {
}
.filter-list {
color: #444444;
- font-weight: bold;
}
.filter-list .extra {
margin-top: 10px;
@@ -7689,6 +7701,9 @@ textarea {
.context-info.editing .module-content {
margin-top: 0;
}
+.modal {
+ top: 50%;
+}
.hero {
background: url("../../../base/images/background-tile.png");
padding: 20px 0;
@@ -7738,15 +7753,16 @@ textarea {
.hero .tags:after {
clear: both;
}
+.hero .tags h3,
.hero .tags .tag {
display: block;
float: left;
margin: 5px 10px 0 0;
}
-.hero .tags h3.tag {
+.hero .tags h3 {
font-size: 14px;
line-height: 20px;
- margin-bottom: 0;
+ padding: 2px 8px;
}
.hero-primary,
.hero-secondary {
@@ -8161,6 +8177,62 @@ textarea {
.lang-dropdown .select2-result-label[data-value*="/pt_BR/"]:before {
background-position: 0 -132px;
}
+.table-selected td {
+ background-color: #f5f5f5;
+}
+.table-selected td .edit {
+ display: block;
+}
+.table-bulk-edit th input {
+ top: -5px;
+}
+.table-bulk-edit .table-actions .btn-group {
+ float: left;
+ margin: 0 10px 0 0;
+}
+.table-bulk-edit .context p {
+ margin-bottom: 0;
+}
+.table-header thead th {
+ background-color: #f6f6f6;
+}
+.table-edit-hover .edit {
+ display: none;
+ float: right;
+}
+.table-edit-hover tr:hover .edit {
+ display: block;
+}
+.js .table-toggle-more .toggle-more {
+ display: none;
+}
+.js .table-toggle-more .show-more {
+ display: inline;
+}
+.js .table-toggle-more .show-less {
+ display: none;
+}
+.js .table-toggle-more .toggle-seperator {
+ display: table-row;
+}
+.js .table-toggle-more .toggle-seperator td {
+ height: 11px;
+ padding: 0;
+ background-image: url("../../../base/images/table-seperator.png");
+}
+.js .table .toggle-show td {
+ background: none;
+ text-align: center;
+}
+.js .table-toggle-less .show-less {
+ display: inline;
+}
+.js .table-toggle-less .show-more {
+ display: none;
+}
+.js .table-toggle-less .toggle-seperator {
+ display: none;
+}
.profile .empty,
.profile .dataset-list {
margin-bottom: 20px;
diff --git a/ckan/public/base/less/forms.less b/ckan/public/base/less/forms.less
index f0843c1d317..b38cbc406cf 100644
--- a/ckan/public/base/less/forms.less
+++ b/ckan/public/base/less/forms.less
@@ -372,11 +372,11 @@ textarea {
background: @errorBorder;
margin: -@inputBorderRadius 0 0;
color: @inputBackground;
- width: 216px;
+ width: 208px;
}
.control-medium .error-block {
- width: 326px;
+ width: 318px;
}
.control-full .error-block {
@@ -385,16 +385,15 @@ textarea {
.control-group.error .input-prepend .error-block,
.control-custom.error .error-block {
- margin-left: -1px;
width: auto;
}
.control-custom.error .error-block {
- width: 409px;
+ width: 401px;
}
.control-select.error .error-block {
- width: 204px;
+ width: 196px;
}
// Stages
diff --git a/ckan/public/base/less/layout.less b/ckan/public/base/less/layout.less
index 63c559bfd60..0033ccc7f82 100644
--- a/ckan/public/base/less/layout.less
+++ b/ckan/public/base/less/layout.less
@@ -137,3 +137,7 @@
}
}
}
+
+.modal {
+ top: 50%;
+}
diff --git a/ckan/templates/home/about.html b/ckan/templates/home/about.html
index 1be3b858749..98a3c03e69b 100644
--- a/ckan/templates/home/about.html
+++ b/ckan/templates/home/about.html
@@ -11,7 +11,7 @@
{% block about %}
{% if g.site_about %}
- {{ h.markdown_extract(g.site_about) }}
+ {{ h.render_markdown(g.site_about) }}
{% else %}
{{ _('About') }}
{% snippet 'home/snippets/about_text.html' %}
diff --git a/ckan/templates/package/new_package_metadata.html b/ckan/templates/package/new_package_metadata.html
index b0aa54e9687..2b92105a1e8 100644
--- a/ckan/templates/package/new_package_metadata.html
+++ b/ckan/templates/package/new_package_metadata.html
@@ -2,4 +2,4 @@
{% block subtitle %}{{ _('Add metadata to the dataset') }}{% endblock %}
-{% block form %}{{ h.snippet('package/snippets/package_metadata_form.html', data=data, errors=errors, include_metadata=false, pkg_name=pkg_name) }}{% endblock %}
+{% block form %}{{ h.snippet('package/snippets/package_metadata_form.html', data=data, errors=errors, error_summary=error_summary, include_metadata=false, pkg_name=pkg_name) }}{% endblock %}
diff --git a/ckan/templates/package/resource_read.html b/ckan/templates/package/resource_read.html
index 85ea76de691..4d7101634f3 100644
--- a/ckan/templates/package/resource_read.html
+++ b/ckan/templates/package/resource_read.html
@@ -96,10 +96,6 @@
{{ _('Additional Information') }}
{{ _('License') }}
{% snippet "snippets/license.html", pkg_dict=pkg, text_only=True %}
-
- {{ _('Author') }}
- {{ res.author or _('unknown') }}
-
{% for key, value in h.format_resource_items(res.items()) %}
{{ key }} {{ value }}
{% endfor %}
diff --git a/ckan/templates/package/search.html b/ckan/templates/package/search.html
index 73326b159d5..1271aebab17 100644
--- a/ckan/templates/package/search.html
+++ b/ckan/templates/package/search.html
@@ -38,6 +38,7 @@
{% for field in c.fields_grouped %}
+ {% set search_facets_items = c.search_facets.get(field)['items'] %}
{{ c.facet_titles.get(field) }}:
{% for value in c.fields_grouped[field] %}
@@ -45,6 +46,7 @@
{{ c.translated_fields[(field,value)] }}
{%- else -%}
{{ value }}
+ {{ h.list_dict_filter(search_facets_items , 'name', 'display_name', value) }}
{%- endif %}
diff --git a/ckan/templates/package/snippets/package_basic_fields.html b/ckan/templates/package/snippets/package_basic_fields.html
index c6bb8afaad6..2b6933f62a3 100644
--- a/ckan/templates/package/snippets/package_basic_fields.html
+++ b/ckan/templates/package/snippets/package_basic_fields.html
@@ -1,19 +1,28 @@
{% import 'macros/form.html' as form %}
+{% block package_basic_fields_title %}
{{ form.input('title', id='field-title', label=_('Title'), placeholder=_('eg. A descriptive title'), value=data.title, error=errors.title, classes=['control-full', 'control-large'], attrs={'data-module': 'slug-preview-target'}) }}
+{% endblock %}
+{% block package_basic_fields_url %}
{% set prefix = h.url_for(controller='package', action='read', id='') %}
{% set domain = h.url_for(controller='package', action='read', id='', qualified=true) %}
{% set domain = domain|replace("http://", "")|replace("https://", "") %}
{% set attrs = {'data-module': 'slug-preview-slug', 'data-module-prefix': domain, 'data-module-placeholder': '
'} %}
{{ form.prepend('name', id='field-name', label=_('URL'), prepend=prefix, placeholder=_('eg. my-dataset'), value=data.name, error=errors.name, attrs=attrs) }}
+{% endblock %}
+{% block package_basic_fields_description %}
{{ form.markdown('notes', id='field-notes', label=_('Description'), placeholder=_('eg. Some useful notes about the data'), value=data.notes, error=errors.notes) }}
+{% endblock %}
+{% block package_basic_fields_tags %}
{% set tag_attrs = {'data-module': 'autocomplete', 'data-module-tags': '', 'data-module-source': '/api/2/util/tag/autocomplete?incomplete=?'} %}
{{ form.input('tag_string', id='field-tags', label=_('Tags'), placeholder=_('eg. economy, mental health, government'), value=data.tag_string, error=errors.tags, classes=['control-full'], attrs=tag_attrs) }}
+{% endblock %}
+{% block package_basic_fields_license %}
{% set error = errors.license_id %}
{{ _("License") }}
@@ -33,7 +42,9 @@
+{% endblock %}
+{% block package_basic_fields_org %}
{# if we have a default group then this wants remembering #}
{% if data.group_id %}
@@ -46,10 +57,10 @@
{{ _('Organization') }}
- {{ _('Select an organization...') }}
+ {{ _('Select an organization...') }}
{% for organization in organizations_available %}
{# get out first org from users list only if there is not an existing org #}
- {% set selected_org = (existing_org and existing_org == organization.id) or (not existing_org and organization.id == organizations_available[0].id) %}
+ {% set selected_org = (existing_org and existing_org == organization.id) or (not existing_org and not data.id and organization.id == organizations_available[0].id) %}
{{ organization.name }}
{% endfor %}
@@ -57,3 +68,4 @@
{% endif %}
{% endif %}
+{% endblock %}
diff --git a/ckan/templates/package/snippets/package_metadata_fields.html b/ckan/templates/package/snippets/package_metadata_fields.html
index b9c97f6aa43..6bdfa51f140 100644
--- a/ckan/templates/package/snippets/package_metadata_fields.html
+++ b/ckan/templates/package/snippets/package_metadata_fields.html
@@ -2,6 +2,7 @@
{% block package_metadata_fields %}
+{% block package_metadata_fields_visibility %}
{% if data.owner_org %}
{{ _('Visibility') }}
@@ -14,18 +15,25 @@
{% endif %}
+{% endblock %}
+{% block package_metadata_author %}
{{ form.input('author', label=_('Author'), id='field-author', placeholder=_('Joe Bloggs'), value=data.author, error=errors.author, classes=['control-medium']) }}
{{ form.input('author_email', label=_('Author Email'), id='field-author-email', placeholder=_('joe@example.com'), value=data.author_email, error=errors.author_email, classes=['control-medium']) }}
+{% endblock %}
+{% block package_metadata_fields_maintainer %}
{{ form.input('maintainer', label=_('Maintainer'), id='field-maintainer', placeholder=_('Joe Bloggs'), value=data.maintainer, error=errors.maintainer, classes=['control-medium']) }}
{{ form.input('maintainer_email', label=_('Maintainer Email'), id='field-maintainer-email', placeholder=_('joe@example.com'), value=data.maintainer_email, error=errors.maintainer_email, classes=['control-medium']) }}
+{% endblock %}
+{% block package_metadata_fields_custom %}
{% block custom_fields %}
{% snippet 'snippets/custom_form_fields.html', extras=data.extras, errors=errors, limit=3 %}
{% endblock %}
+{% endblock %}
{% block dataset_fields %}
diff --git a/ckan/templates/package/snippets/resource_form.html b/ckan/templates/package/snippets/resource_form.html
index e36e6306478..8ce9d8efae1 100644
--- a/ckan/templates/package/snippets/resource_form.html
+++ b/ckan/templates/package/snippets/resource_form.html
@@ -18,6 +18,8 @@
+ {% endblock %}
+ {% block basic_fields_url %}
{{ form.input('url', id='field-url', label=_('Resource'), placeholder=_('eg. http://example.com/gold-prices-jan-2011.json'), value=data.url, error=errors.url, classes=['control-full', 'control-large']) }}
+ {% endblock %}
+ {% block basic_fields_name %}
{{ form.input('name', id='field-name', label=_('Name'), placeholder=_('eg. January 2011 Gold Prices'), value=data.name, error=errors.name, classes=['control-full']) }}
+ {% endblock %}
+ {% block basic_fields_description %}
{{ form.markdown('description', id='field-description', label=_('Description'), placeholder=_('Some useful notes about the data'), value=data.description, error=errors.description) }}
+ {% endblock %}
+ {% block basic_fields_format %}
{% set format_attrs = {'data-module': 'autocomplete', 'data-module-source': '/api/2/util/resource/format_autocomplete?incomplete=?'} %}
{% call form.input('format', id='field-format', label=_('Format'), placeholder=_('eg. CSV, XML or JSON'), value=data.format, error=errors.format, classes=['control-medium'], attrs=format_attrs) %}
@@ -47,6 +57,7 @@
{{ _('This is generated automatically. You can edit if you wish') }}
{% endcall %}
+ {% endblock %}
{% endblock %}
{% block metadata_fields %}
diff --git a/ckan/templates/snippets/license.html b/ckan/templates/snippets/license.html
index 7ed6cfa0e3e..d575ef0515b 100644
--- a/ckan/templates/snippets/license.html
+++ b/ckan/templates/snippets/license.html
@@ -14,8 +14,6 @@ {{ _('License')
- {% else %}
- {{ h.icon('lock') }}
{% endif %}
diff --git a/ckan/templates/tag/index.html b/ckan/templates/tag/index.html
new file mode 100644
index 00000000000..892345cec93
--- /dev/null
+++ b/ckan/templates/tag/index.html
@@ -0,0 +1,33 @@
+{% extends "page.html" %}
+
+{% block subtitle %}{{ _('Tags') }}{% endblock %}
+
+{% block breadcrumb_content %}
+ {{ _('Tags') }}
+{% endblock %}
+
+{% block primary_content %}
+
+
+
{{ _('Tags') }}
+
+ {% for tag in c.page.items %}
+ {{ h.link_to(tag.display_name, h.url_for(controller='package', action='search', tags=tag.name), class_='tag') }}
+ {% endfor %}
+
+
+ {{ c.page.pager(q=c.q) }}
+
+{% endblock %}
+
+{% block secondary_content %}
+
+{% endblock %}
diff --git a/ckan/tests/functional/api/model/test_vocabulary.py b/ckan/tests/functional/api/model/test_vocabulary.py
index 0b23e26f8c9..0ae424ce8ef 100644
--- a/ckan/tests/functional/api/model/test_vocabulary.py
+++ b/ckan/tests/functional/api/model/test_vocabulary.py
@@ -826,6 +826,28 @@ def test_add_vocab_tag_to_dataset(self):
tag_in_pkg['vocabulary_id'] == tag['vocabulary_id']]
assert len(tags_in_pkg) == 1
+ # Test that the package appears vocabulary_list.
+ vocabs = self._post('/api/action/vocabulary_list')['result']
+ genre_vocab = [vocab for vocab in vocabs if vocab['name'] == 'Genre']
+ assert len(genre_vocab) == 1
+ genre_vocab = genre_vocab[0]
+ noise_tag = [tag_ for tag_ in genre_vocab['tags']
+ if tag_['name'] == 'noise']
+ assert len(noise_tag) == 1
+ noise_tag = noise_tag[0]
+ assert len([p for p in noise_tag['packages'] if
+ p['id'] == updated_package['id']]) == 1
+
+ # Test that the tagged package appears in vocabulary_show.
+ genre_vocab = self._post('/api/action/vocabulary_show',
+ params={'id': genre_vocab['id']})['result']
+ noise_tag = [tag_ for tag_ in genre_vocab['tags']
+ if tag_['name'] == 'noise']
+ assert len(noise_tag) == 1
+ noise_tag = noise_tag[0]
+ assert len([p for p in noise_tag['packages'] if
+ p['id'] == updated_package['id']]) == 1
+
# Remove the new vocab tag from the package.
package['tags'].remove(tag)
updated_package = (self._post('/api/action/package_update',
diff --git a/ckan/tests/functional/api/test_activity.py b/ckan/tests/functional/api/test_activity.py
index 1c7a9c73709..461ae7685c8 100644
--- a/ckan/tests/functional/api/test_activity.py
+++ b/ckan/tests/functional/api/test_activity.py
@@ -13,8 +13,11 @@
logger = logging.getLogger(__name__)
import pylons.test
+from pylons import config
+from paste.deploy.converters import asbool
import paste.fixture
from ckan.lib.helpers import json
+from nose import SkipTest
##def package_update(context, data_dict):
@@ -170,9 +173,10 @@ def find_new_activities(before, after):
class TestActivity:
-
@classmethod
def setup_class(self):
+ if not asbool(config.get('ckan.activity_streams_enabled', 'true')):
+ raise SkipTest('Activity streams not enabled')
import ckan
import ckan.model as model
ckan.tests.CreateTestData.create()
diff --git a/ckan/tests/functional/test_activity.py b/ckan/tests/functional/test_activity.py
index 02d56252871..fa4b80423c0 100644
--- a/ckan/tests/functional/test_activity.py
+++ b/ckan/tests/functional/test_activity.py
@@ -1,7 +1,11 @@
+from pylons import config
from pylons.test import pylonsapp
+from paste.deploy.converters import asbool
import paste.fixture
-import ckan
from routes import url_for
+from nose import SkipTest
+
+import ckan
from ckan.logic.action.create import package_create, user_create, group_create
from ckan.logic.action.create import follow_dataset, follow_user
from ckan.logic.action.update import package_update, resource_update
@@ -18,6 +22,8 @@ class TestActivity(HtmlCheckMethods):
"""
@classmethod
def setup(cls):
+ if not asbool(config.get('ckan.activity_streams_enabled', 'true')):
+ raise SkipTest('Activity streams not enabled')
ckan.tests.CreateTestData.create()
cls.sysadmin_user = ckan.model.User.get('testsysadmin')
cls.app = paste.fixture.TestApp(pylonsapp)
diff --git a/ckan/tests/logic/test_auth.py b/ckan/tests/logic/test_auth.py
index b2e81ab44a8..3ea9f2db39f 100644
--- a/ckan/tests/logic/test_auth.py
+++ b/ckan/tests/logic/test_auth.py
@@ -3,7 +3,6 @@
import ckan.model as model
import ckan.new_authz as new_authz
import json
-from ckan.tests import StatusCodes
INITIAL_TEST_CONFIG_PERMISSIONS = {
'anon_create_dataset': False,
@@ -16,6 +15,7 @@
'create_unowned_dataset': False,
}
+
class TestAuth(tests.WsgiAppCase):
@classmethod
def setup_class(cls):
@@ -34,7 +34,7 @@ def teardown_class(cls):
model.repo.rebuild_db()
def _call_api(self, action, data, user, status=None):
- params='%s=1' % json.dumps(data)
+ params = '%s=1' % json.dumps(data)
return self.app.post('/api/action/%s' % action,
params=params,
extra_environ={'Authorization': self.apikeys[user]},
@@ -65,16 +65,16 @@ def test_01_create_users(self):
self._call_api('user_create', user, 'no_org', 403)
def test_02_create_orgs(self):
- org = {'name': 'org_no_user',}
+ org = {'name': 'org_no_user'}
self._call_api('organization_create', org, 'random_key', 403)
self._call_api('organization_create', org, 'sysadmin')
- org = {'name': 'org_with_user',}
+ org = {'name': 'org_with_user'}
self._call_api('organization_create', org, 'random_key', 403)
self._call_api('organization_create', org, 'sysadmin')
#no user should be able to create org
- org = {'name': 'org_should_not_be_created',}
+ org = {'name': 'org_should_not_be_created'}
self._call_api('organization_create', org, 'org_admin', 403)
def test_03_create_dataset_no_org(self):
@@ -87,13 +87,16 @@ def test_03_create_dataset_no_org(self):
def test_04_create_dataset_with_org(self):
- dataset = {'name': 'admin_create_with_user', 'owner_org': 'org_with_user'}
+ dataset = {'name': 'admin_create_with_user',
+ 'owner_org': 'org_with_user'}
self._call_api('package_create', dataset, 'sysadmin', 200)
- dataset = {'name': 'sysadmin_create_no_user', 'owner_org': 'org_no_user'}
+ dataset = {'name': 'sysadmin_create_no_user',
+ 'owner_org': 'org_no_user'}
self._call_api('package_create', dataset, 'sysadmin', 200)
- dataset = {'name': 'user_create_with_org', 'owner_org': 'org_with_user'}
+ dataset = {'name': 'user_create_with_org',
+ 'owner_org': 'org_with_user'}
self._call_api('package_create', dataset, 'no_org', 403)
def test_05_add_users_to_org(self):
@@ -127,11 +130,11 @@ def _add_datasets(self, user):
self._call_api('package_create', dataset, user, 409)
#admin not able to make dataset not owned by a org
- dataset = {'name': user + '_dataset_bad' }
+ dataset = {'name': user + '_dataset_bad'}
self._call_api('package_create', dataset, user, 409)
#not able to add org to not existant org
- dataset = {'name': user + '_dataset_bad', 'owner_org': 'org_not_exist' }
+ dataset = {'name': user + '_dataset_bad', 'owner_org': 'org_not_exist'}
self._call_api('package_create', dataset, user, 409)
def test_07_add_datasets(self):
@@ -149,7 +152,7 @@ def _update_datasets(self, user):
dataset = {'id': 'sysadmin_create_no_user', 'title': 'test'}
self._call_api('package_update', dataset, user, 403)
#non existant owner org
- dataset = {'id': 'org_editor_dataset', 'owner_org': 'org_not_exist' }
+ dataset = {'id': 'org_editor_dataset', 'owner_org': 'org_not_exist'}
self._call_api('package_update', dataset, user, 409)
def test_08_update_datasets(self):
@@ -191,17 +194,15 @@ def test_11_delete_org(self):
class TestAuthGroups(TestAuth):
def test_01_create_groups(self):
- group = {'name': 'group_no_user',}
+ group = {'name': 'group_no_user'}
self._call_api('group_create', group, 'random_key', 403)
self._call_api('group_create', group, 'sysadmin')
- group = {'name': 'group_with_user',}
+ group = {'name': 'group_with_user'}
self._call_api('group_create', group, 'random_key', 403)
self._call_api('group_create', group, 'sysadmin')
-
def test_02_add_users_to_group(self):
-
self.create_user('org_admin')
self.create_user('org_editor')
self.create_user('org_editor_wannabe')
@@ -232,20 +233,28 @@ def test_03_add_dataset_to_group(self):
package = {'name': 'package_added_by_editor', 'owner_org': 'org'}
self._call_api('package_create', package, 'sysadmin')
- group = {'id': 'group_with_user', 'packages': [{'id': 'package_added_by_admin'}]}
+ res = self._call_api('group_show',
+ {'id': 'group_with_user'},
+ 'org_admin')
+ group = json.loads(res.body)['result']
self._call_api('group_update', group, 'no_group', 403)
self._call_api('group_update', group, 'org_admin')
group = {'id': 'group_with_user',
- 'packages': [{'id': 'package_added_by_admin'}, {'id' :'package_added_by_editor'}]}
+ 'packages': [{'id': 'package_added_by_admin'},
+ {'id': 'package_added_by_editor'}]}
# org editor doesn't have edit rights
self._call_api('group_update', group, 'org_editor', 403)
def test_04_modify_group(self):
-
- group = {'id': 'group_with_user', 'title': 'moo',
- 'packages': [{'id': 'package_added_by_admin'}]}
-
+ res = self._call_api('group_show',
+ {'id': 'group_with_user'},
+ 'org_admin')
+ group = json.loads(res.body)['result']
+ group.update({
+ 'title': 'moo',
+ 'packages': [{'id': 'package_added_by_admin'}]
+ })
self._call_api('group_update', group, 'org_admin')
# need to think about this as is horrible may just let editor edit
@@ -253,14 +262,9 @@ def test_04_modify_group(self):
self._call_api('group_update', group, 'org_editor', 403)
def test_05_delete_group(self):
-
org = {'id': 'group_with_user'}
self._call_api('group_delete', org, 'org_editor', 403)
self._call_api('group_delete', org, 'org_admin', 403)
org = {'id': 'group_with_user'}
self._call_api('group_delete', org, 'org_editor', 403)
self._call_api('group_delete', org, 'org_admin', 403)
-
-
-
-
diff --git a/ckan/tests/logic/test_member.py b/ckan/tests/logic/test_member.py
index 3d6294e2913..38d1d795ac1 100644
--- a/ckan/tests/logic/test_member.py
+++ b/ckan/tests/logic/test_member.py
@@ -1,6 +1,8 @@
-from ckan import model
-from ckan.logic import get_action
-from ckan.lib.create_test_data import CreateTestData
+from nose.tools import assert_raises
+import ckan.model as model
+import ckan.logic as logic
+import ckan.lib.create_test_data as create_test_data
+
class TestMemberLogic(object):
@@ -10,60 +12,62 @@ def setup_class(cls):
cls.groupname = 'david'
model.repo.new_revision()
- CreateTestData.create()
- cls.pkgs = [
- model.Package.by_name('warandpeace'),
- model.Package.by_name('annakarenina'),
- ]
+ create_test_data.CreateTestData.create()
+ cls.pkgs = [model.Package.by_name('warandpeace'),
+ model.Package.by_name('annakarenina')]
@classmethod
def teardown_class(cls):
model.repo.rebuild_db()
- def _build_context( self, obj, obj_type, capacity='public'):
- ctx = { 'model': model,
- 'session': model.Session,
- 'user':self.username
- }
- dd = {
- 'id': self.groupname,
- 'object': obj,
- 'object_type': obj_type,
- 'capacity': capacity }
+ def _build_context(self, obj, obj_type, capacity='public'):
+ ctx = {'model': model,
+ 'session': model.Session,
+ 'user': self.username}
+ dd = {'id': self.groupname,
+ 'object': obj,
+ 'object_type': obj_type,
+ 'capacity': capacity}
return ctx, dd
- def _add_member( self, obj, obj_type, capacity):
- ctx, dd = self._build_context(obj,obj_type,capacity)
- return get_action('member_create')(ctx,dd)
+ def _add_member(self, obj, obj_type, capacity):
+ ctx, dd = self._build_context(obj, obj_type, capacity)
+ return logic.get_action('member_create')(ctx, dd)
def test_member_add(self):
- res = self._add_member( self.pkgs[0].id, 'package', 'public')
+ res = self._add_member(self.pkgs[0].id, 'package', 'public')
assert 'capacity' in res and res['capacity'] == u'public'
def test_member_list(self):
- _ = self._add_member( self.pkgs[0].id, 'package', 'public')
- _ = self._add_member( self.pkgs[1].id, 'package', 'public')
- ctx, dd = self._build_context('','package')
- res = get_action('member_list')(ctx,dd)
+ self._add_member(self.pkgs[0].id, 'package', 'public')
+ self._add_member(self.pkgs[1].id, 'package', 'public')
+ ctx, dd = self._build_context('', 'package')
+ res = logic.get_action('member_list')(ctx, dd)
assert len(res) == 2, res
+ assert (self.pkgs[0].id, 'package', 'public') in res
+ assert (self.pkgs[1].id, 'package', 'public') in res
- ctx, dd = self._build_context('','user', 'admin')
- res = get_action('member_list')(ctx,dd)
+ ctx, dd = self._build_context('', 'user', 'admin')
+ res = logic.get_action('member_list')(ctx, dd)
assert len(res) == 0, res
- _ = self._add_member( self.username, 'user', 'admin')
- ctx, dd = self._build_context('','user', 'admin')
- res = get_action('member_list')(ctx,dd)
- assert len(res) == 1, res
+ ctx, dd = self._build_context('', 'user', 'admin')
+ dd['id'] = u'foo'
+ assert_raises(logic.NotFound, logic.get_action('member_list'), ctx, dd)
+ self._add_member(self.username, 'user', 'admin')
+ ctx, dd = self._build_context('', 'user', 'admin')
+ res = logic.get_action('member_list')(ctx, dd)
+ assert len(res) == 1, res
+ assert (self.username, 'user', 'Admin') in res
def test_member_delete(self):
- _ = self._add_member( self.username, 'user', 'admin')
- ctx, dd = self._build_context(self.username,'user', 'admin')
- res = get_action('member_list')(ctx,dd)
+ self._add_member(self.username, 'user', 'admin')
+ ctx, dd = self._build_context(self.username, 'user', 'admin')
+ res = logic.get_action('member_list')(ctx, dd)
assert len(res) == 1, res
- get_action('member_delete')(ctx,dd)
+ logic.get_action('member_delete')(ctx, dd)
- res = get_action('member_list')(ctx,dd)
+ res = logic.get_action('member_list')(ctx, dd)
assert len(res) == 0, res
diff --git a/ckanext/datastore/bin/set_permissions.sql b/ckanext/datastore/bin/set_permissions.sql
index 1bbc06d203f..18b6265b63a 100644
--- a/ckanext/datastore/bin/set_permissions.sql
+++ b/ckanext/datastore/bin/set_permissions.sql
@@ -14,9 +14,9 @@ To run the script, execute:
*/
-- name of the main CKAN database
-\set maindb '{ckandb}'
+\set maindb "{ckandb}"
-- the name of the datastore database
-\set datastoredb '{datastoredb}'
+\set datastoredb "{datastoredb}"
-- username of the ckan postgres user
\set ckanuser "{ckanuser}"
-- username of the datastore user that can write
diff --git a/ckanext/organizations/__init__.py b/ckanext/organizations/__init__.py
deleted file mode 100644
index 9472ce03e3b..00000000000
--- a/ckanext/organizations/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-'''Organization form
-
-Provides a form for organization creation
-'''
-__version__ = '0.1'
-
diff --git a/ckanext/organizations/controllers.py b/ckanext/organizations/controllers.py
deleted file mode 100644
index 56bba8f30e6..00000000000
--- a/ckanext/organizations/controllers.py
+++ /dev/null
@@ -1,174 +0,0 @@
-import logging
-
-from ckan.lib.base import BaseController, c, model, request, render, h, g
-from ckan.lib.base import ValidationException, abort, gettext
-from pylons.i18n import get_lang, _
-from ckan.lib.alphabet_paginate import AlphaPage
-from ckan.lib.dictization.model_dictize import package_dictize
-
-import ckan.forms
-import ckan.authz as authz
-import ckan.lib.dictization.model_save as model_save
-import ckan.lib.mailer as mailer
-import ckan.lib.navl.dictization_functions as dict_func
-import ckan.logic as logic
-import ckan.logic.action as action
-import ckan.logic.schema as schema
-import ckan.model as model
-
-import pylons.config as config
-from ckan.lib.navl.validators import (ignore_missing,
- not_empty,
- empty,
- ignore,
- keep_extras,)
-
-class OrganizationController(BaseController):
-
- def _send_application( self, group, reason ):
- from genshi.template.text import NewTextTemplate
-
- if not reason:
- h.flash_error(_("There was a problem with your submission, \
- please correct it and try again"))
- errors = {"reason": ["No reason was supplied"]}
- return self.apply(group.id, errors=errors,
- error_summary=action.error_summary(errors))
-
- admins = group.members_of_type( model.User, 'admin' ).all()
- recipients = [(u.fullname,u.email) for u in admins] if admins else \
- [(config.get('ckan.admin.name', "CKAN Administrator"),
- config.get('ckan.admin.email', None), )]
-
- if not recipients:
- h.flash_error(_("There is a problem with the system configuration"))
- errors = {"reason": ["No group administrator exists"]}
- return self.apply(group.id, data=data, errors=errors,
- error_summary=action.error_summary(errors))
-
- extra_vars = {
- 'group' : group,
- 'requester': c.userobj,
- 'reason' : reason
- }
- email_msg = render("organizations/email/join_publisher_request.txt",
- extra_vars=extra_vars,
- loader_class=NewTextTemplate)
-
- try:
- for (name,recipient) in recipients:
- mailer.mail_recipient(name,
- recipient,
- "Publisher request",
- email_msg)
- except:
- h.flash_error(_("There is a problem with the system configuration"))
- errors = {"reason": ["No mail server was found"]}
- return self.apply(group.id, errors=errors,
- error_summary=action.error_summary(errors))
-
- h.flash_success(_("Your application has been submitted"))
- h.redirect_to( 'publisher_read', id=group.name)
-
- def apply(self, id=None, data=None, errors=None, error_summary=None):
- """
- A user has requested access to this publisher and so we will send an
- email to any admins within the publisher.
- """
- if 'parent' in request.params and not id:
- id = request.params['parent']
-
- if id:
- c.group = model.Group.get(id)
- if 'save' in request.params and not errors:
- return self._send_application(c.group, request.params.get('reason', None))
-
- self._add_publisher_list()
- data = data or {}
- errors = errors or {}
- error_summary = error_summary or {}
-
- data.update(request.params)
-
- vars = {'data': data, 'errors': errors, 'error_summary': error_summary}
- c.form = render('organizations/apply_form.html', extra_vars=vars)
- return render('organizations/apply.html')
-
- def _add_users( self, group, parameters ):
- if not group:
- h.flash_error(_("There was a problem with your submission, "
- "please correct it and try again"))
- errors = {"reason": ["No reason was supplied"]}
- return self.apply(group.id, errors=errors,
- error_summary=action.error_summary(errors))
-
- data_dict = logic.clean_dict(dict_func.unflatten(
- logic.tuplize_dict(logic.parse_params(request.params))))
- data_dict['id'] = group.id
-
- # Temporary fix for strange caching during dev
- l = data_dict['users']
- for d in l:
- d['capacity'] = d.get('capacity','editor')
-
- context = {
- "group" : group,
- "schema": schema.default_group_schema(),
- "model": model,
- "session": model.Session
- }
-
- # Temporary cleanup of a capacity being sent without a name
- users = [d for d in data_dict['users'] if len(d) == 2]
- data_dict['users'] = users
-
- model.repo.new_revision()
- model_save.group_member_save(context, data_dict, 'users')
- model.Session.commit()
-
- h.redirect_to( controller='group', action='edit', id=group.name)
-
-
- def users(self, id, data=None, errors=None, error_summary=None):
- c.group = model.Group.get(id)
-
- if not c.group:
- abort(404, _('Group not found'))
-
- context = {
- 'model': model,
- 'session': model.Session,
- 'user': c.user or c.author,
- 'group': c.group }
-
- try:
- logic.check_access('group_update',context)
- except logic.NotAuthorized, e:
- abort(401, _('User %r not authorized to edit %s') % (c.user, id))
-
- if 'save' in request.params and not errors:
- return self._add_users(c.group, request.params)
-
- data = data or {}
- errors = errors or {}
- error_summary = error_summary or {}
-
- data['users'] = []
- data['users'].extend( { "name": user.name,
- "capacity": "admin" }
- for user in c.group.members_of_type( model.User, "admin" ).all() )
- data['users'].extend( { "name": user.name,
- "capacity": "editor" }
- for user in c.group.members_of_type( model.User, 'editor' ).all() )
-
- vars = {'data': data, 'errors': errors, 'error_summary': error_summary}
- c.form = render('organizations/users_form.html', extra_vars=vars)
-
- return render('organizations/users.html')
-
- def _add_publisher_list(self):
- c.possible_parents = model.Session.query(model.Group).\
- filter(model.Group.state == 'active').\
- filter(model.Group.type == 'organization').\
- order_by(model.Group.title).all()
-
diff --git a/ckanext/organizations/forms.py b/ckanext/organizations/forms.py
deleted file mode 100644
index a9542973b46..00000000000
--- a/ckanext/organizations/forms.py
+++ /dev/null
@@ -1,274 +0,0 @@
-import os
-import logging
-
-import ckan.authz as authz
-from ckan.logic import NotAuthorized
-from ckan.logic.schema import group_form_schema, form_to_db_package_schema
-from ckan.lib import base
-from ckan.lib.base import c, model, abort, request
-from ckan.lib.base import redirect, _, config, h
-from ckan.lib.navl.dictization_functions import DataError
-import ckan.plugins as p
-
-from ckan.plugins import IGroupForm, IDatasetForm, IConfigurer, IRoutes
-from ckan.plugins import implements, SingletonPlugin
-from ckan.logic import check_access
-from ckan.logic.validators import tag_string_convert
-from ckan.lib.navl.validators import (ignore_missing,
- not_empty,
- empty,
- ignore,
- keep_extras)
-
-log = logging.getLogger(__name__)
-
-
-def group_required(key, data, errors, context):
- """ We want at least a group in the data we are provided """
- has_group = ('groups', 0, 'id') in data
- if not has_group:
- errors[('Organizations', '')] = \
- [_('Please choose an organization to add the dataset to')]
-
-
-class OrganizationForm(SingletonPlugin):
- """
- This plugin implements an IGroupForm for form associated with a
- organization group. ``IConfigurer`` is used to add the local template
- path and the IGroupForm supplies the custom form.
- """
- implements(IGroupForm, inherit=True)
- implements(IConfigurer, inherit=True)
- implements(IRoutes)
- implements(IConfigurer)
-
- def before_map(self, map):
- controller = 'ckanext.organizations.controllers:OrganizationController'
- map.connect('/organization/users/{id}', controller=controller,
- action='users')
- map.connect('/organization/apply/{id}', controller=controller,
- action='apply')
- map.connect('/organization/apply', controller=controller,
- action='apply')
- map.connect('/organization/edit/{id}', controller='group',
- action='edit')
- map.connect('/organization/new', controller='group', action='new')
- map.connect('/organization/{id}', controller='group', action='read')
- map.connect('/organization', controller='group', action='index')
- map.redirect('/organizations', '/organization')
- return map
-
- def after_map(self, map):
- return map
-
- def update_config(self, config):
- """
- This IConfigurer implementation causes CKAN to look in the
- ```templates``` directory when looking for the group_form()
- """
- templates = 'templates'
- if p.toolkit.asbool(config.get('ckan.legacy_templates', False)):
- templates = 'templates_legacy'
- p.toolkit.add_template_directory(config, templates)
- p.toolkit.add_public_directory(config, 'public')
-
- # Override /group/* as the default groups urls
- config['ckan.default.group_type'] = 'organization'
-
- def new_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the new page
- """
- return 'organizations/new.html'
-
- def index_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the index page
- """
- return 'organizations/index.html'
-
- def read_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the read page
- """
- return 'organizations/read.html'
-
- def history_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the read page
- """
- return 'organizations/history.html'
-
- def edit_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the edit page
- """
- return 'organization_edit.html'
-
- def group_form(self):
- """
- Returns a string representing the location of the template to be
- rendered. e.g. "forms/group_form.html".
- """
- return 'organizations/form.html'
-
- def group_types(self):
- """
- Returns an iterable of group type strings.
-
- If a request involving a group of one of those types is made, then
- this plugin instance will be delegated to.
-
- There must only be one plugin registered to each group type. Any
- attempts to register more than one plugin instance to a given group
- type will raise an exception at startup.
- """
- return ["organization"]
-
- def is_fallback(self):
- """
- Returns true iff this provides the fallback behaviour, when no other
- plugin instance matches a group's type.
-
- As this is not the fallback controller we should return False. If
- we were wanting to act as the fallback, we'd return True
- """
- return False
-
- def form_to_db_schema(self):
- """
- Returns the schema for mapping group data from a form to a format
- suitable for the database.
- """
- return group_form_schema()
-
- def db_to_form_schema(self):
- """
- Returns the schema for mapping group data from the database into a
- format suitable for the form (optional)
- """
- return group_form_schema()
-
- def check_data_dict(self, data_dict):
- """
- Check if the return data is correct.
-
- raise a DataError if not.
- """
-
- def setup_template_variables(self, context, data_dict):
- """
- Add variables to c just prior to the template being rendered. We should
- use the available groups for the current user, but should be optional
- in case this is a top level group
- """
- c.user_groups = c.userobj.get_groups('organization')
- local_ctx = {'model': model, 'session': model.Session,
- 'user': c.user or c.author}
-
- try:
- check_access('group_create', local_ctx)
- c.is_superuser_or_groupadmin = True
- except NotAuthorized:
- c.is_superuser_or_groupadmin = False
-
- if 'group' in context:
- group = context['group']
- # Only show possible groups where the current user is a member
- c.possible_parents = c.userobj.get_groups('organization', 'admin')
-
- c.parent = None
- grps = group.get_groups('organization')
- if grps:
- c.parent = grps[0]
- c.users = group.members_of_type(model.User)
-
-
-class OrganizationDatasetForm(SingletonPlugin):
-
- implements(IDatasetForm, inherit=True)
-
- def is_fallback(self):
- return True
-
- def package_types(self):
- return ['dataset']
-
- def new_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the new page
- """
- return 'package/new.html'
-
- def comments_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the comments page
- """
- return 'package/comments.html'
-
- def search_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the search page (if present)
- """
- return 'package/search.html'
-
- def read_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the read page
- """
- return 'package/read.html'
-
- def history_template(self):
- """
- Returns a string representing the location of the template to be
- rendered for the history page
- """
- return 'package/history.html'
-
- def package_form(self):
- return 'organizations/package_form.html'
-
- def db_to_form_schema(self):
- '''This is an interface to manipulate data from the database
- into a format suitable for the form (optional)'''
-
- def form_to_db_schema(self):
- schema = form_to_db_package_schema()
- schema['groups']['capacity'] = [ignore_missing, unicode]
- schema['__after'] = [group_required]
- return schema
-
- def check_data_dict(self, data_dict, schema=None):
- '''Check if the return data is correct, mostly for checking out
- if spammers are submitting only part of the form'''
-
- def setup_template_variables(self, context, data_dict):
- from pylons import config
-
- data_dict.update({'available_only': True})
-
- c.groups_available = c.userobj and \
- c.userobj.get_groups('organization') or []
- c.licences = [('', '')] + base.model.Package.get_license_options()
- c.is_sysadmin = authz.Authorizer().is_sysadmin(c.user)
-
- ## This is messy as auths take domain object not data_dict
- context_pkg = context.get('package', None)
- pkg = context_pkg or c.pkg
- if pkg:
- try:
- if not context_pkg:
- context['package'] = pkg
- check_access('package_change_state', context)
- c.auth_for_change_state = True
- except NotAuthorized:
- c.auth_for_change_state = False
diff --git a/ckanext/organizations/templates/email/join_publisher_request.txt b/ckanext/organizations/templates/email/join_publisher_request.txt
deleted file mode 100644
index c15b46e0c54..00000000000
--- a/ckanext/organizations/templates/email/join_publisher_request.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Dear administrator,
-
-A request has been made for membership of your organization $group.title by $requester.name {% if requester.fullname %}( $requester.fullname ){% end %}
-
-The reason given for the request was:
-
-"$reason"
-
-Please contact the user to verify and then if you would like to add this user you can do so by visiting ${h.url_for(controller='ckanext.organizers.controllers:OrganizationController', action='users', id=group.name, qualified=True) }
-
-If you do not wish to add this user you can safely disregard this email.
-
diff --git a/ckanext/organizations/templates/organization_edit.html b/ckanext/organizations/templates/organization_edit.html
deleted file mode 100644
index 224d0733463..00000000000
--- a/ckanext/organizations/templates/organization_edit.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- Edit: ${c.group.display_name}
- Edit: ${c.group.display_name}
- ${h.literal('no-sidebar')}
-
-
-
- ${Markup(c.form)}
-
-
-
-
-
diff --git a/ckanext/organizations/templates/organizations/form.html b/ckanext/organizations/templates/organizations/form.html
deleted file mode 100644
index 01d57727822..00000000000
--- a/ckanext/organizations/templates/organizations/form.html
+++ /dev/null
@@ -1,42 +0,0 @@
-{% extends "group/snippets/group_form.html" %}
-
-{#
-As the form is rendered as a seperate page we take advantage of this by
-overriding the form blocks depending on the current context
-#}
-{% block dataset_fields %}
- {% if action == "edit" %}{{ super() }}{% endif %}
-{% endblock %}
-
-{% block custom_fields %}
- {% if action == "edit" %}{{ super() }}{% endif %}
-{% endblock %}
-
-{% block save_text %}
- {%- if action == "edit" -%}
- {{ _('Update Organization') }}
- {%- else -%}
- {{ _('Create Organization') }}
- {%- endif -%}
-{% endblock %}
-
-{% block delete_button %}
- {% if action == "edit" %}{{ super() }}{% endif %}
-{% endblock %}
-
-{% block basic_fields %}
- {% set attrs = {'data-module': 'slug-preview-target'} %}
- {{ form.input('title', label=_('Title'), id='field-title', placeholder=_('My Organization'), value=data.title, error=errors.title, classes=['control-full'], attrs=attrs) }}
-
- {% set prefix = h.url_for(controller='group', action='read', id='') %}
- {% set domain = h.url_for(controller='group', action='read', id='', qualified=true) %}
- {% set domain = domain|replace("http://", "")|replace("https://", "") %}
- {% set attrs = {'data-module': 'slug-preview-slug', 'data-module-prefix': domain, 'data-module-placeholder': ''} %}
-
- {{ form.prepend('name', label=_('URL'), prepend=prefix, id='field-url', placeholder=_('my-organization'), value=data.name, error=errors.name, attrs=attrs) }}
-
- {{ form.markdown('description', label=_('Description'), id='field-description', placeholder=_('A little information about my organization...'), value=data.description, error=errors.description) }}
-
- {{ form.input('image_url', label=_('Image URL'), id='field-image-url', type='url', placeholder=_('http://example.com/my-image.jpg'), value=data.image_url, error=errors.image_url, classes=['control-full']) }}
-
- {% endblock %}
\ No newline at end of file
diff --git a/ckanext/organizations/templates/organizations/index.html b/ckanext/organizations/templates/organizations/index.html
deleted file mode 100644
index 41532b77b87..00000000000
--- a/ckanext/organizations/templates/organizations/index.html
+++ /dev/null
@@ -1,41 +0,0 @@
-{% extends "page.html" %}
-
-{% block subtitle %}{{ _('Organization') }}{% endblock %}
-
-{% block breadcrumb_content %}
- {% link_for _('Organizations'), controller='group', action='index' %}
-{% endblock %}
-
-{% block actions_content %}
- {% link_for _('Add Organization'), controller='group', action='new', class_='btn', icon='plus' %}
-{% endblock %}
-
-{% block primary_content %}
-
-
-
{{ _('Organizations') }}
- {% if c.page.items %}
- {% snippet "group/snippets/group_list.html", groups=c.page.items %}
- {% else %}
-
- {{ _('There are currently no organizations for this site') }}.
- {% if h.check_access('package_create') %}
- {% link_for _('How about creating one?'), controller='group', action='new' %}.
- {% endif %}
-
- {% endif %}
-
- {{ c.page.pager() }}
-
-{% endblock %}
-
-{% block secondary_content %}
-
-
{{ _('What are Organizations?') }}
-
- {% trans %}
-
Organizations allow you to add both users and datasets to it in order to control who can access and manage your datasets
- {% endtrans %}
-
-
-{% endblock %}
diff --git a/ckanext/organizations/templates/organizations/new.html b/ckanext/organizations/templates/organizations/new.html
deleted file mode 100644
index 73a284f46a3..00000000000
--- a/ckanext/organizations/templates/organizations/new.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends "group/base_form_page.html" %}
-
-{% block subtitle %}{{ _('Create an organization') }}{% endblock %}
-
-{% block breadcrumb_link %}{{ h.nav_link(_('Create Organization'), controller='group', action='edit', id=c.group.name) }}{% endblock %}
-
-{% block page_heading %}{{ _('Create an organization') }}{% endblock %}
-
-{% block secondary_content %}
-
-
{{ _('What are Organizations?') }}
-
- {% trans %}
-
An organization can be set-up to specify which users have permission to add or
- remove datasets from it.
- {% endtrans %}
-
-
-{% endblock %}
diff --git a/ckanext/organizations/templates/organizations/read.html b/ckanext/organizations/templates/organizations/read.html
deleted file mode 100644
index c3a66ca1f84..00000000000
--- a/ckanext/organizations/templates/organizations/read.html
+++ /dev/null
@@ -1,47 +0,0 @@
-{% extends "page.html" %}
-
-{% block subtitle %}{{ c.group_dict.display_name }}{% endblock %}
-
-{% block breadcrumb_content %}
- {% link_for _('Organizations'), controller='group', action='index' %}
- {% link_for c.group_dict.display_name|truncate(35), controller='group', action='read', id=c.group_dict.name %}
-{% endblock %}
-
-{% block actions_content %}
- {% if h.check_access('group_update', {'id': c.group.id}) %}
- {% link_for _('Add Dataset to Organization'), controller='package', action='new', group=c.group_dict.id, class_='btn', icon='plus' %}
- {% link_for _('Edit'), controller='group', action='edit', id=c.group_dict.name, class_='btn', icon='cog' %}
- {% link_for _('Manage Users'), controller='ckanext.organizations.controllers:OrganizationController', action='users', id=c.group_dict.name, class_='btn', icon='cog' %}
- {% endif %}
- {# {% link_for _('History'), controller='group', action='history', id=c.group_dict.name, class_='btn', icon='undo' %} #}
-{% endblock %}
-
-{% block primary_content %}
-
-
- {% include "package/snippets/search_form.html" %}
-
- {{ c.page.pager(q=c.q) }}
-
-{% endblock %}
-
-{% block secondary_content %}
- {% snippet 'snippets/group.html', group=c.group_dict %}
-
-
- {{ _('Administrators') }}
-
- {% for admin in c.group_admins %}
- {{ h.linked_user(admin, 30) }}
- {% endfor %}
-
-
-
- {{ h.snippet('snippets/facet_list.html', title='Tags', name='tags', extras={'id':c.group_dict.id}) }}
- {{ h.snippet('snippets/facet_list.html', title='Formats', name='res_format', extras={'id':c.group_dict.id}) }}
-{% endblock %}
-
-{% block links %}
- {{ super() }}
- {% include "group/snippets/feeds.html" %}
-{% endblock %}
diff --git a/ckanext/organizations/templates/organizations/users.html b/ckanext/organizations/templates/organizations/users.html
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/ckanext/organizations/templates/organizations/users_form.html b/ckanext/organizations/templates/organizations/users_form.html
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/ckanext/organizations/templates_legacy/organizations/apply.html b/ckanext/organizations/templates_legacy/organizations/apply.html
deleted file mode 100644
index d88eee54370..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/apply.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- Apply
- Apply for membership
-
-
-
- ${Markup(c.form)}
-
-
-
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/apply_form.html b/ckanext/organizations/templates_legacy/organizations/apply_form.html
deleted file mode 100644
index 4799eb96536..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/apply_form.html
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/email/join_publisher_request.txt b/ckanext/organizations/templates_legacy/organizations/email/join_publisher_request.txt
deleted file mode 100644
index c15b46e0c54..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/email/join_publisher_request.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Dear administrator,
-
-A request has been made for membership of your organization $group.title by $requester.name {% if requester.fullname %}( $requester.fullname ){% end %}
-
-The reason given for the request was:
-
-"$reason"
-
-Please contact the user to verify and then if you would like to add this user you can do so by visiting ${h.url_for(controller='ckanext.organizers.controllers:OrganizationController', action='users', id=group.name, qualified=True) }
-
-If you do not wish to add this user you can safely disregard this email.
-
diff --git a/ckanext/organizations/templates_legacy/organizations/form.html b/ckanext/organizations/templates_legacy/organizations/form.html
deleted file mode 100644
index 5a1dc6abe96..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/form.html
+++ /dev/null
@@ -1,156 +0,0 @@
-
-
-
-
-
-
Errors in form
-
The form contains invalid entries:
-
- ${"%s: %s" % (key if not key=='Name' else 'URL', error)}
-
-
-
-
-
-
-
Url
-
-
- ${h.url(controller='group', action='index')+'/'}
-
-
-
-
Warning: URL is very long. Consider changing it to something shorter.
-
2+ characters, lowercase, using only 'a-z0-9' and '-_'
-
${errors.get('name', '')}
-
-
-
-
Description
-
- ${markdown_editor('description', data.get('description'), 'notes', _('Start with a summary sentence ...'))}
-
-
-
-
Image URL:
-
-
-
The URL for the image that is associated with this organization.
-
-
-
-
State
-
-
- active
- deleted
-
-
-
-
-
-
-
Parent Organization
-
-
- ${ c.parent.title }
-
-
- No parent organization
-
-
-
-
-
-
- ${pg.title}
-
-
-
-
-
-
-
-
-
-
- Users (${len(c.users.all())})
-Manage users
-
-
-
-
- ${user['name']}
-
-
-
-
-
-
- There are no users currently in this publisher.
-
-
-
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/history.html b/ckanext/organizations/templates_legacy/organizations/history.html
deleted file mode 100644
index 227bf1b9a42..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/history.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
- History: ${c.group.display_name}
- History: ${c.group.display_name}
-
-
-
- Revisions
-
-
-
-
-
-
-
-
-
-
- Revision Timestamp Author Log Message
-
-
-
-
- ${h.radio("selected1", revision_dict['id'], checked=(index == 0))}
- ${h.radio("selected2", revision_dict['id'], checked=(index == len(c.group_revisions)-1))}
-
-
- ${revision_dict['id']}
-
- ${revision_dict['timestamp']}
- ${h.linked_user(revision_dict['author'])}
- ${revision_dict['message']}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/index.html b/ckanext/organizations/templates_legacy/organizations/index.html
deleted file mode 100644
index cbf38919286..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/index.html
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
- Organizations
- Organizations
-
-
-
- What Are Organizations?
- Whilst tags are great at collecting datasets together, there are occasions when you want to restrict users from editing a collection. An organization can be set-up to specify which users have permission to add or remove datasets from it.
-
-
-
-
-
- ${c.page.pager()}
- ${group_list_from_dict(c.page.items)}
- ${c.page.pager()}
-
-
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/layout.html b/ckanext/organizations/templates_legacy/organizations/layout.html
deleted file mode 100644
index 7e740e9bd3a..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/layout.html
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
- ${h.subnav_named_route(c, h.icon('group') + _('View'), 'organization_read',controller='group', action='read', id=c.group.name)}
- ${h.subnav_named_route(c, h.icon('page_white_stack') + _('History'), 'organization_action', controller='group', action='history', id=c.group.name)}
- |
-
- ${h.icon('add') + _('Add Dataset')}
-
-
- ${h.subnav_named_route( c,h.icon('group_edit') + _('Edit'), 'organization_action', action='edit', id=c.group.name )}
-
-
- ${h.icon('group_edit') + _('Join')}
-
-
-
-
-
- ${h.subnav_named_route(c, h.icon('group') + _('List Organizations'), "organization_index", action="index" )}
-
-
- ${ h.subnav_named_route(c, h.icon('group_add') + _('Add an Organization'), "organization_new", action='new')}
-
-
-
-
-
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/new.html b/ckanext/organizations/templates_legacy/organizations/new.html
deleted file mode 100644
index 642d57f5b5e..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/new.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
- Add an organization
- Add an organization
-
-
- ${Markup(c.form)}
-
-
-
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/package_form.html b/ckanext/organizations/templates_legacy/organizations/package_form.html
deleted file mode 100644
index cfd68253d3f..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/package_form.html
+++ /dev/null
@@ -1,324 +0,0 @@
-
-
-
-
Errors in form
-
The form contains invalid entries:
-
- ${"%s: %s" % (key if not key=='Name' else 'URL', error)}
-
-
-
-
- Resource ${idx}:
-
- ${thiskey}: ${errorinfo};
-
-
-
-
-
-
-
-
-
-
-
-
-
Title
-
-
-
${errors.get('title', '')}
-
-
-
-
-
Url
-
-
- ${h.url(controller='package', action='search')+'/'}
-
-
-
-
Warning: URL is very long. Consider changing it to something shorter.
-
2+ characters, lowercase, using only 'a-z0-9' and '-_'
-
${errors.get('name', '')}
-
-
-
-
-
Home Page
-
-
-
The URL for the web page describing the data (not the data itself).
-
e.g. http://www.example.com/growth-figures.html
-
${errors.get('url', '')}
-
-
-
-
-
License
-
-
-
- ${licence_desc}
-
-
-
(Don't worry if you don't know which license the data has been released under).
-
-
-
-
-
-
-
-
-
-
-
-
- Add Resources
-
-
Upload or link data files, APIs and other materials related to your dataset.
-
-
-
-
-
-
-
-
-
Author
-
-
-
The name of the main contact, for enquiries about this particular dataset, using the e-mail address in the following field.
-
-
-
-
-
-
-
Maintainer
-
-
-
If there is another important contact person (in addition to the person in the Author field) then provide details here.
-
-
-
-
-
Maintainer email
-
-
-
-
-
-
-
Version
-
-
-
A number representing the version (if applicable)
-
e.g. 1.2.0
-
-
-
-
-
-
-
-
- Delete
-
- Do you really want to change the state of this dataset? Yes!
-
- This dataset is
-
- active
- deleted
-
-
-
-
-
-
-
-
-
Summary
-
-
Briefly describe the changes you have made...
-
${data.get('log_message', h.auto_log_message(c))}
-
-
-
-
-
-
-
Author: ${c.author}
-
- Since you have not signed in this will just be your IP address.
- Click here to sign in before saving (opens in new window).
-
-
-
-
-
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/read.html b/ckanext/organizations/templates_legacy/organizations/read.html
deleted file mode 100644
index a0224c00bca..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/read.html
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
- ${c.group_dict.display_name}
- ${c.group_dict.display_name}
-
- ${c.group.image_url}
-
-
-
-
-
-
-
-
-
-
-
- Administrators
-
- ${h.linked_user(admin)}
-
-
-
-
-
- Members
-
- ${h.linked_user(editor)}
-
-
-
-
-
- ${facet_div('tags', 'Tags')}
- ${facet_div('res_format', 'Resource Formats')}
-
-
-
- State: ${c.group['state']}
-
-
-
-
-
-
-
-
-
-
Datasets
-
-
- ${field_list()}
-
-
You searched for "${c.q}". ${c.page.item_count} datasets found.
- ${c.page.pager()}
- ${package_list_from_dict(c.page.items)}
- ${c.page.pager()}
-
-
-
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/users.html b/ckanext/organizations/templates_legacy/organizations/users.html
deleted file mode 100644
index 9b5e47d9dbf..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/users.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- Users: ${c.group.display_name}
- Users: ${c.group.display_name}
-
-
-
- ${Markup(c.form)}
-
-
-
-
-
-
diff --git a/ckanext/organizations/templates_legacy/organizations/users_form.html b/ckanext/organizations/templates_legacy/organizations/users_form.html
deleted file mode 100644
index cc9ff15e0bf..00000000000
--- a/ckanext/organizations/templates_legacy/organizations/users_form.html
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
Errors in form
-
The form contains invalid entries:
-
- ${"%s: %s" % (key, error)}
-
-
-
-
-
-
- Users
-
-
-
-
-
- ${user['name']}
-
- Admin
- Editor
-
- Delete
-
-
-
-
- There are no users currently in this organization.
-
- Add users
-
- User
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/about.rst b/doc/about.rst
deleted file mode 100644
index 72df911d93f..00000000000
--- a/doc/about.rst
+++ /dev/null
@@ -1,33 +0,0 @@
-About CKAN
-===========
-
-Development
------------
-
-CKAN is an open source project and contributions are welcome!
-
-We discuss large changes and new features on the `ckan-discuss `_ mailing list, and technical issues on the `ckan-dev `_ mailing list. Please join us there.
-
-You can find developer resources and links to our ticketing system on the `CKAN wiki `_.
-
-Acknowledgements
-----------------
-
-Thanks to the following projects, without which CKAN would not have
-been possible:
-
- * `Python `_
- * `Pylons `_
- * CKAN logo: "angry hamster" by http://www.maedelmaedel.com/ and
- http://www.villainous.biz/
- * `FamFamFam silk icons `_
-
-Copying and Licence
--------------------
-
-This material is copyright (c) 2006-2011 Open Knowledge Foundation.
-
-It is open and licensed under the GNU Affero General Public License (AGPL) v3.0
-whose full text may be found at:
-
-
diff --git a/doc/administrative-dashboard.rst b/doc/administrative-dashboard.rst
deleted file mode 100644
index 6e90735e055..00000000000
--- a/doc/administrative-dashboard.rst
+++ /dev/null
@@ -1,66 +0,0 @@
-=============================
-CKAN Administrative Dashboard
-=============================
-
-CKAN provides an administrative dashboard available to Sysadmin Administrators.
-The dashboard allows you to:
-
-* Create and remove sysadmins
-* Edit general system level authorization
-* Manage the 'trash' bin (i.e. datasets or revisions that have been marked as deleted)
-
-The dashboard is located, relative to your site root, at ``/ckan-admin/``.
-
-.. note:: To create your first sysadmin you cannot use Dashboard as you will
- not yet have access! Instead create a sysadmin using the command line
- ``paster`` by running the following command::
-
- paster sysadmin -h
-
-Setting System-Level Roles
-==========================
-
-Authorization interface is located at: ``/ckan-admin/authz``
-
-This page allows you to see and change the users and authorization groups who
-have 'roles' on the 'System Object'. In a standard installation, there are four
-'roles' which a user can have on the System (or on any object):
-
-* admin (administrator)
-
- * Having an admin role on the System objects means you are a System Administrator
- and may carry out **any** operation on any object.
-
- .. warning:: Once a person is an system administrator, they can carry out
- **any** operatoin on the system including **destructive**
- ones. Grant System Administrator access with care!
-
-* reader (Read action allowed)
-
- * Without read access a site user or visitor will not be able to see
- anything except the login page, even the page which allows them to
- create an account, so they're locked out forever unless they already
- have a valid account.
-
-* editor (Update action allowed)
-* anon-editor
-
-.. note:: these roles can be applied to users on your system as well as to
- 'pseudo-users' like 'visitor', which stands for anyone who accesses
- the site whether logged in or not (see :doc:`authorization` for more
- on permissions and roles).
-
-Make Someone a Sysadmin
-=======================
-
-Given the user the role 'admin'.
-
-The Trash
-=========
-
-When you delete datasets or revisions they go into the 'trash'. The contents of
-the trash can be viewed by System Administrators at: ``/ckan-admin/trash``.
-
-Contents of the trash can be removed permanently (and **irreversibly**) by
-going to the trash page and selecting the purge option.
-
diff --git a/doc/configuration.rst b/doc/configuration.rst
index 7dbc7a4c7f8..6e9bae57393 100644
--- a/doc/configuration.rst
+++ b/doc/configuration.rst
@@ -233,6 +233,23 @@ CKAN operates a delegated authentication model based on `OpenID