changeset 265:0e5455fda8fd

Implemented basic repository managment. Implemented repo2db mappings, model, helpers updates and code cleanups
author Marcin Kuzminski <marcin@python-works.com>
date Mon, 07 Jun 2010 00:18:33 +0200
parents 0d68a749db33
children 32d6c955218c
files pylons_app/config/environment.py pylons_app/controllers/repos.py pylons_app/controllers/users.py pylons_app/lib/auth.py pylons_app/lib/helpers.py pylons_app/lib/utils.py pylons_app/model/db.py pylons_app/model/forms.py pylons_app/model/hg_model.py pylons_app/model/repo_model.py pylons_app/model/user_model.py pylons_app/templates/admin/repos/repo_add.html pylons_app/templates/admin/repos/repo_edit.html pylons_app/templates/summary/summary.html
diffstat 14 files changed, 327 insertions(+), 75 deletions(-) [+]
line wrap: on
line diff
--- a/pylons_app/config/environment.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/config/environment.py	Mon Jun 07 00:18:33 2010 +0200
@@ -6,6 +6,7 @@
 from pylons_app.lib.auth import set_available_permissions
 from pylons_app.lib.utils import repo2db_mapper
 from pylons_app.model import init_model
+from pylons_app.model.hg_model import _get_repos_cached_initial
 from sqlalchemy import engine_from_config
 import logging
 import os
@@ -60,7 +61,7 @@
         sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.')
 
     init_model(sa_engine_db1)
-    repo2db_mapper()
+    repo2db_mapper(_get_repos_cached_initial(config['pylons.app_globals']))
     set_available_permissions(config)
     # CONFIGURATION OPTIONS HERE (note: all config options will override
     # any Pylons config options)
--- a/pylons_app/controllers/repos.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/controllers/repos.py	Mon Jun 07 00:18:33 2010 +0200
@@ -2,7 +2,6 @@
 # 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
@@ -22,20 +21,25 @@
 admin controller for pylons
 @author: marcink
 """
-import logging
+from operator import itemgetter
 from pylons import request, response, session, tmpl_context as c, url, \
     app_globals as g
 from pylons.controllers.util import abort, redirect
-from pylons_app.lib.auth import LoginRequired
 from pylons.i18n.translation import _
 from pylons_app.lib import helpers as h
+from pylons_app.lib.auth import LoginRequired
 from pylons_app.lib.base import BaseController, render
-from pylons_app.lib.filters import clean_repo
-from pylons_app.lib.utils import check_repo, invalidate_cache
+from pylons_app.lib.utils import invalidate_cache
+from pylons_app.model.repo_model import RepoModel
 from pylons_app.model.hg_model import HgModel
+from pylons_app.model.forms import RepoForm
+from pylons_app.model.meta import Session
+from datetime import datetime
+import formencode
+from formencode import htmlfill
+import logging
 import os
 import shutil
-from operator import itemgetter
 log = logging.getLogger(__name__)
 
 class ReposController(BaseController):
@@ -59,30 +63,33 @@
     def create(self):
         """POST /repos: Create a new item"""
         # url('repos')
-        name = request.POST.get('name')
-
+        repo_model = RepoModel()
+        _form = RepoForm()()
         try:
-            self._create_repo(name)
-            #clear our cached list for refresh with new repo
+            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') % name, category='success')
-        except Exception as e:
-            log.error(e)
-        
+            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 _create_repo(self, repo_name):        
-        repo_path = os.path.join(g.base_path, repo_name)
-        if check_repo(repo_name, g.base_path):
-            log.info('creating repo %s in %s', repo_name, repo_path)
-            from vcs.backends.hg import MercurialRepository
-            MercurialRepository(repo_path, create=True)
-                        
 
     def new(self, format='html'):
         """GET /repos/new: Form to create a new item"""
         new_repo = request.GET.get('repo', '')
-        c.new_repo = clean_repo(new_repo)
+        c.new_repo = h.repo_name_slug(new_repo)
 
         return render('admin/repos/repo_add.html')
 
@@ -94,7 +101,26 @@
         #    h.form(url('repo', id=ID),
         #           method='put')
         # url('repo', id=ID)
-
+        repo_model = RepoModel()
+        _form = RepoForm(edit=True)()
+        try:
+            form_result = _form.to_python(dict(request.POST))
+            repo_model.update(id, form_result)
+            invalidate_cache('cached_repo_list')
+            h.flash(_('Repository updated succesfully'), category='success')
+                           
+        except formencode.Invalid as errors:
+            c.repo_info = repo_model.get(id)
+            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, id):
         """DELETE /repos/id: Delete an existing item"""
         # Forms posted to this method should contain a hidden field:
@@ -103,19 +129,25 @@
         #    h.form(url('repo', id=ID),
         #           method='delete')
         # url('repo', id=ID)
-        from datetime import datetime
-        path = g.paths[0][1].replace('*', '')
-        rm_path = os.path.join(path, id)
-        log.info("Removing %s", rm_path)
-        shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
-        shutil.move(rm_path, os.path.join(path, 'rm__%s-%s' % (datetime.today(), id)))
+        
+        repo_model = RepoModel()
+        repo = repo_model.get(id)
+        if not repo:
+            h.flash(_('%s repository is not mapped to db perhaps' 
+                      ' it was moved or renamed please run the application again'
+                      ' in order to rescan repositories') % id, category='error')
         
-        #clear our cached list for refresh with new repo
-        invalidate_cache('cached_repo_list')
-        h.flash(_('deleted repository %s') % rm_path, category='success')            
+            return redirect(url('repos'))
+        try:
+            repo_model.delete(repo)            
+            invalidate_cache('cached_repo_list')
+            h.flash(_('deleted repository %s') % id, category='success')
+        except Exception:
+            h.flash(_('An error occured during deletion of %s') % id,
+                    category='error')
+        
         return redirect(url('repos'))
         
-
     def show(self, id, format='html'):
         """GET /repos/id: Show a specific item"""
         # url('repo', id=ID)
@@ -123,5 +155,13 @@
     def edit(self, id, format='html'):
         """GET /repos/id/edit: Form to edit an existing item"""
         # url('edit_repo', id=ID)
-        c.new_repo = id
-        return render('admin/repos/repo_edit.html')
+        repo_model = RepoModel()
+        c.repo_info = repo_model.get(id)
+        defaults = c.repo_info.__dict__
+        defaults.update({'user':c.repo_info.user.username})        
+        return htmlfill.render(
+            render('admin/repos/repo_edit.html'),
+            defaults=defaults,
+            encoding="UTF-8",
+            force_defaults=False
+        )          
--- a/pylons_app/controllers/users.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/controllers/users.py	Mon Jun 07 00:18:33 2010 +0200
@@ -23,7 +23,6 @@
 @author: marcink
 """
 import logging
-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 _
@@ -34,6 +33,7 @@
 from pylons_app.model.forms import UserForm
 from pylons_app.model.user_model import UserModel
 import formencode
+from formencode import htmlfill
 
 log = logging.getLogger(__name__)
 
@@ -65,15 +65,18 @@
         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')
-            return redirect(url('users'))
-                           
+            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"""
@@ -89,12 +92,11 @@
         #           method='put')
         # url('user', id=ID)
         user_model = UserModel()
-        login_form = UserForm(edit=True)()
+        _form = UserForm(edit=True)()
         try:
-            form_result = login_form.to_python(dict(request.POST))
+            form_result = _form.to_python(dict(request.POST))
             user_model.update(id, form_result)
             h.flash(_('User updated succesfully'), category='success')
-            return redirect(url('users'))
                            
         except formencode.Invalid as errors:
             c.user = user_model.get_user(id)
@@ -103,7 +105,12 @@
                  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:
@@ -112,13 +119,14 @@
         #    h.form(url('user', id=ID),
         #           method='delete')
         # url('user', id=ID)
+        user_model = UserModel()
         try:
-            self.sa.delete(self.sa.query(User).get(id))
-            self.sa.commit()
+            user_model.delete(id)
             h.flash(_('sucessfully deleted user'), category='success')
-        except:
-            self.sa.rollback()
-            raise
+        except Exception:
+            h.flash(_('An error occured during deletion of user'),
+                    category='error')
+        
         return redirect(url('users'))
         
     def show(self, id, format='html'):
--- a/pylons_app/lib/auth.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/lib/auth.py	Mon Jun 07 00:18:33 2010 +0200
@@ -65,6 +65,7 @@
     A simple object that handles a mercurial username for authentication
     """
     username = 'None'
+    user_id = None
     is_authenticated = False
     is_admin = False
     permissions = set()
--- a/pylons_app/lib/helpers.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/lib/helpers.py	Mon Jun 07 00:18:33 2010 +0200
@@ -114,11 +114,9 @@
     Return slug of name of repository
     """
     slug = urlify(value)
-    for c in """=[]\;',/~!@#$%^&*()+{}|:""":
+    for c in """=[]\;'"<>,/~!@#$%^&*()+{}|:""":
         slug = slug.replace(c, '-')
-    print slug
     slug = recursive_replace(slug, '-')
-    print slug    
     return slug
     
 files_breadcrumbs = _FilesBreadCrumbs()
--- a/pylons_app/lib/utils.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/lib/utils.py	Mon Jun 07 00:18:33 2010 +0200
@@ -28,6 +28,7 @@
 import logging
 from mercurial import ui, config, hg
 from mercurial.error import RepoError
+from pylons_app.model.db import Repository, User
 log = logging.getLogger(__name__)
 
 
@@ -152,9 +153,28 @@
         return '0' * 12
 
 
-def repo2db_mapper():
+def repo2db_mapper(initial_repo_list):
+    """
+    maps all found repositories into db
     """
-    scann all dirs for .hgdbid
-    if some dir doesn't have one generate one.
-    """
-    pass
+    from pylons_app.model.meta import Session
+    sa = Session()
+    user = sa.query(User).filter(User.admin == True).first()
+    for name, repo in initial_repo_list.items():
+        if not sa.query(Repository).get(name):
+            log.info('%s not found creating default', name)
+            try:
+                
+                new_repo = Repository()
+                new_repo.repo_name = name
+                desc = repo.description if repo.description != 'unknown' else \
+                                            'auto description for %s' % name
+                new_repo.description = desc
+                new_repo.user_id = user.user_id
+                new_repo.private = False
+                sa.add(new_repo)
+                sa.commit()
+            except:
+                sa.rollback()
+                raise
+            
--- a/pylons_app/model/db.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/model/db.py	Mon Jun 07 00:18:33 2010 +0200
@@ -1,11 +1,12 @@
 from pylons_app.model.meta import Base
 from sqlalchemy.orm import relation, backref
 from sqlalchemy import *
+from vcs.utils.lazy import LazyProperty
 
 class User(Base): 
     __tablename__ = 'users'
     __table_args__ = {'useexisting':True}
-    user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
+    user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
     username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
@@ -17,6 +18,10 @@
     
     user_log = relation('UserLog')
     
+    @LazyProperty
+    def full_contact(self):
+        return '%s %s <%s>' % (self.name, self.lastname, self.email)
+        
     def __repr__(self):
         return "<User('%s:%s')>" % (self.user_id, self.username)
       
@@ -24,7 +29,7 @@
     __tablename__ = 'user_logs'
     __table_args__ = {'useexisting':True}
     user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
-    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
+    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
     repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
@@ -33,14 +38,12 @@
 
 class Repository(Base):
     __tablename__ = 'repositories'
-    repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
-    repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
+    repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None, primary_key=True)
+    user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
     private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
-    
+    description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
     user = relation('User')
     
-    
 class Permission(Base):
     __tablename__ = 'permissions'
     __table_args__ = {'useexisting':True}
--- a/pylons_app/model/forms.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/model/forms.py	Mon Jun 07 00:18:33 2010 +0200
@@ -25,8 +25,9 @@
 from pylons import session
 from pylons.i18n.translation import _
 from pylons_app.lib.auth import get_crypt_password
+import pylons_app.lib.helpers as h
 from pylons_app.model import meta
-from pylons_app.model.db import User
+from pylons_app.model.db import User, Repository
 from sqlalchemy.exc import OperationalError
 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
 from webhelpers.pylonslib.secure_form import authentication_token
@@ -93,6 +94,7 @@
                     auth_user.username = username
                     auth_user.is_authenticated = True
                     auth_user.is_admin = user.admin
+                    auth_user.user_id = user.user_id
                     session['hg_app_user'] = auth_user
                     session.save()
                     log.info('user %s is now authenticated', username)
@@ -119,7 +121,30 @@
                                          error_dict=self.e_dict_disable)
             
             
-        
+class ValidRepoUser(formencode.validators.FancyValidator):
+            
+    def to_python(self, value, state):
+        sa = meta.Session
+        try:
+            self.user_db = sa.query(User).filter(User.username == value).one()
+        except Exception:
+            raise formencode.Invalid(_('This username is not valid'),
+                                     value, state)
+        return self.user_db.user_id
+
+def ValidRepoName(edit=False):    
+    class _ValidRepoName(formencode.validators.FancyValidator):
+            
+        def to_python(self, value, state):
+            slug = h.repo_name_slug(value)
+            
+            sa = meta.Session
+            if sa.query(Repository).get(slug) and not edit:
+                raise formencode.Invalid(_('This repository already exists'),
+                                         value, state)
+                        
+            return slug 
+    return _ValidRepoName
 #===============================================================================
 # FORMS        
 #===============================================================================
@@ -163,3 +188,16 @@
         email = Email(not_empty=True)
         
     return _UserForm
+
+def RepoForm(edit=False):
+    class _RepoForm(formencode.Schema):
+        allow_extra_fields = True
+        filter_extra_fields = True
+        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)
+        
+        if edit:
+            user = All(Int(not_empty=True), ValidRepoUser)
+        
+    return _RepoForm
--- a/pylons_app/model/hg_model.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/model/hg_model.py	Mon Jun 07 00:18:33 2010 +0200
@@ -27,8 +27,9 @@
 from beaker.cache import cache_region
 from mercurial import ui
 from mercurial.hgweb.hgwebdir_mod import findrepos
-from pylons import app_globals as g
 from vcs.exceptions import RepositoryError, VCSError
+from pylons_app.model.meta import Session
+from pylons_app.model.db import Repository
 import logging
 import os
 import sys
@@ -40,12 +41,19 @@
     sys.stderr.write('You have to import vcs module')
     raise Exception('Unable to import vcs')
 
+def _get_repos_cached_initial(app_globals):
+    """
+    return cached dict with repos
+    """
+    g = app_globals
+    return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
 
 @cache_region('long_term', 'cached_repo_list')
 def _get_repos_cached():
     """
     return cached dict with repos
     """
+    from pylons import app_globals as g
     return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
 
 @cache_region('long_term', 'full_changelog')
@@ -62,7 +70,6 @@
         """
         Constructor
         """
-        pass
     
     @staticmethod
     def repo_scan(repos_prefix, repos_path, baseui):
@@ -72,6 +79,7 @@
         :param repos_path: path to directory it could take syntax with 
         * or ** for deep recursive displaying repositories
         """
+        sa = Session()
         def check_repo_dir(path):
             """
             Checks the repository
@@ -102,8 +110,13 @@
                     raise RepositoryError('Duplicate repository name %s found in'
                                     ' %s' % (name, path))
                 else:
+                    
                     repos_list[name] = MercurialRepository(path, baseui=baseui)
                     repos_list[name].name = name
+                    dbrepo = sa.query(Repository).get(name)
+                    if dbrepo:
+                        repos_list[name].description = dbrepo.description
+                        repos_list[name].contact = dbrepo.user.full_contact
             except OSError:
                 continue
         return repos_list
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pylons_app/model/repo_model.py	Mon Jun 07 00:18:33 2010 +0200
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# model for handling repositories actions
+# 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 Jun 5, 2010
+model for handling repositories actions
+@author: marcink
+"""
+from pylons_app.model.meta import Session
+from pylons_app.model.db import Repository
+import shutil
+import os
+from datetime import datetime
+from pylons_app.lib.utils import check_repo
+from pylons import app_globals as g
+import logging
+log = logging.getLogger(__name__)
+
+class RepoModel(object):
+    
+    def __init__(self):
+        self.sa = Session()
+    
+    def get(self, id):
+        return self.sa.query(Repository).get(id)
+        
+    
+    def update(self, id, form_data):
+        try:
+            if id != form_data['repo_name']:
+                self.__rename_repo(id, form_data['repo_name'])
+            cur_repo = self.sa.query(Repository).get(id)
+            for k, v in form_data.items():
+                if k == 'user':
+                    cur_repo.user_id = v
+                else:
+                    setattr(cur_repo, k, v)
+                
+            self.sa.add(cur_repo)
+            self.sa.commit()
+        except Exception as e:
+            log.error(e)
+            self.sa.rollback()
+            raise    
+    
+    def create(self, form_data, cur_user):
+        try:
+            new_repo = Repository()
+            for k, v in form_data.items():
+                setattr(new_repo, k, v)
+                
+            new_repo.user_id = cur_user.user_id
+            self.sa.add(new_repo)
+            self.sa.commit()
+            self.__create_repo(form_data['repo_name'])
+        except Exception as e:
+            log.error(e)
+            self.sa.rollback()
+            raise    
+                     
+    def delete(self, repo):
+        try:
+            self.sa.delete(repo)
+            self.sa.commit()
+            self.__delete_repo(repo.repo_name)
+        except Exception as e:
+            log.error(e)
+            self.sa.rollback()
+            raise
+       
+    def __create_repo(self, repo_name):        
+        repo_path = os.path.join(g.base_path, repo_name)
+        if check_repo(repo_name, g.base_path):
+            log.info('creating repo %s in %s', repo_name, repo_path)
+            from vcs.backends.hg import MercurialRepository
+            MercurialRepository(repo_path, create=True)
+
+    def __rename_repo(self, old, new):
+        log.info('renaming repoo from %s to %s', old, new)
+        old_path = os.path.join(g.base_path, old)
+        new_path = os.path.join(g.base_path, new)
+        shutil.move(old_path, new_path)
+    
+    def __delete_repo(self, name):
+        rm_path = os.path.join(g.base_path, name)
+        log.info("Removing %s", rm_path)
+        #disable hg 
+        shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
+        #disable repo
+        shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s-%s' % (datetime.today(), id)))
--- a/pylons_app/model/user_model.py	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/model/user_model.py	Mon Jun 07 00:18:33 2010 +0200
@@ -26,6 +26,8 @@
 
 from pylons_app.model.db import User
 from pylons_app.model.meta import Session
+import logging
+log = logging.getLogger(__name__)
 
 class UserModel(object):
 
@@ -43,7 +45,8 @@
                 
             self.sa.add(new_user)
             self.sa.commit()
-        except:
+        except Exception as e:
+            log.error(e)
             self.sa.rollback()
             raise      
     
@@ -59,6 +62,16 @@
                 
             self.sa.add(new_user)
             self.sa.commit()
-        except:
+        except Exception as e:
+            log.error(e)
             self.sa.rollback()
             raise      
+
+    def delete(self, id):
+        try:
+            self.sa.delete(self.sa.query(User).get(id))
+            self.sa.commit()            
+        except Exception as e:
+            log.error(e)
+            self.sa.rollback()
+            raise        
--- a/pylons_app/templates/admin/repos/repo_add.html	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/templates/admin/repos/repo_add.html	Mon Jun 07 00:18:33 2010 +0200
@@ -20,15 +20,18 @@
         <table>
         	<tr>
         		<td>${_('Name')}</td>
-        		<td>${h.text('name',c.new_repo)}</td>
+        		<td>${h.text('repo_name',c.new_repo)}</td>
+        		<td>${self.get_form_error('repo_name')}</td>
         	</tr>
         	<tr>
         		<td>${_('Description')}</td>
         		<td>${h.textarea('description',cols=23,rows=5)}</td>
+        		<td>${self.get_form_error('description')}</td>
         	</tr>
         	<tr>
         		<td>${_('Private')}</td>
         		<td>${h.checkbox('private')}</td>
+        		<td>${self.get_form_error('private')}</td>
         	</tr>
         	<tr>
         		<td></td>
--- a/pylons_app/templates/admin/repos/repo_edit.html	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/templates/admin/repos/repo_edit.html	Mon Jun 07 00:18:33 2010 +0200
@@ -16,19 +16,27 @@
 <%def name="main()">
 	<div>
         <h2>${_('Repositories')} - ${_('edit')}</h2>
-        ${h.form(url('repo', id=c.new_repo),method='put')}
+        ${h.form(url('repo', id=c.repo_info.repo_name),method='put')}
         <table>
         	<tr>
         		<td>${_('Name')}</td>
-        		<td>${h.text('name',c.new_repo)}</td>
+        		<td>${h.text('repo_name')}</td>
+        		<td>${self.get_form_error('repo_name')}</td>
         	</tr>
         	<tr>
         		<td>${_('Description')}</td>
         		<td>${h.textarea('description',cols=23,rows=5)}</td>
+        		<td>${self.get_form_error('description')}</td>
         	</tr>
         	<tr>
         		<td>${_('Private')}</td>
         		<td>${h.checkbox('private')}</td>
+        		<td>${self.get_form_error('private')}</td>
+        	</tr>
+        	<tr>
+        		<td>${_('Owner')}</td>
+        		<td>${h.text('user')}</td>
+        		<td>${self.get_form_error('user')}</td>
         	</tr>
         	<tr>
         		<td></td>
--- a/pylons_app/templates/summary/summary.html	Sun Jun 06 23:35:21 2010 +0200
+++ b/pylons_app/templates/summary/summary.html	Mon Jun 07 00:18:33 2010 +0200
@@ -70,7 +70,7 @@
 			<td>${cs.author|n,filters.person}</td>
 			<td>r${cs.revision}</td>
 			<td>
-				${h.link_to(truncate(cs.message,60),
+				${h.link_to(h.truncate(cs.message,60),
 				h.url('changeset_home',repo_name=c.repo_name,revision=cs._short),
 				title=cs.message)}
 			</td>