[ckan-changes] commit/ckan: 6 new changesets
Bitbucket
commits-noreply at bitbucket.org
Wed Oct 5 13:31:45 UTC 2011
6 new changesets in ckan:
http://bitbucket.org/okfn/ckan/changeset/6904048ce970/
changeset: 6904048ce970
branch: feature-1369-strip-showdown
user: zephod
date: 2011-10-04 14:44:07
summary: [layout-base][s]: Stripped showdown.js. Okfn needs to accept a pull request for ckanjs to validate this change.
affected #: 2 files (-1 bytes)
--- a/ckan/public/scripts/application.js Tue Oct 04 13:14:14 2011 +0100
+++ b/ckan/public/scripts/application.js Tue Oct 04 13:44:07 2011 +0100
@@ -211,7 +211,6 @@
my.setupMarkdownEditor = function(elements) {
// Markdown editor hooks
- var converter=new Showdown.converter();
elements.live('click', function(e) {
e.preventDefault();
var $el = $(e.target);
--- a/ckan/templates/layout_base.html Tue Oct 04 13:14:14 2011 +0100
+++ b/ckan/templates/layout_base.html Tue Oct 04 13:44:07 2011 +0100
@@ -212,7 +212,6 @@
<script type="text/javascript" src="${g.site_url}/scripts/vendor/underscore/1.1.6/underscore.js"></script><script type="text/javascript" src="${g.site_url}/scripts/vendor/backbone/0.5.1/backbone.js"></script><!-- TODO should not be necessary; we use AJAX to produce consistent previews -->
- <script type="text/javascript" src="${g.site_url}/scripts/vendor/showdown/showdown.js"></script><script type="text/javascript" src="${g.site_url}/scripts/vendor/jquery.fileupload/20110801/jquery.iframe-transport.js"></script><script type="text/javascript" src="${g.site_url}/scripts/vendor/jquery.fileupload/20110801/jquery.fileupload.js"></script><script src="https://raw.github.com/okfn/ckanjs/master/pkg/ckanjs.js"></script>
http://bitbucket.org/okfn/ckan/changeset/ca18279f3823/
changeset: ca18279f3823
branch: feature-1264-core-admin
user: zephod
date: 2011-10-04 18:37:57
summary: [admin][l]: Merged ckanext-admin into core.
affected #: 7 files (-1 bytes)
--- a/ckan/config/routing.py Tue Oct 04 13:14:14 2011 +0100
+++ b/ckan/config/routing.py Tue Oct 04 17:37:57 2011 +0100
@@ -256,6 +256,9 @@
map.connect('/revision/diff/{id}', controller='revision', action='diff')
map.connect('/revision/list', controller='revision', action='list')
map.connect('/revision/{id}', controller='revision', action='read')
+
+ map.connect('ckanadmin_index', '/ckan-admin', controller='admin', action='index')
+ map.connect('ckanadmin', '/ckan-admin/{action}', controller='admin')
for plugin in routing_plugins:
map = plugin.after_map(map)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/controllers/admin.py Tue Oct 04 17:37:57 2011 +0100
@@ -0,0 +1,292 @@
+from ckan.lib.base import *
+import ckan.authz
+import ckan.lib.authztool
+import ckan.model as model
+
+from ckan.model.authz import Role
+roles = Role.get_all()
+role_tuples = [(x,x) for x in roles]
+
+def get_sysadmins():
+ q = model.Session.query(model.SystemRole).filter_by(role=model.Role.ADMIN)
+ return [uor.user for uor in q.all() if uor.user]
+
+
+class AdminController(BaseController):
+ def __before__(self, action, **params):
+ super(AdminController, self).__before__(action, **params)
+ if not ckan.authz.Authorizer().is_sysadmin(unicode(c.user)):
+ abort(401, 'Need to be system administrator to administer')
+ c.revision_change_state_allowed = (
+ c.user and
+ self.authorizer.is_authorized(c.user, model.Action.CHANGE_STATE,
+ model.Revision)
+ )
+
+ def index(self):
+ #now pass the list of sysadmins
+ c.sysadmins = [a.name for a in get_sysadmins()]
+
+ return render('admin/index.html')
+
+
+ def authz(self):
+ def action_save_form(users_or_authz_groups):
+ # The permissions grid has been saved
+ # which is a grid of checkboxes named user$role
+ rpi = request.params.items()
+
+ # The grid passes us a list of the users/roles that were displayed
+ submitted = [ a for (a,b) in rpi if (b == u'submitted')]
+ # and also those which were checked
+ checked = [ a for (a,b) in rpi if (b == u'on')]
+
+ # from which we can deduce true/false for each user/role combination
+ # that was displayed in the form
+ table_dict={}
+ for a in submitted:
+ table_dict[a]=False
+ for a in checked:
+ table_dict[a]=True
+
+ # now we'll split up the user$role strings to make a dictionary from
+ # (user,role) to True/False, which tells us what we need to do.
+ new_user_role_dict={}
+ for (ur,val) in table_dict.items():
+ u,r = ur.split('$')
+ new_user_role_dict[(u,r)] = val
+
+ # we get the current user/role assignments
+ # and make a dictionary of them
+ current_uors = model.Session.query(model.SystemRole).all()
+
+ if users_or_authz_groups=='users':
+ current_users_roles = [( uor.user.name, uor.role) for uor in current_uors if uor.user]
+ elif users_or_authz_groups=='authz_groups':
+ current_users_roles = [( uor.authorized_group.name, uor.role) for uor in current_uors if uor.authorized_group]
+ else:
+ assert False, "shouldn't be here"
+
+ current_user_role_dict={}
+ for (u,r) in current_users_roles:
+ current_user_role_dict[(u,r)]=True
+
+ # and now we can loop through our dictionary of desired states
+ # checking whether a change needs to be made, and if so making it
+
+ # WORRY: Here it seems that we have to check whether someone is already assigned
+ # a role, in order to avoid assigning it twice, or attempting to delete it when
+ # it doesn't exist. Otherwise problems occur. However this doesn't affect the
+ # index page, which would seem to be prone to suffer the same effect.
+ # Why the difference?
+
+ if users_or_authz_groups=='users':
+ for ((u,r), val) in new_user_role_dict.items():
+ if val:
+ if not ((u,r) in current_user_role_dict):
+ model.add_user_to_role(model.User.by_name(u),r,model.System())
+ else:
+ if ((u,r) in current_user_role_dict):
+ model.remove_user_from_role(model.User.by_name(u),r,model.System())
+ elif users_or_authz_groups=='authz_groups':
+ for ((u,r), val) in new_user_role_dict.items():
+ if val:
+ if not ((u,r) in current_user_role_dict):
+ model.add_authorization_group_to_role(model.AuthorizationGroup.by_name(u),r,model.System())
+ else:
+ if ((u,r) in current_user_role_dict):
+ model.remove_authorization_group_from_role(model.AuthorizationGroup.by_name(u),r,model.System())
+ else:
+ assert False, "shouldn't be here"
+
+
+ # finally commit the change to the database
+ model.Session.commit()
+ h.flash_success("Changes Saved")
+
+ if ('save' in request.POST):
+ action_save_form('users')
+
+ if ('authz_save' in request.POST):
+ action_save_form('authz_groups')
+
+
+
+
+ def action_add_form(users_or_authz_groups):
+ # The user is attempting to set new roles for a named user
+ new_user = request.params.get('new_user_name')
+ # this is the list of roles whose boxes were ticked
+ checked_roles = [ a for (a,b) in request.params.items() if (b == u'on')]
+ # this is the list of all the roles that were in the submitted form
+ submitted_roles = [ a for (a,b) in request.params.items() if (b == u'submitted')]
+
+ # from this we can make a dictionary of the desired states
+ # i.e. true for the ticked boxes, false for the unticked
+ desired_roles = {}
+ for r in submitted_roles:
+ desired_roles[r]=False
+ for r in checked_roles:
+ desired_roles[r]=True
+
+ # again, in order to avoid either creating a role twice or deleting one which is
+ # non-existent, we need to get the users' current roles (if any)
+
+ current_uors = model.Session.query(model.SystemRole).all()
+
+ if users_or_authz_groups=='users':
+ current_roles = [uor.role for uor in current_uors if ( uor.user and uor.user.name == new_user )]
+ user_object = model.User.by_name(new_user)
+ if user_object==None:
+ # The submitted user does not exist. Bail with flash message
+ h.flash_error('unknown user:' + str (new_user))
+ else:
+ # Whenever our desired state is different from our current state, change it.
+ for (r,val) in desired_roles.items():
+ if val:
+ if (r not in current_roles):
+ model.add_user_to_role(user_object, r, model.System())
+ else:
+ if (r in current_roles):
+ model.remove_user_from_role(user_object, r, model.System())
+ h.flash_success("User Added")
+
+ elif users_or_authz_groups=='authz_groups':
+ current_roles = [uor.role for uor in current_uors if ( uor.authorized_group and uor.authorized_group.name == new_user )]
+ user_object = model.AuthorizationGroup.by_name(new_user)
+ if user_object==None:
+ # The submitted user does not exist. Bail with flash message
+ h.flash_error('unknown authorization group:' + str (new_user))
+ else:
+ # Whenever our desired state is different from our current state, change it.
+ for (r,val) in desired_roles.items():
+ if val:
+ if (r not in current_roles):
+ model.add_authorization_group_to_role(user_object, r, model.System())
+ else:
+ if (r in current_roles):
+ model.remove_authorization_group_from_role(user_object, r, model.System())
+ h.flash_success("Authorization Group Added")
+
+
+ else:
+ assert False, "shouldn't be here"
+
+
+
+
+
+
+
+
+
+
+ # and finally commit all these changes to the database
+ model.Session.commit()
+
+ if 'add' in request.POST:
+ action_add_form('users')
+ if 'authz_add' in request.POST:
+ action_add_form('authz_groups')
+
+
+ # =================
+ # Display the page
+
+ # Find out all the possible roles. For the system object that's just all of them.
+ possible_roles = Role.get_all()
+
+ # get the list of users who have roles on the System, with their roles
+ uors = model.Session.query(model.SystemRole).all()
+ # uniquify and sort
+ users = sorted(list(set([uor.user.name for uor in uors if uor.user])))
+ authz_groups = sorted(list(set([uor.authorized_group.name for uor in uors if uor.authorized_group])))
+
+ # make a dictionary from (user, role) to True, False
+ users_roles = [( uor.user.name, uor.role) for uor in uors if uor.user]
+ user_role_dict={}
+ for u in users:
+ for r in possible_roles:
+ if (u,r) in users_roles:
+ user_role_dict[(u,r)]=True
+ else:
+ user_role_dict[(u,r)]=False
+
+
+ # and similarly make a dictionary from (authz_group, role) to True, False
+ authz_groups_roles = [( uor.authorized_group.name, uor.role) for uor in uors if uor.authorized_group]
+ authz_groups_role_dict={}
+ for u in authz_groups:
+ for r in possible_roles:
+ if (u,r) in authz_groups_roles:
+ authz_groups_role_dict[(u,r)]=True
+ else:
+ authz_groups_role_dict[(u,r)]=False
+
+
+
+ # pass these variables to the template for rendering
+ c.roles = possible_roles
+
+ c.users = users
+ c.user_role_dict = user_role_dict
+
+ c.authz_groups = authz_groups
+ c.authz_groups_role_dict = authz_groups_role_dict
+
+ return render('admin/authz.html')
+
+ def trash(self):
+ c.deleted_revisions = model.Session.query(
+ model.Revision).filter_by(state=model.State.DELETED)
+ c.deleted_packages = model.Session.query(
+ model.Package).filter_by(state=model.State.DELETED)
+ if not request.params:
+ return render('admin/trash.html')
+ else:
+ # NB: we repeat retrieval of of revisions
+ # this is obviously inefficient (but probably not *that* bad)
+ # but has to be done to avoid (odd) sqlalchemy errors (when doing
+ # purge packages) of form: "this object already exists in the
+ # session"
+ msgs = []
+ if 'purge-packages' in request.params:
+ revs_to_purge = []
+ for pkg in c.deleted_packages:
+ revisions = [ x[0] for x in pkg.all_related_revisions ]
+ # ensure no accidental purging of other(non-deleted) packages
+ # initially just avoided purging revisions where
+ # non-deleted packages were affected
+ # however this lead to confusing outcomes e.g.
+ # we succesfully deleted revision in which package was deleted (so package
+ # now active again) but no other revisions
+ problem = False
+ for r in revisions:
+ affected_pkgs = set(r.packages).difference(set(c.deleted_packages))
+ if affected_pkgs:
+ msg = _('Cannot purge package %s as ' + \
+ 'associated revision %s includes non-deleted packages %s')
+ msg = msg % (pkg.id, r.id, [pkg.id for r in affected_pkgs])
+ msgs.append(msg)
+ problem = True
+ break
+ if not problem:
+ revs_to_purge += [ r.id for r in revisions ]
+ model.Session.remove()
+ else:
+ revs_to_purge = [ rev.id for rev in c.deleted_revisions ]
+
+ revs_to_purge = list(set(revs_to_purge))
+ for id in revs_to_purge:
+ revision = model.Session.query(model.Revision).get(id)
+ try:
+ model.repo.purge_revision(revision, leave_record=False)
+ except Exception, inst:
+ msg = 'Problem purging revision %s: %s' % (id,
+ inst)
+ msgs.append(msg)
+ h.flash_success(_('Purge complete'))
+ for msg in msgs:
+ h.flash_error(msg)
+ h.redirect_to(h.url_for('ckanadmin', action='trash'))
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/templates/admin/authz.html Tue Oct 04 17:37:57 2011 +0100
@@ -0,0 +1,53 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+
+ <py:def function="page_title">System Roles</py:def>
+
+ <div py:match="content">
+
+ <h1>Roles on the System Object</h1>
+
+ <h2>Update Existing Roles</h2>
+
+ <form id="theform" method="POST">
+ ${authz_form_table('theform', c.roles, c.users, c.user_role_dict)}
+ <button type="submit" name="save">
+ Save
+ </button>
+ </form>
+
+ <h2>Add Roles for Any User</h2>
+
+ <form id="addform" method="POST">
+ ${authz_add_table(c.roles)}
+ <button type="submit" name="add"> Add </button>
+ </form>
+
+ <hr/>
+
+ <h2>Existing Roles for Authorization Groups</h2>
+
+ <form id="authzgroup_form" method="POST">
+ ${authz_form_group_table('authzgroup_form', c.roles, c.authz_groups, c.authz_groups_role_dict)}
+ <button type="submit" name="authz_save">
+ Save
+ </button>
+ </form>
+
+ <h2>Add Roles for Any Authorization Group</h2>
+
+ <form id="authzgroup_addform" method="POST">
+ ${authz_add_group_table(c.roles)}
+ <button type="submit" name="authz_add"> Add </button>
+ </form>
+
+
+
+
+ </div>
+
+ <xi:include href="layout.html" />
+</html>
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/templates/admin/index.html Tue Oct 04 17:37:57 2011 +0100
@@ -0,0 +1,24 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+
+ <py:def function="page_title">Authorization - Administration</py:def>
+
+ <div py:match="content">
+ <h1>Administration Dashboard</h1>
+
+ <h2>Current Sysadmins</h2>
+ <p>You can change sysadmins on the <a
+ href="${h.url_for('ckanadmin',
+ action='authz')}">authorization page</a>.</p>
+ <ul>
+ <li py:for="user in c.sysadmins">
+ ${h.linked_user(user)}
+ </li>
+ </ul>
+ </div>
+
+ <xi:include href="layout.html" />
+</html>
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/templates/admin/layout.html Tue Oct 04 17:37:57 2011 +0100
@@ -0,0 +1,30 @@
+<html
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip=""
+ >
+ <py:match path="minornavigation">
+ <ul class="tabbed">
+ <li>
+ <a href="${h.url_for('ckanadmin', action='index')}">
+ Home
+ </a>
+ </li>
+ <li>
+ <a href="${h.url_for('ckanadmin', action='authz')}">
+ Authorization
+ </a>
+ </li>
+ <li>
+ <a href="${h.url_for('ckanadmin', action='trash')}">
+ Trash
+ </a>
+ </li>
+ </ul>
+ </py:match>
+
+ <xi:include href="../layout.html" />
+</html>
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/templates/admin/trash.html Tue Oct 04 17:37:57 2011 +0100
@@ -0,0 +1,42 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+
+ <py:def function="page_title">Trash - Administration</py:def>
+
+ <div py:match="content">
+ <h1>The Trash Bin</h1>
+
+ <h2>Deleted Revisions</h2>
+ <form method="POST" id="form-purge-revisions">
+ <button
+ type="submit"
+ name="purge-revisions"
+ value="purge"
+ class="purge-button"
+ >
+ Purge them all (forever and irreversibly)
+ </button>
+ </form>
+
+ ${revision_list(c.deleted_revisions)}
+
+ <h2>Deleted Packages</h2>
+ <form method="POST" id="form-purge-packages">
+ <button
+ type="submit"
+ name="purge-packages"
+ value="purge"
+ class="purge-button"
+ >
+ Purge them all (forever and irreversibly)
+ </button>
+ </form>
+
+ ${package_list(c.deleted_packages)}
+ </div>
+
+ <xi:include href="layout.html" />
+</html>
+
--- a/ckan/templates/layout_base.html Tue Oct 04 13:14:14 2011 +0100
+++ b/ckan/templates/layout_base.html Tue Oct 04 17:37:57 2011 +0100
@@ -157,7 +157,7 @@
</a></li><li>
- <a href="${url('/ckan-admin')}">
+ <a href="${h.url_for('ckanadmin_index')}">
Site Admin
</a></li>
http://bitbucket.org/okfn/ckan/changeset/4fe9497efe4a/
changeset: 4fe9497efe4a
branch: feature-1264-core-admin
user: zephod
date: 2011-10-04 21:12:28
summary: [admin][m]: Made admin pages as beautiful as other template pages.
affected #: 7 files (-1 bytes)
--- a/ckan/lib/helpers.py Tue Oct 04 17:37:57 2011 +0100
+++ b/ckan/lib/helpers.py Tue Oct 04 20:12:28 2011 +0100
@@ -264,3 +264,7 @@
def time_ago_in_words_from_str(date_str, granularity='month'):
return date.time_ago_in_words(date_str_to_datetime(date_str), granularity=granularity)
+def button_attr(enable, type='primary'):
+ if enable:
+ return 'class="pretty-button %s"' % type
+ return 'disabled class="pretty-button disabled"'
--- a/ckan/public/css/style.css Tue Oct 04 17:37:57 2011 +0100
+++ b/ckan/public/css/style.css Tue Oct 04 20:12:28 2011 +0100
@@ -1078,9 +1078,6 @@
}
-/* ================================== */
-/* = Twitter.Bootstrap Form Buttons = */
-/* ================================== */
div.form-submit {
background: #eee;
padding: 20px;
@@ -1098,6 +1095,23 @@
clear: both;
}
+/* ==================== */
+/* = Multi-form pages = */
+/* ==================== */
+body.admin form {
+ margin-bottom: 30px;
+}
+body.admin form button {
+ float: right;
+}
+body.admin.authz form button {
+ width: 120px;
+}
+
+
+/* ================================== */
+/* = Twitter.Bootstrap Form Buttons = */
+/* ================================== */
.pretty-button {
cursor: pointer;
display: inline-block;
--- a/ckan/templates/_util.html Tue Oct 04 17:37:57 2011 +0100
+++ b/ckan/templates/_util.html Tue Oct 04 20:12:28 2011 +0100
@@ -52,46 +52,46 @@
<ul py:def="package_list(packages)" class="datasets"><li py:for="package in packages"
class="${'fullyopen' if (package.isopen() and package.resources) else None}">
- <div class="header">
- <span class="title">
- ${h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name))}
- </span>
-
- <div class="search_meta">
- <py:if test="package.resources">
- <ul class="dataset_formats">
- <py:for each="resource in package.resources">
- <py:if test="resource.format and not resource.format == ''">
- <li><a href="${resource.url}"
- title="${resource.description}">${resource.format}</a></li>
- </py:if>
- </py:for>
+ <div class="header">
+ <span class="title">
+ ${h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name))}
+ </span>
+
+ <div class="search_meta">
+ <py:if test="package.resources">
+ <ul class="dataset_formats">
+ <py:for each="resource in package.resources">
+ <py:if test="resource.format and not resource.format == ''">
+ <li><a href="${resource.url}"
+ title="${resource.description}">${resource.format}</a></li>
+ </py:if>
+ </py:for>
+ </ul>
+ </py:if>
+ <ul class="openness">
+ <py:if test="package.isopen()">
+ <li>
+ <a href="http://opendefinition.org/okd/" title="This dataset satisfies the Open Definition.">
+ <img src="http://assets.okfn.org/images/ok_buttons/od_80x15_blue.png" alt="[Open Data]" />
+ </a>
+ </li>
+ </py:if>
+ <py:if test="not package.isopen()">
+ <li>
+ <span class="closed">
+ ${h.icon('lock')} Not Openly Licensed
+ </span>
+ </li>
+ </py:if></ul>
- </py:if>
- <ul class="openness">
- <py:if test="package.isopen()">
- <li>
- <a href="http://opendefinition.org/okd/" title="This dataset satisfies the Open Definition.">
- <img src="http://assets.okfn.org/images/ok_buttons/od_80x15_blue.png" alt="[Open Data]" />
- </a>
- </li>
- </py:if>
- <py:if test="not package.isopen()">
- <li>
- <span class="closed">
- ${h.icon('lock')} Not Openly Licensed
- </span>
- </li>
- </py:if>
- </ul>
+ </div></div>
- </div>
- <div class="extract">
- ${h.markdown_extract(package.notes)}
- </div>
- <!--ul py:if="package.tags" class="tags">
- <li py:for="tag in package.tags">${tag.name}</li>
- </ul-->
+ <div class="extract">
+ ${h.markdown_extract(package.notes)}
+ </div>
+ <!--ul py:if="package.tags" class="tags">
+ <li py:for="tag in package.tags">${tag.name}</li>
+ </ul--></li></ul>
@@ -99,11 +99,11 @@
<li py:for="package in packages"
class="${'fullyopen' if (package.isopen and package.get('resources')) else None}"><div class="header">
- <span class="title">
- ${h.link_to(package.get('title') or package.get('name'), h.url_for(controller='package', action='read', id=package.get('name')))}
- </span>
-
- <div class="search_meta">
+ <span class="title">
+ ${h.link_to(package.get('title') or package.get('name'), h.url_for(controller='package', action='read', id=package.get('name')))}
+ </span>
+
+ <div class="search_meta"><py:if test="package.resources"><ul class="dataset_formats"><py:for each="resource in package.resources">
@@ -387,6 +387,9 @@
</td><td>${revision.message}</td></tr>
+ <tr py:if="revisions.count()==0" class="table-empty">
+ <td colspan="5">(none)</td>
+ </tr></table>
--- a/ckan/templates/admin/authz.html Tue Oct 04 17:37:57 2011 +0100
+++ b/ckan/templates/admin/authz.html Tue Oct 04 20:12:28 2011 +0100
@@ -3,44 +3,43 @@
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip="">
- <py:def function="page_title">System Roles</py:def>
+ <py:def function="page_title">Administration - Authorization</py:def>
+ <py:def function="page_heading">Administration - Authorization</py:def><div py:match="content">
-
- <h1>Roles on the System Object</h1>
-
- <h2>Update Existing Roles</h2>
+ <h3>Update Existing Roles</h3><form id="theform" method="POST">
${authz_form_table('theform', c.roles, c.users, c.user_role_dict)}
- <button type="submit" name="save">
- Save
+ <button type="submit" name="save" class="pretty-button primary">
+ Save Changes
</button>
+ <div class="clear"></div></form>
- <h2>Add Roles for Any User</h2>
-
+ <h3>Add Roles for Any User</h3><form id="addform" method="POST">
${authz_add_table(c.roles)}
- <button type="submit" name="add"> Add </button>
+ <button type="submit" name="add" class="pretty-button primary">Add Role</button>
+ <div class="clear"></div></form><hr/>
- <h2>Existing Roles for Authorization Groups</h2>
+ <h3>Existing Roles for Authorization Groups</h3><form id="authzgroup_form" method="POST">
${authz_form_group_table('authzgroup_form', c.roles, c.authz_groups, c.authz_groups_role_dict)}
- <button type="submit" name="authz_save">
- Save
- </button>
+ <button type="submit" name="authz_save" class="pretty-button primary">Save Changes</button>
+ <div class="clear"></div></form>
- <h2>Add Roles for Any Authorization Group</h2>
+ <h3>Add Roles for Any Authorization Group</h3><form id="authzgroup_addform" method="POST">
${authz_add_group_table(c.roles)}
- <button type="submit" name="authz_add"> Add </button>
+ <button type="submit" name="authz_add" class="pretty-button primary">Add Role</button>
+ <div class="clear"></div></form>
--- a/ckan/templates/admin/index.html Tue Oct 04 17:37:57 2011 +0100
+++ b/ckan/templates/admin/index.html Tue Oct 04 20:12:28 2011 +0100
@@ -3,12 +3,11 @@
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip="">
- <py:def function="page_title">Authorization - Administration</py:def>
+ <py:def function="page_title">Administration Dashboard</py:def>
+ <py:def function="page_heading">Administration Dashboard</py:def><div py:match="content">
- <h1>Administration Dashboard</h1>
-
- <h2>Current Sysadmins</h2>
+ <h3>Current Sysadmins</h3><p>You can change sysadmins on the <a
href="${h.url_for('ckanadmin',
action='authz')}">authorization page</a>.</p>
--- a/ckan/templates/admin/layout.html Tue Oct 04 17:37:57 2011 +0100
+++ b/ckan/templates/admin/layout.html Tue Oct 04 20:12:28 2011 +0100
@@ -6,17 +6,17 @@
><py:match path="minornavigation"><ul class="tabbed">
- <li>
+ <li py:attrs="{'class':'current-tab'} if c.action=='index' else {}"><a href="${h.url_for('ckanadmin', action='index')}">
Home
</a></li>
- <li>
+ <li py:attrs="{'class':'current-tab'} if c.action=='authz' else {}"><a href="${h.url_for('ckanadmin', action='authz')}">
Authorization
</a></li>
- <li>
+ <li py:attrs="{'class':'current-tab'} if c.action=='trash' else {}"><a href="${h.url_for('ckanadmin', action='trash')}">
Trash
</a>
--- a/ckan/templates/admin/trash.html Tue Oct 04 17:37:57 2011 +0100
+++ b/ckan/templates/admin/trash.html Tue Oct 04 20:12:28 2011 +0100
@@ -3,38 +3,44 @@
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip="">
- <py:def function="page_title">Trash - Administration</py:def>
+ <py:def function="page_title">Administration - Trash</py:def>
+ <py:def function="page_heading">Administration - Trash</py:def><div py:match="content">
- <h1>The Trash Bin</h1>
-
- <h2>Deleted Revisions</h2>
+ <h3>Deleted Revisions</h3><form method="POST" id="form-purge-revisions">
+ ${revision_list(c.deleted_revisions)}
<button
type="submit"
name="purge-revisions"
value="purge"
- class="purge-button"
+ py:attrs=
+ "{'disabled':'disabled','class':'pretty-button'}
+ if c.deleted_revisions.count()==0
+ else {'class':'pretty-button danger'}"
>
Purge them all (forever and irreversibly)
</button>
+ <div class="clear"></div></form>
- ${revision_list(c.deleted_revisions)}
-
- <h2>Deleted Packages</h2>
+ <h3>Deleted Datasets</h3><form method="POST" id="form-purge-packages">
+ ${package_list(c.deleted_packages)}
+ <span py:if="c.deleted_packages.count()==0"><em>(None)</em></span><button
type="submit"
name="purge-packages"
value="purge"
- class="purge-button"
+ py:attrs=
+ "{'disabled':'disabled','class':'pretty-button'}
+ if c.deleted_packages.count()==0
+ else {'class':'pretty-button danger'}"
>
Purge them all (forever and irreversibly)
</button>
+ <div class="clear"></div></form>
-
- ${package_list(c.deleted_packages)}
</div><xi:include href="layout.html" />
http://bitbucket.org/okfn/ckan/changeset/7c49a7e0e84c/
changeset: 7c49a7e0e84c
branch: feature-1264-core-admin
user: zephod
date: 2011-10-05 12:45:54
summary: [admin][m]: Refactored look & feel of pages. Fixed purge bug: Purging the latest revision would break the edit page.
affected #: 3 files (-1 bytes)
--- a/ckan/controllers/admin.py Tue Oct 04 20:12:28 2011 +0100
+++ b/ckan/controllers/admin.py Wed Oct 05 11:45:54 2011 +0100
@@ -250,42 +250,47 @@
# purge packages) of form: "this object already exists in the
# session"
msgs = []
- if 'purge-packages' in request.params:
- revs_to_purge = []
- for pkg in c.deleted_packages:
- revisions = [ x[0] for x in pkg.all_related_revisions ]
- # ensure no accidental purging of other(non-deleted) packages
- # initially just avoided purging revisions where
- # non-deleted packages were affected
- # however this lead to confusing outcomes e.g.
- # we succesfully deleted revision in which package was deleted (so package
- # now active again) but no other revisions
- problem = False
- for r in revisions:
- affected_pkgs = set(r.packages).difference(set(c.deleted_packages))
- if affected_pkgs:
- msg = _('Cannot purge package %s as ' + \
- 'associated revision %s includes non-deleted packages %s')
- msg = msg % (pkg.id, r.id, [pkg.id for r in affected_pkgs])
- msgs.append(msg)
- problem = True
- break
- if not problem:
- revs_to_purge += [ r.id for r in revisions ]
- model.Session.remove()
+ if ('purge-packages' in request.params) or ('purge-revisions' in request.params):
+ if 'purge-packages' in request.params:
+ revs_to_purge = []
+ for pkg in c.deleted_packages:
+ revisions = [ x[0] for x in pkg.all_related_revisions ]
+ # ensure no accidental purging of other(non-deleted) packages
+ # initially just avoided purging revisions where
+ # non-deleted packages were affected
+ # however this lead to confusing outcomes e.g.
+ # we succesfully deleted revision in which package was deleted (so package
+ # now active again) but no other revisions
+ problem = False
+ for r in revisions:
+ affected_pkgs = set(r.packages).difference(set(c.deleted_packages))
+ if affected_pkgs:
+ msg = _('Cannot purge package %s as ' + \
+ 'associated revision %s includes non-deleted packages %s')
+ msg = msg % (pkg.id, r.id, [pkg.id for r in affected_pkgs])
+ msgs.append(msg)
+ problem = True
+ break
+ if not problem:
+ revs_to_purge += [ r.id for r in revisions ]
+ model.Session.remove()
+ else:
+ revs_to_purge = [ rev.id for rev in c.deleted_revisions ]
+ revs_to_purge = list(set(revs_to_purge))
+ for id in revs_to_purge:
+ revision = model.Session.query(model.Revision).get(id)
+ try:
+ # TODO deleting the head revision corrupts the edit page
+ # Ensure that whatever 'head' pointer is used gets moved down to the next revision
+ model.repo.purge_revision(revision, leave_record=False)
+ except Exception, inst:
+ msg = 'Problem purging revision %s: %s' % (id,
+ inst)
+ msgs.append(msg)
+ h.flash_success(_('Purge complete'))
else:
- revs_to_purge = [ rev.id for rev in c.deleted_revisions ]
+ msgs.append('Action not implemented.')
- revs_to_purge = list(set(revs_to_purge))
- for id in revs_to_purge:
- revision = model.Session.query(model.Revision).get(id)
- try:
- model.repo.purge_revision(revision, leave_record=False)
- except Exception, inst:
- msg = 'Problem purging revision %s: %s' % (id,
- inst)
- msgs.append(msg)
- h.flash_success(_('Purge complete'))
for msg in msgs:
h.flash_error(msg)
h.redirect_to(h.url_for('ckanadmin', action='trash'))
--- a/ckan/model/__init__.py Tue Oct 04 20:12:28 2011 +0100
+++ b/ckan/model/__init__.py Wed Oct 05 11:45:54 2011 +0100
@@ -230,6 +230,8 @@
continue
if 'pending' not in obj.state:
obj.current = True
+ import datetime
+ obj.expired_timestamp = datetime.datetime(9999, 12, 31)
self.session.add(obj)
break
# now delete revision object
--- a/ckan/templates/revision/read.html Tue Oct 04 20:12:28 2011 +0100
+++ b/ckan/templates/revision/read.html Wed Oct 05 11:45:54 2011 +0100
@@ -17,10 +17,10 @@
id=c.revision.id)}"
><py:if test="c.revision.state!='deleted'">
- <button type="submit" name="action" value="delete">Delete</button>
+ <button type="submit" name="action" value="delete" class="pretty-button">Delete</button></py:if><py:if test="c.revision.state=='deleted'">
- <button type="submit" name="action" value="undelete">Undelete</button>
+ <button type="submit" name="action" value="undelete" class="pretty-button">Undelete</button></py:if></form></div>
http://bitbucket.org/okfn/ckan/changeset/274d913ffcf5/
changeset: 274d913ffcf5
branch: feature-1264-core-admin
user: zephod
date: 2011-10-05 15:20:33
summary: [admin][s]: Repaired tests.
affected #: 2 files (-1 bytes)
--- a/ckan/templates/_util.html Wed Oct 05 11:45:54 2011 +0100
+++ b/ckan/templates/_util.html Wed Oct 05 14:20:33 2011 +0100
@@ -387,7 +387,7 @@
</td><td>${revision.message}</td></tr>
- <tr py:if="revisions.count()==0" class="table-empty">
+ <tr py:if="not any(revisions)" class="table-empty"><td colspan="5">(none)</td></tr></table>
--- a/ckan/templates/admin/trash.html Wed Oct 05 11:45:54 2011 +0100
+++ b/ckan/templates/admin/trash.html Wed Oct 05 14:20:33 2011 +0100
@@ -8,15 +8,15 @@
<div py:match="content"><h3>Deleted Revisions</h3>
+ ${revision_list(c.deleted_revisions)}
<form method="POST" id="form-purge-revisions">
- ${revision_list(c.deleted_revisions)}
<button
type="submit"
name="purge-revisions"
value="purge"
py:attrs=
"{'disabled':'disabled','class':'pretty-button'}
- if c.deleted_revisions.count()==0
+ if not any(c.deleted_revisions)
else {'class':'pretty-button danger'}"
>
Purge them all (forever and irreversibly)
@@ -25,16 +25,16 @@
</form><h3>Deleted Datasets</h3>
+ ${package_list(c.deleted_packages)}
+ <span py:if="not any(c.deleted_packages)"><em>(None)</em></span><form method="POST" id="form-purge-packages">
- ${package_list(c.deleted_packages)}
- <span py:if="c.deleted_packages.count()==0"><em>(None)</em></span><button
type="submit"
name="purge-packages"
value="purge"
py:attrs=
"{'disabled':'disabled','class':'pretty-button'}
- if c.deleted_packages.count()==0
+ if not any(c.deleted_packages)
else {'class':'pretty-button danger'}"
>
Purge them all (forever and irreversibly)
http://bitbucket.org/okfn/ckan/changeset/240620ebcf90/
changeset: 240620ebcf90
branch: feature-1264-core-admin
user: zephod
date: 2011-10-05 15:30:32
summary: [admin][s]: Undelete button works. Look and feel improved.
affected #: 2 files (-1 bytes)
--- a/ckan/public/css/style.css Wed Oct 05 14:20:33 2011 +0100
+++ b/ckan/public/css/style.css Wed Oct 05 14:30:32 2011 +0100
@@ -1098,14 +1098,20 @@
/* ==================== */
/* = Multi-form pages = */
/* ==================== */
-body.admin form {
+body.admin form#form-purge-packages,
+body.admin form#form-purge-revisions {
margin-bottom: 30px;
+ text-align: right;
}
-body.admin form button {
- float: right;
+body.admin .actions button {
+ margin: 0;
+}
+body.admin.authz form {
+ margin-bottom: 30px;
}
body.admin.authz form button {
width: 120px;
+ float: right;
}
--- a/ckan/templates/_util.html Wed Oct 05 14:20:33 2011 +0100
+++ b/ckan/templates/_util.html Wed Oct 05 14:30:32 2011 +0100
@@ -366,10 +366,10 @@
id=revision.id)}"
><py:if test="revision.state!='deleted'">
- <button type="submit" name="action" value="delete">Delete</button>
+ <button type="submit" name="action" value="delete" class="pretty-button small">Delete</button></py:if><py:if test="revision.state=='deleted'">
- <button type="submit" name="action" value="undelete">Undelete</button>
+ <button type="submit" name="action" value="undelete" class="pretty-button small">Undelete</button></py:if></form></div>
@@ -419,10 +419,10 @@
id=revision['id'])}"
><py:if test="revision['state']!='deleted'">
- <button type="submit" name="action" value="delete">Delete</button>
+ <button type="submit" name="action" value="delete" class="pretty-button small">Delete</button></py:if><py:if test="revision['state']=='deleted'">
- <button type="submit" name="action" value="undelete">Undelete</button>
+ <button type="submit" name="action" value="undelete" class="pretty-button small">Undelete</button></py:if></form></div>
Repository URL: https://bitbucket.org/okfn/ckan/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
More information about the ckan-changes
mailing list