changeset 318:fdf9f6ee5217

Implemented permissions into hg app, secured admin controllers, templates and repository specific controllers
author Marcin Kuzminski <marcin@python-works.com>
date Tue, 29 Jun 2010 20:45:03 +0200
parents c961b78ff0a0
children c12f4d19c950
files pylons_app/controllers/branches.py pylons_app/controllers/changelog.py pylons_app/controllers/changeset.py pylons_app/controllers/files.py pylons_app/controllers/permissions.py pylons_app/controllers/repos.py pylons_app/controllers/shortlog.py pylons_app/controllers/summary.py pylons_app/controllers/tags.py pylons_app/controllers/users.py pylons_app/templates/base/base.html pylons_app/templates/index.html
diffstat 12 files changed, 86 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/pylons_app/controllers/branches.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/branches.py	Tue Jun 29 20:45:03 2010 +0200
@@ -22,17 +22,17 @@
 branches controller for pylons
 @author: marcink
 """
-from pylons import tmpl_context as c
-from pylons_app.lib.auth import LoginRequired
+from pylons import tmpl_context as c, request
+from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from pylons_app.lib.base import BaseController, render
 from pylons_app.model.hg_model import HgModel
 import logging
-
 log = logging.getLogger(__name__)
 
 class BranchesController(BaseController):
     
     @LoginRequired()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin')
     def __before__(self):
         super(BranchesController, self).__before__()
     
@@ -40,7 +40,7 @@
         hg_model = HgModel()
         c.repo_info = hg_model.get_repo(c.repo_name)
         c.repo_branches = {}
-        for name, hash in c.repo_info.branches.items():
-            c.repo_branches[name] = c.repo_info.get_changeset(hash)
+        for name, hash_ in c.repo_info.branches.items():
+            c.repo_branches[name] = c.repo_info.get_changeset(hash_)
                 
         return render('branches/branches.html')
--- a/pylons_app/controllers/changelog.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/changelog.py	Tue Jun 29 20:45:03 2010 +0200
@@ -2,14 +2,6 @@
 # encoding: utf-8
 # changelog controller for pylons
 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-from json import dumps
-from mercurial.graphmod import colored, CHANGESET, revisions as graph_rev
-from pylons import request, session, tmpl_context as c
-from pylons_app.lib.auth import LoginRequired
-from pylons_app.lib.base import BaseController, render
-from pylons_app.model.hg_model import HgModel
-from webhelpers.paginate import Page
-import logging
  
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -30,11 +22,21 @@
 changelog controller for pylons
 @author: marcink
 """
-log = logging.getLogger(__name__)     
+from json import dumps
+from mercurial.graphmod import colored, CHANGESET, revisions as graph_rev
+from pylons import request, session, tmpl_context as c
+from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
+from pylons_app.lib.base import BaseController, render
+from pylons_app.model.hg_model import HgModel
+from webhelpers.paginate import Page
+import logging
+log = logging.getLogger(__name__)
 
 class ChangelogController(BaseController):
     
     @LoginRequired()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
+                                   'repository.admin')    
     def __before__(self):
         super(ChangelogController, self).__before__()
                 
--- a/pylons_app/controllers/changeset.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/changeset.py	Tue Jun 29 20:45:03 2010 +0200
@@ -2,16 +2,6 @@
 # encoding: utf-8
 # changeset controller for pylons
 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-from pylons import tmpl_context as c, url
-from pylons.controllers.util import redirect
-from pylons_app.lib.auth import LoginRequired
-from pylons_app.lib.base import BaseController, render
-from pylons_app.model.hg_model import HgModel
-from vcs.exceptions import RepositoryError
-from vcs.nodes import FileNode
-from vcs.utils import diffs as differ
-import logging
-import traceback
  
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -32,13 +22,24 @@
 changeset controller for pylons
 @author: marcink
 """
-
+from pylons import tmpl_context as c, url, request
+from pylons.controllers.util import redirect
+from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
+from pylons_app.lib.base import BaseController, render
+from pylons_app.model.hg_model import HgModel
+from vcs.exceptions import RepositoryError
+from vcs.nodes import FileNode
+from vcs.utils import diffs as differ
+import logging
+import traceback
 
 log = logging.getLogger(__name__)
 
 class ChangesetController(BaseController):
     
     @LoginRequired()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
+                                   'repository.admin')       
     def __before__(self):
         super(ChangesetController, self).__before__()
         
--- a/pylons_app/controllers/files.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/files.py	Tue Jun 29 20:45:03 2010 +0200
@@ -2,20 +2,7 @@
 # encoding: utf-8
 # files controller for pylons
 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
-from mercurial import archival
-from pylons import request, response, session, tmpl_context as c, url
-from pylons.controllers.util import redirect
-from pylons_app.lib.auth import LoginRequired
-from pylons_app.lib.base import BaseController, render
-from pylons_app.lib.utils import EmptyChangeset
-from pylons_app.model.hg_model import HgModel
-from vcs.exceptions import RepositoryError, ChangesetError
-from vcs.nodes import FileNode
-from vcs.utils import diffs as differ
-import logging
-import pylons_app.lib.helpers as h
-import tempfile
- 
+
 # 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
@@ -35,13 +22,27 @@
 files controller for pylons
 @author: marcink
 """
-
+from mercurial import archival
+from pylons import request, response, session, tmpl_context as c, url
+from pylons.controllers.util import redirect
+from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
+from pylons_app.lib.base import BaseController, render
+from pylons_app.lib.utils import EmptyChangeset, get_repo_slug
+from pylons_app.model.hg_model import HgModel
+from vcs.exceptions import RepositoryError, ChangesetError
+from vcs.nodes import FileNode
+from vcs.utils import diffs as differ
+import logging
+import pylons_app.lib.helpers as h
+import tempfile
         
 log = logging.getLogger(__name__)
 
 class FilesController(BaseController):
     
     @LoginRequired()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
+                                   'repository.admin')       
     def __before__(self):
         super(FilesController, self).__before__()
 
--- a/pylons_app/controllers/permissions.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/permissions.py	Tue Jun 29 20:45:03 2010 +0200
@@ -44,7 +44,7 @@
     #     map.resource('permission', 'permissions')
     
     @LoginRequired()
-    @HasPermissionAllDecorator('hg.admin')
+    #@HasPermissionAllDecorator('hg.admin')
     def __before__(self):
         c.admin_user = session.get('admin_user')
         c.admin_username = session.get('admin_username')
--- a/pylons_app/controllers/repos.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/repos.py	Tue Jun 29 20:45:03 2010 +0200
@@ -21,21 +21,19 @@
 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, \
-    app_globals as g
+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
+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.repo_model import RepoModel
+from pylons_app.model.forms import RepoForm
 from pylons_app.model.hg_model import HgModel
-from pylons_app.model.forms import RepoForm
-from pylons_app.model.meta import Session
+from pylons_app.model.repo_model import RepoModel
 import formencode
-from formencode import htmlfill
 import logging
 log = logging.getLogger(__name__)
 
@@ -44,7 +42,9 @@
     # 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')
@@ -104,7 +104,8 @@
             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')
+            h.flash(_('Repository %s updated succesfully' % repo_name),
+                    category='success')
                            
         except formencode.Invalid as errors:
             c.repo_info = repo_model.get(repo_name)
@@ -135,7 +136,8 @@
             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')
+                      ' in order to rescan repositories') % repo_name,
+                      category='error')
         
             return redirect(url('repos'))
         try:
@@ -175,7 +177,8 @@
             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')
+                      ' in order to rescan repositories') % repo_name,
+                      category='error')
         
             return redirect(url('repos'))        
         defaults = c.repo_info.__dict__
--- a/pylons_app/controllers/shortlog.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/shortlog.py	Tue Jun 29 20:45:03 2010 +0200
@@ -23,17 +23,18 @@
 @author: marcink
 """
 from pylons import tmpl_context as c, request
-from pylons_app.lib.auth import LoginRequired
+from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from pylons_app.lib.base import BaseController, render
 from pylons_app.model.hg_model import HgModel
 from webhelpers.paginate import Page
 import logging
-
 log = logging.getLogger(__name__)
 
 class ShortlogController(BaseController):
     
     @LoginRequired()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
+                                   'repository.admin')       
     def __before__(self):
         super(ShortlogController, self).__before__()
         
--- a/pylons_app/controllers/summary.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/summary.py	Tue Jun 29 20:45:03 2010 +0200
@@ -23,20 +23,21 @@
 @author: marcink
 """
 from pylons import tmpl_context as c, request
-from pylons_app.lib.auth import LoginRequired
+from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from pylons_app.lib.base import BaseController, render
 from pylons_app.model.hg_model import HgModel
 from webhelpers.paginate import Page
 import logging
-
 log = logging.getLogger(__name__)
 
 class SummaryController(BaseController):
     
     @LoginRequired()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
+                                   'repository.admin')           
     def __before__(self):
         super(SummaryController, self).__before__()
-        
+                
     def index(self):
         hg_model = HgModel()
         c.repo_info = hg_model.get_repo(c.repo_name)
--- a/pylons_app/controllers/tags.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/tags.py	Tue Jun 29 20:45:03 2010 +0200
@@ -22,17 +22,17 @@
 tags controller for pylons
 @author: marcink
 """
-from pylons import tmpl_context as c
-from pylons_app.lib.auth import LoginRequired
+from pylons import tmpl_context as c, request
+from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 from pylons_app.lib.base import BaseController, render
 from pylons_app.model.hg_model import HgModel
 import logging
-
 log = logging.getLogger(__name__)
 
 class TagsController(BaseController):
     
     @LoginRequired()
+    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin')       
     def __before__(self):
         super(TagsController, self).__before__()
         
--- a/pylons_app/controllers/users.py	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/controllers/users.py	Tue Jun 29 20:45:03 2010 +0200
@@ -31,7 +31,7 @@
 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
+from pylons_app.model.user_model import UserModel, DefaultUserException
 import formencode
 import logging
 
@@ -125,10 +125,11 @@
         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')
-        
+                    category='error')            
         return redirect(url('users'))
         
     def show(self, id, format='html'):
@@ -140,6 +141,11 @@
         """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'),
--- a/pylons_app/templates/base/base.html	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/templates/base/base.html	Tue Jun 29 20:45:03 2010 +0200
@@ -106,13 +106,17 @@
 	            <li ${is_current('branches')}>${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name))}</li>
 	            <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>
-				<li>${h.link_to(_('settings'),h.url('edit_repo',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>
+				%endif					        
 	        </ul>
 		%else:
 		##Root menu
 			<ul class="page-nav">
 				<li ${is_current('home')}>${h.link_to(_('Home'),h.url('/'))}</li>
-				<li ${is_current('admin')}>${h.link_to(_('Admin'),h.url('admin_home'))}</li>
+				%if h.HasPermissionAll('hg.admin')('access admin main page'):
+					<li ${is_current('admin')}>${h.link_to(_('Admin'),h.url('admin_home'))}</li>
+				%endif
 				<li class="logout">${h.link_to(u'Logout',h.url('logout_home'))}</li>
 			</ul>
 		%endif    
@@ -129,7 +133,7 @@
     <ul class="submenu">
         <li ${is_current('repos')}>${h.link_to(u'repos',h.url('repos'),class_='repos')}</li>
         <li ${is_current('users')}>${h.link_to(u'users',h.url('users'),class_='users')}</li>
-        <li ${is_current('permissions')}>${h.link_to(u'permissions',h.url('permissions'),class_='permissions')}</li>
+        ##comented for now<li ${is_current('permissions')}>${h.link_to(u'permissions',h.url('permissions'),class_='permissions')}</li>
     </ul>
     </div>
     %endif
--- a/pylons_app/templates/index.html	Tue Jun 29 20:43:01 2010 +0200
+++ b/pylons_app/templates/index.html	Tue Jun 29 20:45:03 2010 +0200
@@ -31,6 +31,7 @@
 	    <td>${_('Atom')}</td>
 	  </tr>	
 	%for cnt,repo in enumerate(c.repos_list):
+		%if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(repo['name'],'main page check'):
  		<tr class="parity${cnt%2}">
 		    <td>${h.link_to(repo['name'],
 		    	h.url('summary_home',repo_name=repo['name']))}</td>
@@ -48,6 +49,7 @@
 				<a title="${_('Subscribe to %s atom feed')%repo['name']}"  class="atom_logo" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
 			</td>
 		</tr>
+		%endif
 	%endfor
 	</table>
 </%def>