Mercurial > public > src > rhodecode
changeset 340:920efb8af63d demo
Merge with 8026872a10ee6f218890d64219d8f26e27dce415
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Wed, 30 Jun 2010 17:16:12 +0200 |
parents | 27ef9dd22ca2 (current diff) 8026872a10ee (diff) |
children | 3f50e44b41b4 |
files | pylons_app/controllers/admin.py pylons_app/controllers/admin/repos.py pylons_app/controllers/admin/users.py pylons_app/controllers/permissions.py pylons_app/controllers/repos.py pylons_app/controllers/users.py |
diffstat | 20 files changed, 916 insertions(+), 534 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Tue Jun 29 21:14:21 2010 +0200 +++ b/.hgtags Wed Jun 30 17:16:12 2010 +0200 @@ -1,13 +1,14 @@ -436bee78d81a02835837d11ef1bf6c308b866bb4 v0.1 Stable -3142616771cd4721e5d5c403947674a7cc90ec99 v0.2 Stable -e2600310e0b22f6c0946c5a4ad663f53fedb0dca v0.3 -aa5ef0f1554831500fb0acae0eed19955773105b v0.2 -aa5ef0f1554831500fb0acae0eed19955773105b v0.2 -0000000000000000000000000000000000000000 v0.2 -3142616771cd4721e5d5c403947674a7cc90ec99 v0.2 Stable -0000000000000000000000000000000000000000 v0.2 Stable -0000000000000000000000000000000000000000 v0.2 -3142616771cd4721e5d5c403947674a7cc90ec99 v0.2 -436bee78d81a02835837d11ef1bf6c308b866bb4 v0.1 Stable -0000000000000000000000000000000000000000 v0.1 Stable -436bee78d81a02835837d11ef1bf6c308b866bb4 v0.1 +436bee78d81a02835837d11ef1bf6c308b866bb4 v0.1.0 +3142616771cd4721e5d5c403947674a7cc90ec99 v0.2.0 +3380ca40cdbad1b5d993431d00636b7aa8ba496e v0.6.0 +50a39f923f311da3ac493cde8094d2b41afe4104 v0.6.8 +c097458480a5972dd75d5695b61e855fd0ab371e v0.7.0 +8bdec09436cb7e4a764bd2ba50b84060e30eb34f v0.7.1 +1a18994cdc3bdd156ee93c7c0fb8d94a88f1f640 v0.7.2 +a3a7c3e03b76ee264a828cb1087970bb98bbffcd v0.7.3 +58b46f9194c347641bfc9a26697ef413a4761971 v0.7.4 +710e7a75bb6b8346cee3bd0ddda67592e4790268 v0.7.5 +ca80f8c0056211dad33483a50b913593516d7a6c v0.7.6 +0cf49c29c846fefeb4e1a222e4b1850e9e3eaa62 v0.7.7 +702c7e565c56a49c89414e81f28571c8e5b67408 v0.7.8 +c12f4d19c95065f313eefcd45eac9ef507f5fa55 v0.7.9
--- a/pylons_app/config/routing.py Tue Jun 29 21:14:21 2010 +0200 +++ b/pylons_app/config/routing.py Wed Jun 30 17:16:12 2010 +0200 @@ -32,7 +32,7 @@ return not cr(repo_name, config['base_path']) #REST routes - with map.submapper(path_prefix='/_admin', controller='repos') as m: + with map.submapper(path_prefix='/_admin', controller='pylons_app.controllers.admin.repos:ReposController') as m: m.connect("repos", "/repos", action="create", conditions=dict(method=["POST"])) m.connect("repos", "/repos", @@ -67,11 +67,11 @@ action="delete_perm_user", conditions=dict(method=["DELETE"], function=check_repo)) - map.resource('user', 'users', path_prefix='/_admin') - map.resource('permission', 'permissions', path_prefix='/_admin') + map.resource('user', 'users', controller='pylons_app.controllers.admin.users:UsersController', path_prefix='/_admin') + map.resource('permission', 'permissions', controller='pylons_app.controllers.admin.permissions:PermissionsController', path_prefix='/_admin') #ADMIN - with map.submapper(path_prefix='/_admin', controller='admin') as m: + with map.submapper(path_prefix='/_admin', controller='pylons_app.controllers.admin.admin:AdminController') as m: m.connect('admin_home', '', action='index')#main page m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}', action='add_repo') @@ -84,9 +84,11 @@ controller='feed', action='atom', conditions=dict(function=check_repo)) + #LOGIN/LOGOUT map.connect('login_home', '/login', controller='login') map.connect('logout_home', '/logout', controller='login', action='logout') + #OTHERS map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}', controller='changeset', revision='tip', conditions=dict(function=check_repo)) @@ -115,4 +117,12 @@ map.connect('files_archive_home', '/{repo_name:.*}/archive/{revision}/{fileformat}', controller='files', action='archivefile', revision='tip', conditions=dict(function=check_repo)) + map.connect('repo_settings_update', '/{repo_name:.*}/settings', + controller='settings', action="update", + conditions=dict(method=["PUT"], function=check_repo)) + map.connect('repo_settings_home', '/{repo_name:.*}/settings', + controller='settings', action='index', + conditions=dict(function=check_repo)) + + return map
--- a/pylons_app/controllers/admin.py Tue Jun 29 21:14:21 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# admin controller for pylons -# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; version 2 -# of the License or (at your opinion) any later version of the license. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -""" -Created on April 7, 2010 -admin controller for pylons -@author: marcink -""" -import logging -from pylons import request, response, session, tmpl_context as c -from pylons_app.lib.base import BaseController, render -from pylons_app.model import meta -from pylons_app.model.db import UserLog -from webhelpers.paginate import Page -from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator - -log = logging.getLogger(__name__) - -class AdminController(BaseController): - - @LoginRequired() - def __before__(self): - super(AdminController, self).__before__() - - @HasPermissionAllDecorator('hg.admin') - def index(self): - sa = meta.Session - - users_log = sa.query(UserLog).order_by(UserLog.action_date.desc()) - p = int(request.params.get('page', 1)) - c.users_log = Page(users_log, page=p, items_per_page=10) - c.log_data = render('admin/admin_log.html') - if request.params.get('partial'): - return c.log_data - return render('admin/admin.html') -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pylons_app/controllers/admin/admin.py Wed Jun 30 17:16:12 2010 +0200 @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# encoding: utf-8 +# admin controller for pylons +# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License or (at your opinion) any later version of the license. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +""" +Created on April 7, 2010 +admin controller for pylons +@author: marcink +""" +import logging +from pylons import request, response, session, tmpl_context as c +from pylons_app.lib.base import BaseController, render +from pylons_app.model import meta +from pylons_app.model.db import UserLog +from webhelpers.paginate import Page +from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator + +log = logging.getLogger(__name__) + +class AdminController(BaseController): + + @LoginRequired() + def __before__(self): + super(AdminController, self).__before__() + + @HasPermissionAllDecorator('hg.admin') + def index(self): + sa = meta.Session + + users_log = sa.query(UserLog).order_by(UserLog.action_date.desc()) + p = int(request.params.get('page', 1)) + c.users_log = Page(users_log, page=p, items_per_page=10) + c.log_data = render('admin/admin_log.html') + if request.params.get('partial'): + return c.log_data + return render('admin/admin.html') +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pylons_app/controllers/admin/permissions.py Wed Jun 30 17:16:12 2010 +0200 @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# encoding: utf-8 +# permissions controller for pylons +# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License or (at your opinion) any later version of the license. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +""" +Created on April 27, 2010 +permissions controller for pylons +@author: marcink +""" +from formencode import htmlfill +from pylons import request, session, tmpl_context as c, url +from pylons.controllers.util import abort, redirect +from pylons.i18n.translation import _ +from pylons_app.lib import helpers as h +from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator +from pylons_app.lib.base import BaseController, render +from pylons_app.model.db import User, UserLog +from pylons_app.model.forms import UserForm +from pylons_app.model.user_model import UserModel +import formencode +import logging + +log = logging.getLogger(__name__) + +class PermissionsController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + # To properly map this controller, ensure your config/routing.py + # file has a resource setup: + # map.resource('permission', 'permissions') + + @LoginRequired() + #@HasPermissionAllDecorator('hg.admin') + def __before__(self): + c.admin_user = session.get('admin_user') + c.admin_username = session.get('admin_username') + super(PermissionsController, self).__before__() + + def index(self, format='html'): + """GET /permissions: All items in the collection""" + # url('permissions') + return render('admin/permissions/permissions.html') + + def create(self): + """POST /permissions: Create a new item""" + # url('permissions') + + def new(self, format='html'): + """GET /permissions/new: Form to create a new item""" + # url('new_permission') + + def update(self, id): + """PUT /permissions/id: Update an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="PUT" /> + # Or using helpers: + # h.form(url('permission', id=ID), + # method='put') + # url('permission', id=ID) + + def delete(self, id): + """DELETE /permissions/id: Delete an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="DELETE" /> + # Or using helpers: + # h.form(url('permission', id=ID), + # method='delete') + # url('permission', id=ID) + + def show(self, id, format='html'): + """GET /permissions/id: Show a specific item""" + # url('permission', id=ID) + + def edit(self, id, format='html'): + """GET /permissions/id/edit: Form to edit an existing item""" + # url('edit_permission', id=ID)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pylons_app/controllers/admin/repos.py Wed Jun 30 17:16:12 2010 +0200 @@ -0,0 +1,201 @@ +#!/usr/bin/env python +# encoding: utf-8 +# repos controller for pylons +# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License or (at your opinion) any later version of the license. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +""" +Created on April 7, 2010 +admin controller for pylons +@author: marcink +""" +from formencode import htmlfill +from operator import itemgetter +from pylons import request, response, session, tmpl_context as c, url +from pylons.controllers.util import abort, redirect +from pylons.i18n.translation import _ +from pylons_app.lib import helpers as h +from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator +from pylons_app.lib.base import BaseController, render +from pylons_app.lib.utils import invalidate_cache +from pylons_app.model.forms import RepoForm +from pylons_app.model.hg_model import HgModel +from pylons_app.model.repo_model import RepoModel +import formencode +import logging +log = logging.getLogger(__name__) + +class ReposController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + # To properly map this controller, ensure your config/routing.py + # file has a resource setup: + # map.resource('repo', 'repos') + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + def __before__(self): + c.admin_user = session.get('admin_user') + c.admin_username = session.get('admin_username') + super(ReposController, self).__before__() + + def index(self, format='html'): + """GET /repos: All items in the collection""" + # url('repos') + cached_repo_list = HgModel().get_repos() + c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort')) + return render('admin/repos/repos.html') + + def create(self): + """POST /repos: Create a new item""" + # url('repos') + repo_model = RepoModel() + _form = RepoForm()() + try: + form_result = _form.to_python(dict(request.POST)) + repo_model.create(form_result, c.hg_app_user) + invalidate_cache('cached_repo_list') + h.flash(_('created repository %s') % form_result['repo_name'], + category='success') + + except formencode.Invalid as errors: + c.form_errors = errors.error_dict + c.new_repo = errors.value['repo_name'] + return htmlfill.render( + render('admin/repos/repo_add.html'), + defaults=errors.value, + encoding="UTF-8") + + except Exception: + h.flash(_('error occured during creation of repository %s') \ + % form_result['repo_name'], category='error') + + return redirect('repos') + + def new(self, format='html'): + """GET /repos/new: Form to create a new item""" + new_repo = request.GET.get('repo', '') + c.new_repo = h.repo_name_slug(new_repo) + + return render('admin/repos/repo_add.html') + + def update(self, repo_name): + """PUT /repos/repo_name: Update an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="PUT" /> + # Or using helpers: + # h.form(url('repo', repo_name=ID), + # method='put') + # url('repo', repo_name=ID) + repo_model = RepoModel() + _form = RepoForm(edit=True)() + try: + form_result = _form.to_python(dict(request.POST)) + repo_model.update(repo_name, form_result) + invalidate_cache('cached_repo_list') + h.flash(_('Repository %s updated succesfully' % repo_name), + category='success') + + except formencode.Invalid as errors: + c.repo_info = repo_model.get(repo_name) + c.users_array = repo_model.get_users_js() + errors.value.update({'user':c.repo_info.user.username}) + c.form_errors = errors.error_dict + return htmlfill.render( + render('admin/repos/repo_edit.html'), + defaults=errors.value, + encoding="UTF-8") + except Exception: + h.flash(_('error occured during update of repository %s') \ + % form_result['repo_name'], category='error') + return redirect(url('repos')) + + def delete(self, repo_name): + """DELETE /repos/repo_name: Delete an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="DELETE" /> + # Or using helpers: + # h.form(url('repo', repo_name=ID), + # method='delete') + # url('repo', repo_name=ID) + + h.flash(_('deleted repository %s - disabled for demo :)') + % repo_name, category='success') + return redirect(url('repos')) + + repo_model = RepoModel() + repo = repo_model.get(repo_name) + if not repo: + h.flash(_('%s repository is not mapped to db perhaps' + ' it was moved or renamed from the filesystem' + ' please run the application again' + ' in order to rescan repositories') % repo_name, + category='error') + + return redirect(url('repos')) + try: + repo_model.delete(repo) + invalidate_cache('cached_repo_list') + h.flash(_('deleted repository %s') % repo_name, category='success') + except Exception: + h.flash(_('An error occured during deletion of %s') % repo_name, + category='error') + + return redirect(url('repos')) + + def delete_perm_user(self, repo_name): + """ + DELETE an existing repository permission user + @param repo_name: + """ + + try: + repo_model = RepoModel() + repo_model.delete_perm_user(request.POST, repo_name) + except Exception as e: + h.flash(_('An error occured during deletion of repository user'), + category='error') + + + def show(self, repo_name, format='html'): + """GET /repos/repo_name: Show a specific item""" + # url('repo', repo_name=ID) + + def edit(self, repo_name, format='html'): + """GET /repos/repo_name/edit: Form to edit an existing item""" + # url('edit_repo', repo_name=ID) + repo_model = RepoModel() + c.repo_info = repo = repo_model.get(repo_name) + if not repo: + h.flash(_('%s repository is not mapped to db perhaps' + ' it was created or renamed from the filesystem' + ' please run the application again' + ' in order to rescan repositories') % repo_name, + category='error') + + return redirect(url('repos')) + defaults = c.repo_info.__dict__ + defaults.update({'user':c.repo_info.user.username}) + c.users_array = repo_model.get_users_js() + + for p in c.repo_info.repo2perm: + defaults.update({'perm_%s' % p.user.username: + p.permission.permission_name}) + + return htmlfill.render( + render('admin/repos/repo_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pylons_app/controllers/admin/users.py Wed Jun 30 17:16:12 2010 +0200 @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# encoding: utf-8 +# users controller for pylons +# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License or (at your opinion) any later version of the license. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +""" +Created on April 4, 2010 +users controller for pylons +@author: marcink +""" +from formencode import htmlfill +from pylons import request, session, tmpl_context as c, url +from pylons.controllers.util import abort, redirect +from pylons.i18n.translation import _ +from pylons_app.lib import helpers as h +from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator +from pylons_app.lib.base import BaseController, render +from pylons_app.model.db import User, UserLog +from pylons_app.model.forms import UserForm +from pylons_app.model.user_model import UserModel, DefaultUserException +import formencode +import logging + +log = logging.getLogger(__name__) + +class UsersController(BaseController): + """REST Controller styled on the Atom Publishing Protocol""" + # To properly map this controller, ensure your config/routing.py + # file has a resource setup: + # map.resource('user', 'users') + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + def __before__(self): + c.admin_user = session.get('admin_user') + c.admin_username = session.get('admin_username') + super(UsersController, self).__before__() + + + def index(self, format='html'): + """GET /users: All items in the collection""" + # url('users') + + c.users_list = self.sa.query(User).all() + return render('admin/users/users.html') + + def create(self): + """POST /users: Create a new item""" + # url('users') + + user_model = UserModel() + login_form = UserForm()() + try: + form_result = login_form.to_python(dict(request.POST)) + user_model.create(form_result) + h.flash(_('created user %s') % form_result['username'], + category='success') + except formencode.Invalid as errors: + c.form_errors = errors.error_dict + return htmlfill.render( + render('admin/users/user_add.html'), + defaults=errors.value, + encoding="UTF-8") + except Exception: + h.flash(_('error occured during creation of user %s') \ + % form_result['username'], category='error') + return redirect(url('users')) + + def new(self, format='html'): + """GET /users/new: Form to create a new item""" + # url('new_user') + return render('admin/users/user_add.html') + + def update(self, id): + """PUT /users/id: Update an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="PUT" /> + # Or using helpers: + # h.form(url('user', id=ID), + # method='put') + # url('user', id=ID) + user_model = UserModel() + _form = UserForm(edit=True)() + try: + form_result = _form.to_python(dict(request.POST)) + user_model.update(id, form_result) + h.flash(_('User updated succesfully'), category='success') + + except formencode.Invalid as errors: + c.user = user_model.get_user(id) + c.form_errors = errors.error_dict + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=errors.value, + encoding="UTF-8") + except Exception: + h.flash(_('error occured during update of user %s') \ + % form_result['username'], category='error') + + return redirect(url('users')) + + def delete(self, id): + """DELETE /users/id: Delete an existing item""" + # Forms posted to this method should contain a hidden field: + # <input type="hidden" name="_method" value="DELETE" /> + # Or using helpers: + # h.form(url('user', id=ID), + # method='delete') + # url('user', id=ID) + h.flash(_('sucessfully deleted user - disabled for demo :)'), category='success') + return redirect(url('users')) + user_model = UserModel() + try: + user_model.delete(id) + h.flash(_('sucessfully deleted user'), category='success') + except DefaultUserException as e: + h.flash(str(e), category='warning') + except Exception: + h.flash(_('An error occured during deletion of user'), + category='error') + return redirect(url('users')) + + def show(self, id, format='html'): + """GET /users/id: Show a specific item""" + # url('user', id=ID) + + + def edit(self, id, format='html'): + """GET /users/id/edit: Form to edit an existing item""" + # url('edit_user', id=ID) + c.user = self.sa.query(User).get(id) + if c.user.username == 'default': + h.flash(_("You can't edit this user since it's" + " crucial for entire application"), category='warning') + return redirect(url('users')) + + defaults = c.user.__dict__ + return htmlfill.render( + render('admin/users/user_edit.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + )
--- a/pylons_app/controllers/changelog.py Tue Jun 29 21:14:21 2010 +0200 +++ b/pylons_app/controllers/changelog.py Wed Jun 30 17:16:12 2010 +0200 @@ -72,7 +72,7 @@ if not repo.revisions:return dumps([]), 0 max_rev = repo.revisions[-1] - offset = 1 if p == 1 else ((p - 1) * revcount) + offset = 1 if p == 1 else ((p - 1) * revcount + 1) rev_start = repo.revisions[(-1 * offset)] revcount = min(max_rev, revcount)
--- a/pylons_app/controllers/permissions.py Tue Jun 29 21:14:21 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# permissions controller for pylons -# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; version 2 -# of the License or (at your opinion) any later version of the license. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -""" -Created on April 27, 2010 -permissions controller for pylons -@author: marcink -""" -from formencode import htmlfill -from pylons import request, session, tmpl_context as c, url -from pylons.controllers.util import abort, redirect -from pylons.i18n.translation import _ -from pylons_app.lib import helpers as h -from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator -from pylons_app.lib.base import BaseController, render -from pylons_app.model.db import User, UserLog -from pylons_app.model.forms import UserForm -from pylons_app.model.user_model import UserModel -import formencode -import logging - -log = logging.getLogger(__name__) - -class PermissionsController(BaseController): - """REST Controller styled on the Atom Publishing Protocol""" - # To properly map this controller, ensure your config/routing.py - # file has a resource setup: - # map.resource('permission', 'permissions') - - @LoginRequired() - #@HasPermissionAllDecorator('hg.admin') - def __before__(self): - c.admin_user = session.get('admin_user') - c.admin_username = session.get('admin_username') - super(PermissionsController, self).__before__() - - def index(self, format='html'): - """GET /permissions: All items in the collection""" - # url('permissions') - return render('admin/permissions/permissions.html') - - def create(self): - """POST /permissions: Create a new item""" - # url('permissions') - - def new(self, format='html'): - """GET /permissions/new: Form to create a new item""" - # url('new_permission') - - def update(self, id): - """PUT /permissions/id: Update an existing item""" - # Forms posted to this method should contain a hidden field: - # <input type="hidden" name="_method" value="PUT" /> - # Or using helpers: - # h.form(url('permission', id=ID), - # method='put') - # url('permission', id=ID) - - def delete(self, id): - """DELETE /permissions/id: Delete an existing item""" - # Forms posted to this method should contain a hidden field: - # <input type="hidden" name="_method" value="DELETE" /> - # Or using helpers: - # h.form(url('permission', id=ID), - # method='delete') - # url('permission', id=ID) - - def show(self, id, format='html'): - """GET /permissions/id: Show a specific item""" - # url('permission', id=ID) - - def edit(self, id, format='html'): - """GET /permissions/id/edit: Form to edit an existing item""" - # url('edit_permission', id=ID)
--- a/pylons_app/controllers/repos.py Tue Jun 29 21:14:21 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# repos controller for pylons -# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; version 2 -# of the License or (at your opinion) any later version of the license. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -""" -Created on April 7, 2010 -admin controller for pylons -@author: marcink -""" -from formencode import htmlfill -from operator import itemgetter -from pylons import request, response, session, tmpl_context as c, url -from pylons.controllers.util import abort, redirect -from pylons.i18n.translation import _ -from pylons_app.lib import helpers as h -from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator -from pylons_app.lib.base import BaseController, render -from pylons_app.lib.utils import invalidate_cache -from pylons_app.model.forms import RepoForm -from pylons_app.model.hg_model import HgModel -from pylons_app.model.repo_model import RepoModel -import formencode -import logging -log = logging.getLogger(__name__) - -class ReposController(BaseController): - """REST Controller styled on the Atom Publishing Protocol""" - # To properly map this controller, ensure your config/routing.py - # file has a resource setup: - # map.resource('repo', 'repos') - - @LoginRequired() - @HasPermissionAllDecorator('hg.admin') - def __before__(self): - c.admin_user = session.get('admin_user') - c.admin_username = session.get('admin_username') - super(ReposController, self).__before__() - - def index(self, format='html'): - """GET /repos: All items in the collection""" - # url('repos') - cached_repo_list = HgModel().get_repos() - c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort')) - return render('admin/repos/repos.html') - - def create(self): - """POST /repos: Create a new item""" - # url('repos') - repo_model = RepoModel() - _form = RepoForm()() - try: - form_result = _form.to_python(dict(request.POST)) - repo_model.create(form_result, c.hg_app_user) - invalidate_cache('cached_repo_list') - h.flash(_('created repository %s') % form_result['repo_name'], - category='success') - - except formencode.Invalid as errors: - c.form_errors = errors.error_dict - c.new_repo = errors.value['repo_name'] - return htmlfill.render( - render('admin/repos/repo_add.html'), - defaults=errors.value, - encoding="UTF-8") - - except Exception: - h.flash(_('error occured during creation of repository %s') \ - % form_result['repo_name'], category='error') - - return redirect('repos') - - def new(self, format='html'): - """GET /repos/new: Form to create a new item""" - new_repo = request.GET.get('repo', '') - c.new_repo = h.repo_name_slug(new_repo) - - return render('admin/repos/repo_add.html') - - def update(self, repo_name): - """PUT /repos/repo_name: Update an existing item""" - # Forms posted to this method should contain a hidden field: - # <input type="hidden" name="_method" value="PUT" /> - # Or using helpers: - # h.form(url('repo', repo_name=ID), - # method='put') - # url('repo', repo_name=ID) - repo_model = RepoModel() - _form = RepoForm(edit=True)() - try: - form_result = _form.to_python(dict(request.POST)) - repo_model.update(repo_name, form_result) - invalidate_cache('cached_repo_list') - h.flash(_('Repository %s updated succesfully' % repo_name), - category='success') - - except formencode.Invalid as errors: - c.repo_info = repo_model.get(repo_name) - c.users_array = repo_model.get_users_js() - errors.value.update({'user':c.repo_info.user.username}) - c.form_errors = errors.error_dict - return htmlfill.render( - render('admin/repos/repo_edit.html'), - defaults=errors.value, - encoding="UTF-8") - except Exception: - h.flash(_('error occured during update of repository %s') \ - % form_result['repo_name'], category='error') - return redirect(url('repos')) - - def delete(self, repo_name): - """DELETE /repos/repo_name: Delete an existing item""" - # Forms posted to this method should contain a hidden field: - # <input type="hidden" name="_method" value="DELETE" /> - # Or using helpers: - # h.form(url('repo', repo_name=ID), - # method='delete') - # url('repo', repo_name=ID) - - h.flash(_('deleted repository %s - disabled for demo :)') - % repo_name, category='success') - return redirect(url('repos')) - - repo_model = RepoModel() - repo = repo_model.get(repo_name) - if not repo: - h.flash(_('%s repository is not mapped to db perhaps' - ' it was moved or renamed from the filesystem' - ' please run the application again' - ' in order to rescan repositories') % repo_name, - category='error') - - return redirect(url('repos')) - try: - repo_model.delete(repo) - invalidate_cache('cached_repo_list') - h.flash(_('deleted repository %s') % repo_name, category='success') - except Exception: - h.flash(_('An error occured during deletion of %s') % repo_name, - category='error') - - return redirect(url('repos')) - - def delete_perm_user(self, repo_name): - """ - DELETE an existing repository permission user - @param repo_name: - """ - - try: - repo_model = RepoModel() - repo_model.delete_perm_user(request.POST, repo_name) - except Exception as e: - h.flash(_('An error occured during deletion of repository user'), - category='error') - - - def show(self, repo_name, format='html'): - """GET /repos/repo_name: Show a specific item""" - # url('repo', repo_name=ID) - - def edit(self, repo_name, format='html'): - """GET /repos/repo_name/edit: Form to edit an existing item""" - # url('edit_repo', repo_name=ID) - repo_model = RepoModel() - c.repo_info = repo = repo_model.get(repo_name) - if not repo: - h.flash(_('%s repository is not mapped to db perhaps' - ' it was created or renamed from the filesystem' - ' please run the application again' - ' in order to rescan repositories') % repo_name, - category='error') - - return redirect(url('repos')) - defaults = c.repo_info.__dict__ - defaults.update({'user':c.repo_info.user.username}) - c.users_array = repo_model.get_users_js() - - for p in c.repo_info.repo2perm: - defaults.update({'perm_%s' % p.user.username: - p.permission.permission_name}) - - return htmlfill.render( - render('admin/repos/repo_edit.html'), - defaults=defaults, - encoding="UTF-8", - force_defaults=False - )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pylons_app/controllers/settings.py Wed Jun 30 17:16:12 2010 +0200 @@ -0,0 +1,97 @@ +#!/usr/bin/env python +# encoding: utf-8 +# settings controller for pylons +# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License or (at your opinion) any later version of the license. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +""" +Created on June 30, 2010 +settings controller for pylons +@author: marcink +""" +from formencode import htmlfill +from pylons import tmpl_context as c, request, url +from pylons.controllers.util import redirect +from pylons.i18n.translation import _ +from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAllDecorator +from pylons_app.lib.base import BaseController, render +from pylons_app.lib.utils import invalidate_cache +from pylons_app.model.forms import RepoSettingsForm +from pylons_app.model.repo_model import RepoModel +import formencode +import logging +import pylons_app.lib.helpers as h +log = logging.getLogger(__name__) + +class SettingsController(BaseController): + + @LoginRequired() + @HasRepoPermissionAllDecorator('repository.admin') + def __before__(self): + super(SettingsController, self).__before__() + + def index(self, repo_name): + repo_model = RepoModel() + c.repo_info = repo = repo_model.get(repo_name) + if not repo: + h.flash(_('%s repository is not mapped to db perhaps' + ' it was created or renamed from the filesystem' + ' please run the application again' + ' in order to rescan repositories') % repo_name, + category='error') + + return redirect(url('repos')) + defaults = c.repo_info.__dict__ + defaults.update({'user':c.repo_info.user.username}) + c.users_array = repo_model.get_users_js() + + for p in c.repo_info.repo2perm: + defaults.update({'perm_%s' % p.user.username: + p.permission.permission_name}) + + return htmlfill.render( + render('settings/repo_settings.html'), + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + + def update(self, repo_name): + print request.POST + print 'x' * 110 + repo_model = RepoModel() + _form = RepoSettingsForm(edit=True)() + try: + form_result = _form.to_python(dict(request.POST)) + repo_model.update(repo_name, form_result) + invalidate_cache('cached_repo_list') + h.flash(_('Repository %s updated succesfully' % repo_name), + category='success') + + except formencode.Invalid as errors: + c.repo_info = repo_model.get(repo_name) + c.users_array = repo_model.get_users_js() + errors.value.update({'user':c.repo_info.user.username}) + c.form_errors = errors.error_dict + return htmlfill.render( + render('admin/repos/repo_edit.html'), + defaults=errors.value, + encoding="UTF-8") + except Exception: + h.flash(_('error occured during update of repository %s') \ + % form_result['repo_name'], category='error') + + return redirect(url('repo_settings_home', repo_name=repo_name))
--- a/pylons_app/controllers/users.py Tue Jun 29 21:14:21 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -# users controller for pylons -# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; version 2 -# of the License or (at your opinion) any later version of the license. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -""" -Created on April 4, 2010 -users controller for pylons -@author: marcink -""" -from formencode import htmlfill -from pylons import request, session, tmpl_context as c, url -from pylons.controllers.util import abort, redirect -from pylons.i18n.translation import _ -from pylons_app.lib import helpers as h -from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator -from pylons_app.lib.base import BaseController, render -from pylons_app.model.db import User, UserLog -from pylons_app.model.forms import UserForm -from pylons_app.model.user_model import UserModel, DefaultUserException -import formencode -import logging - -log = logging.getLogger(__name__) - -class UsersController(BaseController): - """REST Controller styled on the Atom Publishing Protocol""" - # To properly map this controller, ensure your config/routing.py - # file has a resource setup: - # map.resource('user', 'users') - - @LoginRequired() - @HasPermissionAllDecorator('hg.admin') - def __before__(self): - c.admin_user = session.get('admin_user') - c.admin_username = session.get('admin_username') - super(UsersController, self).__before__() - - - def index(self, format='html'): - """GET /users: All items in the collection""" - # url('users') - - c.users_list = self.sa.query(User).all() - return render('admin/users/users.html') - - def create(self): - """POST /users: Create a new item""" - # url('users') - - user_model = UserModel() - login_form = UserForm()() - try: - form_result = login_form.to_python(dict(request.POST)) - user_model.create(form_result) - h.flash(_('created user %s') % form_result['username'], - category='success') - except formencode.Invalid as errors: - c.form_errors = errors.error_dict - return htmlfill.render( - render('admin/users/user_add.html'), - defaults=errors.value, - encoding="UTF-8") - except Exception: - h.flash(_('error occured during creation of user %s') \ - % form_result['username'], category='error') - return redirect(url('users')) - - def new(self, format='html'): - """GET /users/new: Form to create a new item""" - # url('new_user') - return render('admin/users/user_add.html') - - def update(self, id): - """PUT /users/id: Update an existing item""" - # Forms posted to this method should contain a hidden field: - # <input type="hidden" name="_method" value="PUT" /> - # Or using helpers: - # h.form(url('user', id=ID), - # method='put') - # url('user', id=ID) - user_model = UserModel() - _form = UserForm(edit=True)() - try: - form_result = _form.to_python(dict(request.POST)) - user_model.update(id, form_result) - h.flash(_('User updated succesfully'), category='success') - - except formencode.Invalid as errors: - c.user = user_model.get_user(id) - c.form_errors = errors.error_dict - return htmlfill.render( - render('admin/users/user_edit.html'), - defaults=errors.value, - encoding="UTF-8") - except Exception: - h.flash(_('error occured during update of user %s') \ - % form_result['username'], category='error') - - return redirect(url('users')) - - def delete(self, id): - """DELETE /users/id: Delete an existing item""" - # Forms posted to this method should contain a hidden field: - # <input type="hidden" name="_method" value="DELETE" /> - # Or using helpers: - # h.form(url('user', id=ID), - # method='delete') - # url('user', id=ID) - h.flash(_('sucessfully deleted user - disabled for demo :)'), category='success') - return redirect(url('users')) - user_model = UserModel() - try: - user_model.delete(id) - h.flash(_('sucessfully deleted user'), category='success') - except DefaultUserException as e: - h.flash(str(e), category='warning') - except Exception: - h.flash(_('An error occured during deletion of user'), - category='error') - return redirect(url('users')) - - def show(self, id, format='html'): - """GET /users/id: Show a specific item""" - # url('user', id=ID) - - - def edit(self, id, format='html'): - """GET /users/id/edit: Form to edit an existing item""" - # url('edit_user', id=ID) - c.user = self.sa.query(User).get(id) - if c.user.username == 'default': - h.flash(_("You can't edit this user since it's" - " crucial for entire application"), category='warning') - return redirect(url('users')) - - defaults = c.user.__dict__ - return htmlfill.render( - render('admin/users/user_edit.html'), - defaults=defaults, - encoding="UTF-8", - force_defaults=False - )
--- a/pylons_app/model/forms.py Tue Jun 29 21:14:21 2010 +0200 +++ b/pylons_app/model/forms.py Wed Jun 30 17:16:12 2010 +0200 @@ -182,7 +182,15 @@ state=State_obj) raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg}) return value - + +class ValidSettings(formencode.validators.FancyValidator): + + def to_python(self, value, state): + #settings form can't edit user + if value.has_key('user'): + del['value']['user'] + + return value #=============================================================================== # FORMS #=============================================================================== @@ -240,3 +248,18 @@ chained_validators = [ValidPerms] return _RepoForm + +def RepoSettingsForm(edit=False): + class _RepoForm(formencode.Schema): + allow_extra_fields = True + filter_extra_fields = False + repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit)) + description = UnicodeString(strip=True, min=3, not_empty=True) + private = StringBoolean(if_missing=False) + + chained_validators = [ValidPerms, ValidSettings] + return _RepoForm + + + +
--- a/pylons_app/public/css/monoblue_custom.css Tue Jun 29 21:14:21 2010 +0200 +++ b/pylons_app/public/css/monoblue_custom.css Wed Jun 30 17:16:12 2010 +0200 @@ -742,9 +742,6 @@ } /** end of changeset **/ /** canvas **/ -#graph_nodes { - margin-top: 8px; -} #graph { overflow: hidden; @@ -753,6 +750,8 @@ #graph_nodes { width: 160px; float: left; + margin-left:-50px; + margin-top: 5px; } #graph_content { @@ -774,7 +773,8 @@ border-bottom: 1px solid #CCCCCC; border-left: 1px solid #CCCCCC; border-right: 1px solid #CCCCCC; - height: 120px; + min-height: 80px; + overflow: hidden; } #graph_content .container .left {
--- a/pylons_app/public/js/graph.js Tue Jun 29 21:14:21 2010 +0200 +++ b/pylons_app/public/js/graph.js Wed Jun 30 17:16:12 2010 +0200 @@ -1,5 +1,6 @@ // branch_renderer.js - Rendering of branch DAGs on the client side // +// Copyright 2010 Marcin Kuzminski <marcin AT python-works DOT com> // Copyright 2008 Jesper Noehr <jesper AT noehr DOT org> // Copyright 2008 Dirkjan Ochtman <dirkjan AT ochtman DOT nl> // Copyright 2006 Alexander Schremmer <alex AT alexanderweb DOT de> @@ -32,7 +33,8 @@ this.ctx.fillStyle = 'rgb(0, 0, 0)'; this.cur = [0, 0]; this.max_column = 1; - this.line_width = 3; + this.line_width = 2.5; + this.dot_radius = 5.5; this.bg = [0, 4]; this.cell = [2, 0]; this.revlink = ''; @@ -60,7 +62,7 @@ var idx = 1; var rela = document.getElementById('graph'); var pad = 160; - var scale = 20; + var scale = 22; for (var i in data) { this.scale(scale); @@ -102,20 +104,21 @@ y = row.offsetTop-rela.offsetTop+4; x = pad-((this.cell[0] + this.box_size * start - 1) + this.bg_height-2); + this.ctx.lineWidth=this.line_width; this.ctx.beginPath(); this.ctx.moveTo(x, y); //i don't know why it's +1 just fixes some drawing graph. y += row.clientHeight+1; x = pad-((1 + this.box_size * end) + this.bg_height-2); - this.ctx.lineTo(x,y+extra); + this.ctx.lineTo(x,y+extra,3); this.ctx.stroke(); } column = node[0] color = node[1] - radius = 4; + radius = this.dot_radius; y = row.offsetTop-rela.offsetTop+4; x = pad-(Math.round(this.cell[0] * scale/2 * column + radius) + 15 - (column*4));
--- a/pylons_app/templates/base/base.html Tue Jun 29 21:14:21 2010 +0200 +++ b/pylons_app/templates/base/base.html Wed Jun 30 17:16:12 2010 +0200 @@ -107,7 +107,7 @@ <li ${is_current('tags')}>${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name))}</li> <li ${is_current('files')}>${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name))}</li> %if h.HasRepoPermissionAll('repository.admin')(c.repo_name): - <li>${h.link_to(_('settings'),h.url('edit_repo',repo_name=c.repo_name))}</li> + <li ${is_current('settings')}>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name))}</li> %endif </ul> %else:
--- a/pylons_app/templates/changelog/changelog.html Tue Jun 29 21:14:21 2010 +0200 +++ b/pylons_app/templates/changelog/changelog.html Wed Jun 30 17:16:12 2010 +0200 @@ -42,17 +42,17 @@ <div id="chg_${cnt+1}" class="container"> <div class="left"> <div class="date">${_('commit')} ${cs.revision}: ${cs.raw_id}@${cs.date}</div> + <span class="logtags"> + <span class="branchtag">${cs.branch}</span> + %for tag in cs.tags: + <span class="tagtag">${tag}</span> + %endfor + </span> <div class="author">${cs.author}</div> <div class="message"> ${h.link_to(h.wrap_paragraphs(cs.message), h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))} </div> - <span class="logtags"> - <span class="branchtag">${cs.branch}</span> - %for tag in cs.tags: - <span class="tagtag">${tag}</span> - %endfor - </span> </div> <div class="right"> <div class="changes">
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pylons_app/templates/settings/repo_settings.html Wed Jun 30 17:16:12 2010 +0200 @@ -0,0 +1,240 @@ +## -*- coding: utf-8 -*- +<%inherit file="/base/base.html"/> + +<%def name="title()"> + ${_('Repository settings')} +</%def> +<%def name="breadcrumbs()"> + ${h.link_to(u'Home',h.url('/'))} + / + ${h.link_to(c.repo_name,h.url('shortlog_home',repo_name=c.repo_name))} + / + ${_('settings')} +</%def> +<%def name="page_nav()"> + ${self.menu('settings')} +</%def> +<%def name="main()"> + <h2 class="no-link no-border">${_('Settings')}</h2> + <div> + ${h.form(url('repo_settings_update', repo_name=c.repo_info.repo_name),method='put')} + <table> + <tr> + <td>${_('Name')}</td> + <td>${h.text('repo_name',size="28")}</td> + <td>${self.get_form_error('repo_name')}</td> + </tr> + <tr> + <td>${_('Description')}</td> + <td>${h.textarea('description',cols=32,rows=5)}</td> + <td>${self.get_form_error('description')}</td> + </tr> + <tr> + <td>${_('Private')}</td> + <td>${h.checkbox('private',value="True")}</td> + <td>${self.get_form_error('private')}</td> + </tr> + <tr> + <td>${_('Permissions')}</td> + <td> + <table> + <tr> + <td>${_('none')}</td> + <td>${_('read')}</td> + <td>${_('write')}</td> + <td>${_('admin')}</td> + <td>${_('user')}</td> + </tr> + + %for r2p in c.repo_info.repo2perm: + %if r2p.user.username =='default' and c.repo_info.private: + <tr> + <td colspan="4"> + <span style="font-size: 0.8em">${_('disabled for private repository')}</span></td> + <td>${r2p.user.username}</td> + </tr> + %else: + <tr id=${id(r2p.user.username)}> + <td>${h.radio('perm_%s' % r2p.user.username,'repository.none')}</td> + <td>${h.radio('perm_%s' % r2p.user.username,'repository.read')}</td> + <td>${h.radio('perm_%s' % r2p.user.username,'repository.write')}</td> + <td>${h.radio('perm_%s' % r2p.user.username,'repository.admin')}</td> + <td>${r2p.user.username}</td> + <td> + %if r2p.user.username !='default': + <span class="delete_icon action_button" onclick="ajaxAction(${r2p.user.user_id},${id(r2p.user.username)})"> + <script type="text/javascript"> + function ajaxAction(user_id,field_id){ + var sUrl = "${h.url('delete_repo_user',repo_name=c.repo_name)}"; + var callback = { success:function(o){ + YAHOO.util.Dom.get(String(field_id)).innerHTML = '<td colspan="6"></td>'; + }}; + var postData = '_method=delete&user_id='+user_id; + var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); + }; + </script> + </span> + %endif + </td> + </tr> + %endif + %endfor + <% + if not hasattr(c,'form_errors'): + d = 'display:none;' + else: + d='' + %> + + <tr id="add_perm_input" style="${d}"> + <td>${h.radio('perm_new_user','repository.none')}</td> + <td>${h.radio('perm_new_user','repository.read')}</td> + <td>${h.radio('perm_new_user','repository.write')}</td> + <td>${h.radio('perm_new_user','repository.admin')}</td> + <td class='ac'> + <div id="perm_ac"> + ${h.text('perm_new_user_name',class_='yui-ac-input')} + <div id="perm_container"></div> + </div> + </td> + <td>${self.get_form_error('perm_new_user_name')}</td> + </tr> + <tr> + <td colspan="4"> + <span id="add_perm" class="add_icon" style="cursor: pointer;"> + ${_('Add another user')} + </span> + </td> + </tr> + </table> + </td> + + </tr> + <tr> + <td></td> + <td>${h.submit('update','update')}</td> + </tr> + + </table> + ${h.end_form()} + <script type="text/javascript"> + YAHOO.util.Event.onDOMReady(function(){ + var D = YAHOO.util.Dom; + YAHOO.util.Event.addListener('add_perm','click',function(){ + D.setStyle('add_perm_input','display',''); + D.setStyle('add_perm','opacity','0.6'); + D.setStyle('add_perm','cursor','default'); + }); + }); + </script> + <script type="text/javascript"> + YAHOO.example.FnMultipleFields = function(){ + var myContacts = ${c.users_array|n} + + // Define a custom search function for the DataSource + var matchNames = function(sQuery) { + // Case insensitive matching + var query = sQuery.toLowerCase(), + contact, + i=0, + l=myContacts.length, + matches = []; + + // Match against each name of each contact + for(; i<l; i++) { + contact = myContacts[i]; + if((contact.fname.toLowerCase().indexOf(query) > -1) || + (contact.lname.toLowerCase().indexOf(query) > -1) || + (contact.nname && (contact.nname.toLowerCase().indexOf(query) > -1))) { + matches[matches.length] = contact; + } + } + + return matches; + }; + + // Use a FunctionDataSource + var oDS = new YAHOO.util.FunctionDataSource(matchNames); + oDS.responseSchema = { + fields: ["id", "fname", "lname", "nname"] + } + + // Instantiate AutoComplete for perms + var oAC_perms = new YAHOO.widget.AutoComplete("perm_new_user_name", "perm_container", oDS); + oAC_perms.useShadow = false; + oAC_perms.resultTypeList = false; + + // Instantiate AutoComplete for owner + var oAC_owner = new YAHOO.widget.AutoComplete("user", "owner_container", oDS); + oAC_owner.useShadow = false; + oAC_owner.resultTypeList = false; + + + // Custom formatter to highlight the matching letters + var custom_formatter = function(oResultData, sQuery, sResultMatch) { + var query = sQuery.toLowerCase(), + fname = oResultData.fname, + lname = oResultData.lname, + nname = oResultData.nname || "", // Guard against null value + query = sQuery.toLowerCase(), + fnameMatchIndex = fname.toLowerCase().indexOf(query), + lnameMatchIndex = lname.toLowerCase().indexOf(query), + nnameMatchIndex = nname.toLowerCase().indexOf(query), + displayfname, displaylname, displaynname; + + if(fnameMatchIndex > -1) { + displayfname = highlightMatch(fname, query, fnameMatchIndex); + } + else { + displayfname = fname; + } + + if(lnameMatchIndex > -1) { + displaylname = highlightMatch(lname, query, lnameMatchIndex); + } + else { + displaylname = lname; + } + + if(nnameMatchIndex > -1) { + displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")"; + } + else { + displaynname = nname ? "(" + nname + ")" : ""; + } + + return displayfname + " " + displaylname + " " + displaynname; + + }; + oAC_perms.formatResult = custom_formatter; + oAC_owner.formatResult = custom_formatter; + + // Helper function for the formatter + var highlightMatch = function(full, snippet, matchindex) { + return full.substring(0, matchindex) + + "<span class='match'>" + + full.substr(matchindex, snippet.length) + + "</span>" + + full.substring(matchindex + snippet.length); + }; + + var myHandler = function(sType, aArgs) { + var myAC = aArgs[0]; // reference back to the AC instance + var elLI = aArgs[1]; // reference to the selected LI element + var oData = aArgs[2]; // object literal of selected item's result data + myAC.getInputEl().value = oData.nname; + }; + + oAC_perms.itemSelectEvent.subscribe(myHandler); + oAC_owner.itemSelectEvent.subscribe(myHandler); + + return { + oDS: oDS, + oAC_perms: oAC_perms, + oAC_owner: oAC_owner, + }; + }(); + + </script> + </div> +</%def>
--- a/pylons_app/templates/shortlog/shortlog.html Tue Jun 29 21:14:21 2010 +0200 +++ b/pylons_app/templates/shortlog/shortlog.html Wed Jun 30 17:16:12 2010 +0200 @@ -1,3 +1,4 @@ +## -*- coding: utf-8 -*- <%inherit file="/base/base.html"/> <%def name="title()">
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pylons_app/tests/functional/test_settings.py Wed Jun 30 17:16:12 2010 +0200 @@ -0,0 +1,7 @@ +from pylons_app.tests import * + +class TestSettingsController(TestController): + + def test_index(self): + response = self.app.get(url(controller='settings', action='index')) + # Test response...