changeset 972:2c8fd84935a4 beta

#56 implemented users groups editing, fixed sqlalchemy relation function into relationship (according to 0.6)
author Marcin Kuzminski <marcin@python-works.com>
date Fri, 28 Jan 2011 18:40:50 +0100
parents c5868406fdb0
children 9be6d46c72d6
files rhodecode/controllers/admin/users_groups.py rhodecode/model/db.py rhodecode/model/forms.py rhodecode/model/users_group.py rhodecode/templates/admin/users_groups/users_group_edit.html
diffstat 5 files changed, 292 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/controllers/admin/users_groups.py	Fri Jan 28 14:49:04 2011 +0100
+++ b/rhodecode/controllers/admin/users_groups.py	Fri Jan 28 18:40:50 2011 +0100
@@ -106,6 +106,41 @@
         #           method='put')
         # url('users_group', id=ID)
 
+
+        users_group_model = UsersGroupModel()
+        c.users_group = users_group_model.get(id)
+        c.group_members = [(x.user_id, x.user.username) for x in
+                           c.users_group.members]
+
+        c.available_members = [(x.user_id, x.username) for x in
+                               self.sa.query(User).all()]
+        users_group_form = UsersGroupForm(edit=True,
+                                          old_data=c.users_group.get_dict(),
+                                          available_members=[str(x[0]) for x
+                                                in c.available_members])()
+
+        try:
+            form_result = users_group_form.to_python(request.POST)
+            users_group_model.update(id, form_result)
+            h.flash(_('updated users group %s') % form_result['users_group_name'],
+                    category='success')
+            #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
+        except formencode.Invalid, errors:
+            return htmlfill.render(
+                render('admin/users_groups/users_group_edit.html'),
+                defaults=errors.value,
+                errors=errors.error_dict or {},
+                prefix_error=False,
+                encoding="UTF-8")
+        except Exception:
+            log.error(traceback.format_exc())
+            h.flash(_('error occurred during update of users group %s') \
+                    % request.POST.get('users_group_name'), category='error')
+
+        return redirect(url('users_groups'))
+
+
+
     def delete(self, id):
         """DELETE /users_groups/id: Delete an existing item"""
         # Forms posted to this method should contain a hidden field:
@@ -122,3 +157,22 @@
     def edit(self, id, format='html'):
         """GET /users_groups/id/edit: Form to edit an existing item"""
         # url('edit_users_group', id=ID)
+
+        c.users_group = self.sa.query(UsersGroup).get(id)
+        if not c.users_group:
+            return redirect(url('users_groups'))
+
+        c.users_group.permissions = {}
+        c.group_members = [(x.user_id, x.user.username) for x in
+                           c.users_group.members]
+        print c.group_members, 'x' * 100
+        c.available_members = [(x.user_id, x.username) for x in
+                               self.sa.query(User).all()]
+        defaults = c.users_group.get_dict()
+
+        return htmlfill.render(
+            render('admin/users_groups/users_group_edit.html'),
+            defaults=defaults,
+            encoding="UTF-8",
+            force_defaults=False
+        )
--- a/rhodecode/model/db.py	Fri Jan 28 14:49:04 2011 +0100
+++ b/rhodecode/model/db.py	Fri Jan 28 18:40:50 2011 +0100
@@ -29,7 +29,7 @@
 
 from sqlalchemy import *
 from sqlalchemy.exc import DatabaseError
-from sqlalchemy.orm import relation, backref, class_mapper
+from sqlalchemy.orm import relationship, backref, class_mapper
 from sqlalchemy.orm.session import Session
 
 from rhodecode.model.meta import Base
@@ -107,11 +107,11 @@
     last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
     is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
 
-    user_log = relation('UserLog', cascade='all')
-    user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
+    user_log = relationship('UserLog', cascade='all')
+    user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
 
-    repositories = relation('Repository')
-    user_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
+    repositories = relationship('Repository')
+    user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
 
     @property
     def full_contact(self):
@@ -150,8 +150,8 @@
     action = Column("action", String(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)
 
-    user = relation('User')
-    repository = relation('Repository')
+    user = relationship('User')
+    repository = relationship('Repository')
 
 
 class UsersGroup(Base, BaseModel):
@@ -162,7 +162,7 @@
     users_group_name = Column("users_group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
     users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
 
-    members = relation('UsersGroupMember')
+    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan")
 
 class UsersGroupMember(Base, BaseModel):
     __tablename__ = 'users_groups_members'
@@ -172,8 +172,12 @@
     users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
-    user = relation('User')
-    users_group = relation('UsersGroup')
+    user = relationship('User')
+    users_group = relationship('UsersGroup')
+
+    def __init__(self, gr_id, u_id):
+        self.users_group_id = gr_id
+        self.user_id = u_id
 
 class Repository(Base, BaseModel):
     __tablename__ = 'repositories'
@@ -189,13 +193,13 @@
     fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
     group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
 
-    user = relation('User')
-    fork = relation('Repository', remote_side=repo_id)
-    group = relation('Group')
-    repo_to_perm = relation('RepoToPerm', cascade='all')
-    stats = relation('Statistics', cascade='all', uselist=False)
+    user = relationship('User')
+    fork = relationship('Repository', remote_side=repo_id)
+    group = relationship('Group')
+    repo_to_perm = relationship('RepoToPerm', cascade='all')
+    stats = relationship('Statistics', cascade='all', uselist=False)
 
-    repo_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
+    repo_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
 
     def __repr__(self):
         return "<%s('%s:%s')>" % (self.__class__.__name__,
@@ -209,7 +213,7 @@
     group_name = Column("group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
     group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
 
-    parent_group = relation('Group', remote_side=group_id)
+    parent_group = relationship('Group', remote_side=group_id)
 
 
     def __init__(self, group_name='', parent_group=None):
@@ -239,9 +243,9 @@
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
     repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
-    user = relation('User')
-    permission = relation('Permission')
-    repository = relation('Repository')
+    user = relationship('User')
+    permission = relationship('Permission')
+    repository = relationship('Repository')
 
 class UserToPerm(Base, BaseModel):
     __tablename__ = 'user_to_perm'
@@ -250,8 +254,8 @@
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
-    user = relation('User')
-    permission = relation('Permission')
+    user = relationship('User')
+    permission = relationship('Permission')
 
 class UsersGroupToPerm(Base, BaseModel):
     __tablename__ = 'users_group_to_perm'
@@ -260,8 +264,8 @@
     users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
 
-    users_group = relation('UsersGroup')
-    permission = relation('Permission')
+    users_group = relationship('UsersGroup')
+    permission = relationship('Permission')
 
 class GroupToPerm(Base, BaseModel):
     __tablename__ = 'group_to_perm'
@@ -272,9 +276,9 @@
     permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
     group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
 
-    user = relation('User')
-    permission = relation('Permission')
-    group = relation('Group')
+    user = relationship('User')
+    permission = relationship('Permission')
+    group = relationship('Group')
 
 class Statistics(Base, BaseModel):
     __tablename__ = 'statistics'
@@ -286,7 +290,7 @@
     commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
     languages = Column("languages", LargeBinary(), nullable=False)#JSON data
 
-    repository = relation('Repository', single_parent=True)
+    repository = relationship('Repository', single_parent=True)
 
 class UserFollowing(Base, BaseModel):
     __tablename__ = 'user_followings'
@@ -299,10 +303,10 @@
     follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
     follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
 
-    user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
+    user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
 
-    follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
-    follows_repository = relation('Repository')
+    follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
+    follows_repository = relationship('Repository')
 
 class CacheInvalidation(Base, BaseModel):
     __tablename__ = 'cache_invalidation'
--- a/rhodecode/model/forms.py	Fri Jan 28 14:49:04 2011 +0100
+++ b/rhodecode/model/forms.py	Fri Jan 28 18:40:50 2011 +0100
@@ -26,7 +26,7 @@
 import formencode
 from formencode import All
 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
-    Email, Bool, StringBoolean
+    Email, Bool, StringBoolean, Set
 
 from pylons.i18n.translation import _
 
@@ -99,11 +99,12 @@
             if value in ['default']:
                 raise formencode.Invalid(_('Invalid group name'), value, state)
             #check if group is unique
-            old_un = None
+            old_ugname = None
             if edit:
-                old_un = UserModel().get(old_data.get('users_group_id')).username
+                old_ugname = UsersGroupModel()\
+                    .get(old_data.get('users_group_id')).users_group_name
 
-            if old_un != value or not edit:
+            if old_ugname != value or not edit:
                 if UsersGroupModel().get_by_groupname(value, cache=False,
                                                case_insensitive=True):
                     raise formencode.Invalid(_('This users group already exists') ,
@@ -402,7 +403,7 @@
     return _UserForm
 
 
-def UsersGroupForm(edit=False, old_data={}):
+def UsersGroupForm(edit=False, old_data={}, available_members=[]):
     class _UsersGroupForm(formencode.Schema):
         allow_extra_fields = True
         filter_extra_fields = True
@@ -412,6 +413,11 @@
 
         users_group_active = StringBoolean(if_missing=False)
 
+        if edit:
+            users_group_members = OneOf(available_members, hideList=False,
+                                        testValueList=True,
+                                        if_missing=None, not_empty=False)
+
     return _UsersGroupForm
 
 def RegisterForm(edit=False, old_data={}):
--- a/rhodecode/model/users_group.py	Fri Jan 28 14:49:04 2011 +0100
+++ b/rhodecode/model/users_group.py	Fri Jan 28 18:40:50 2011 +0100
@@ -32,9 +32,7 @@
 
 from rhodecode.model import BaseModel
 from rhodecode.model.caching_query import FromCache
-from rhodecode.model.db import UsersGroup
-
-from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException
+from rhodecode.model.db import UsersGroup, UsersGroupMember
 
 from sqlalchemy.exc import DatabaseError
 
@@ -51,7 +49,8 @@
         return users_group.get(users_group_id)
 
 
-    def get_by_groupname(self, users_group_name, cache=False, case_insensitive=False):
+    def get_by_groupname(self, users_group_name, cache=False,
+                         case_insensitive=False):
 
         if case_insensitive:
             user = self.sa.query(UsersGroup)\
@@ -77,3 +76,26 @@
             self.sa.rollback()
             raise
 
+    def update(self, users_group_id, form_data):
+
+        try:
+            users_group = self.get(users_group_id, cache=False)
+
+            for k, v in form_data.items():
+                if k == 'users_group_members':
+                    users_group.members = []
+                    self.sa.flush()
+                    members_list = []
+                    if v:
+                        for u_id in set(v):
+                            members_list.append(UsersGroupMember(users_group_id,
+                                                             u_id))
+                    setattr(users_group, 'members', members_list)
+                setattr(users_group, k, v)
+
+            self.sa.add(users_group)
+            self.sa.commit()
+        except:
+            log.error(traceback.format_exc())
+            self.sa.rollback()
+            raise
--- a/rhodecode/templates/admin/users_groups/users_group_edit.html	Fri Jan 28 14:49:04 2011 +0100
+++ b/rhodecode/templates/admin/users_groups/users_group_edit.html	Fri Jan 28 18:40:50 2011 +0100
@@ -0,0 +1,166 @@
+## -*- coding: utf-8 -*-
+<%inherit file="/base/base.html"/>
+
+<%def name="title()">
+    ${_('Edit users group')} ${c.users_group.users_group_name} - ${c.rhodecode_name}
+</%def>
+
+<%def name="breadcrumbs_links()">
+    ${h.link_to(_('Admin'),h.url('admin_home'))} 
+    &raquo; 
+    ${h.link_to(_('UsersGroups'),h.url('users_groups'))} 
+    &raquo;
+    ${_('edit')} "${c.users_group.users_group_name}"
+</%def>
+
+<%def name="page_nav()">
+    ${self.menu('admin')}
+</%def>
+
+<%def name="main()">
+<div class="box">
+    <!-- box / title -->
+    <div class="title">
+        ${self.breadcrumbs()}       
+    </div>
+    <!-- end box / title -->
+    ${h.form(url('users_group', id=c.users_group.users_group_id),method='put', id='edit_users_group')}
+    <div class="form">
+        <!-- fields -->
+	        <div class="fields">
+	             <div class="field">
+	                <div class="label">
+	                    <label for="users_group_name">${_('Group name')}:</label>
+	                </div>
+	                <div class="input">
+	                    ${h.text('users_group_name',class_='small')}
+	                </div>
+	             </div>
+	            
+	             <div class="field">
+	                <div class="label label-checkbox">
+	                    <label for="users_group_active">${_('Active')}:</label>
+	                </div>
+	                <div class="checkboxes">
+	                    ${h.checkbox('users_group_active',value=True)}
+	                </div>
+	             </div>
+	            <div class="field">
+                    <div class="label label-checkbox">
+                        <label for="users_group_active">${_('Members')}:</label>
+                    </div>
+                    <div class="checkboxes">
+	                    <table> 
+	                            <tr>
+	                                <td>
+	                                    <div>
+	                                        <div style="float:left">
+	                                        <div class="text">${_('Group members')}</div>
+	                                            ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,style="min-width:210px")}
+	                                        </div>
+	                                        <div style="float:left;width:20px;padding-top:50px">
+	                                            <img alt="add" id="add_element" 
+	                                                style="padding:2px;cursor:pointer" 
+	                                                src="/images/icons/arrow_left.png">
+	                                            <br />
+	                                            <img alt="remove" id="remove_element" 
+	                                                style="padding:2px;cursor:pointer" 
+	                                                src="/images/icons/arrow_right.png">
+	                                        </div>
+	                                        <div style="float:left">
+	                                            <div class="text">${_('Available members')}</div>
+	                                             ${h.select('available_members',[],c.available_members,multiple=True,size=8,style="min-width:210px")}
+	                                        </div>
+	                                    </div>
+	                                </td>           
+	                            </tr>       
+	                    </table>                    
+                    </div>	            
+
+                </div>			        
+                <div class="buttons">
+                  ${h.submit('save','save',class_="ui-button")}
+                </div>             
+            </div>          
+    </div>        
+${h.end_form()}        
+</div>
+    
+<script type="text/javascript">
+    YAHOO.util.Event.onDOMReady(function(){
+            var D = YAHOO.util.Dom;
+            var E = YAHOO.util.Event;
+            
+            //definition of containers ID's
+            var available_container = 'available_members';
+            var selected_container = 'users_group_members';
+            //form containing containers id
+            var form_id = 'edit_users_group';
+            
+            //temp container for storage.
+            var cache = new Array();
+            var c =  D.get(selected_container);
+            
+            //get only selected options for further fullfilment
+            for(var i = 0;node =c.options[i];i++){
+                if(node.selected){
+                    //push selected to my temp storage left overs :)
+                    cache.push(node);
+                }   
+            }
+            
+            //clear 'selected' select
+            c.options.length = 0;
+
+            //fill it with remembered options
+            for(var i = 0;node = cache[i];i++){
+                c.options[i]=new Option(node.text, node.value, false, false);
+            }
+            
+            function prompts_action_callback(e){
+                
+                var choosen = D.get(selected_container);  
+                var availible = D.get(available_container);
+        
+                if (this.id=='add_element'){
+                    for(var i=0; node = availible.options[i];i++){
+                        if(node.selected){
+                            choosen.appendChild(new Option(node.text, node.value, false, false));
+                        }
+                    }
+                }
+                else if (this.id=='remove_element'){
+
+                    //temp container for storage.
+                    cache = new Array();
+                    
+                    for(var i = 0;node = choosen.options[i];i++){
+                        if(!node.selected){
+                            //push left overs :)
+                            cache.push(node);
+                        }   
+                    }
+                    //clear select
+                    choosen.options.length = 0;
+                    for(var i = 0;node = cache[i];i++){
+                        choosen.options[i]=new Option(node.text, node.value, false, false);
+                    }               
+                }                   
+                else{
+                    
+                }
+            }
+            
+    
+            E.addListener(['add_element','remove_element'],'click',prompts_action_callback)
+
+            E.addListener(form_id,'submit',function(){
+                var choosen = D.get(selected_container);
+                for (var i = 0; i < choosen.options.length; i++) {
+                    choosen.options[i].selected = 'selected';
+                }
+            })  
+        });
+</script>    
+
+</%def>  
\ No newline at end of file