diff --git a/docs/changelog.rst b/docs/changelog.rst --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -27,6 +27,7 @@ news solving issues with Mercurial and LDAP - #402 removed group prefix from repository name when listing repositories inside a group +- added gravatars into permission view and permissions autocomplete fixes +++++ diff --git a/rhodecode/controllers/admin/repos.py b/rhodecode/controllers/admin/repos.py --- a/rhodecode/controllers/admin/repos.py +++ b/rhodecode/controllers/admin/repos.py @@ -284,7 +284,6 @@ class ReposController(BaseController): :param repo_name: """ - try: RepoModel().revoke_user_permission(repo=repo_name, user=request.POST['user_id']) diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py --- a/rhodecode/model/repo.py +++ b/rhodecode/model/repo.py @@ -29,7 +29,7 @@ import traceback from datetime import datetime from rhodecode.lib.vcs.backends import get_backend - +from rhodecode.lib.compat import json from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode from rhodecode.lib.caching_query import FromCache from rhodecode.lib.hooks import log_create_repository @@ -37,6 +37,7 @@ from rhodecode.lib.hooks import log_crea from rhodecode.model import BaseModel from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \ Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup +from rhodecode.lib import helpers as h log = logging.getLogger(__name__) @@ -94,25 +95,28 @@ class RepoModel(BaseModel): return repo.scalar() def get_users_js(self): - users = self.sa.query(User).filter(User.active == True).all() - u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},''' - users_array = '[%s]' % '\n'.join([u_tmpl % (u.user_id, u.name, - u.lastname, u.username) - for u in users]) - return users_array + return json.dumps([ + { + 'id': u.user_id, + 'fname': u.name, + 'lname': u.lastname, + 'nname': u.username, + 'gravatar_lnk': h.gravatar_url(u.email, 14) + } for u in users] + ) def get_users_groups_js(self): users_groups = self.sa.query(UsersGroup)\ .filter(UsersGroup.users_group_active == True).all() - g_tmpl = '''{id:%s, grname:"%s",grmembers:"%s"},''' - - users_groups_array = '[%s]' % '\n'.join([g_tmpl % \ - (gr.users_group_id, gr.users_group_name, - len(gr.members)) - for gr in users_groups]) - return users_groups_array + return json.dumps([ + { + 'id': gr.users_group_id, + 'grname': gr.users_group_name, + 'grmembers': len(gr.members), + } for gr in users_groups] + ) def _get_defaults(self, repo_name): """ @@ -345,6 +349,7 @@ class RepoModel(BaseModel): :param repo: Instance of Repository, repository_id, or repository name :param user: Instance of User, user_id or username """ + user = self.__get_user(user) repo = self.__get_repo(repo) diff --git a/rhodecode/public/css/style.css b/rhodecode/public/css/style.css --- a/rhodecode/public/css/style.css +++ b/rhodecode/public/css/style.css @@ -4195,7 +4195,14 @@ form.comment-inline-form { color: #ffffff; } - +.perm-gravatar{ + vertical-align:middle; + padding:2px; +} +.perm-gravatar-ac{ + vertical-align:middle; + padding:2px; +} /***************************************************************************** DIFFS CSS diff --git a/rhodecode/public/js/rhodecode.js b/rhodecode/public/js/rhodecode.js --- a/rhodecode/public/js/rhodecode.js +++ b/rhodecode/public/js/rhodecode.js @@ -609,6 +609,178 @@ var deleteNotification = function(url, n }; +/** MEMBERS AUTOCOMPLETE WIDGET **/ + +var MembersAutoComplete = function (users_list, groups_list, group_lbl, members_lbl) { + var myUsers = users_list; + var myGroups = groups_list; + + // Define a custom search function for the DataSource of users + var matchUsers = function (sQuery) { + // Case insensitive matching + var query = sQuery.toLowerCase(); + var i = 0; + var l = myUsers.length; + var matches = []; + + // Match against each name of each contact + for (; i < l; i++) { + contact = myUsers[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; + }; + + // Define a custom search function for the DataSource of usersGroups + var matchGroups = function (sQuery) { + // Case insensitive matching + var query = sQuery.toLowerCase(); + var i = 0; + var l = myGroups.length; + var matches = []; + + // Match against each name of each contact + for (; i < l; i++) { + matched_group = myGroups[i]; + if (matched_group.grname.toLowerCase().indexOf(query) > -1) { + matches[matches.length] = matched_group; + } + } + return matches; + }; + + //match all + var matchAll = function (sQuery) { + u = matchUsers(sQuery); + g = matchGroups(sQuery); + return u.concat(g); + }; + + // DataScheme for members + var memberDS = new YAHOO.util.FunctionDataSource(matchAll); + memberDS.responseSchema = { + fields: ["id", "fname", "lname", "nname", "grname", "grmembers", "gravatar_lnk"] + }; + + // DataScheme for owner + var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers); + ownerDS.responseSchema = { + fields: ["id", "fname", "lname", "nname", "gravatar_lnk"] + }; + + // Instantiate AutoComplete for perms + var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS); + membersAC.useShadow = false; + membersAC.resultTypeList = false; + + // Instantiate AutoComplete for owner + var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS); + ownerAC.useShadow = false; + ownerAC.resultTypeList = false; + + + // Helper highlight function for the formatter + var highlightMatch = function (full, snippet, matchindex) { + return full.substring(0, matchindex) + + "" + + full.substr(matchindex, snippet.length) + + "" + full.substring(matchindex + snippet.length); + }; + + // Custom formatter to highlight the matching letters + var custom_formatter = function (oResultData, sQuery, sResultMatch) { + var query = sQuery.toLowerCase(); + var _gravatar = function(res, em, group){ + if (group !== undefined){ + em = '/images/icons/group.png' + } + tmpl = '{1}' + return tmpl.format(em,res) + } + // group + if (oResultData.grname != undefined) { + var grname = oResultData.grname; + var grmembers = oResultData.grmembers; + var grnameMatchIndex = grname.toLowerCase().indexOf(query); + var grprefix = "{0}: ".format(group_lbl); + var grsuffix = " (" + grmembers + " )"; + var grsuffix = " ({0} {1})".format(grmembers, members_lbl); + + if (grnameMatchIndex > -1) { + return _gravatar(grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix,null,true); + } + return _gravatar(grprefix + oResultData.grname + grsuffix, null,true); + // Users + } else if (oResultData.fname != undefined) { + var fname = oResultData.fname, + lname = oResultData.lname, + nname = oResultData.nname || "", + // Guard against null value + 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 _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk); + } else { + return ''; + } + }; + membersAC.formatResult = custom_formatter; + ownerAC.formatResult = custom_formatter; + + 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 + //fill the autocomplete with value + if (oData.nname != undefined) { + //users + myAC.getInputEl().value = oData.nname; + YUD.get('perm_new_member_type').value = 'user'; + } else { + //groups + myAC.getInputEl().value = oData.grname; + YUD.get('perm_new_member_type').value = 'users_group'; + } + }; + + membersAC.itemSelectEvent.subscribe(myHandler); + if(ownerAC.itemSelectEvent){ + ownerAC.itemSelectEvent.subscribe(myHandler); + } + + return { + memberDS: memberDS, + ownerDS: ownerDS, + membersAC: membersAC, + ownerAC: ownerAC, + }; +} + + + /** * QUICK REPO MENU */ diff --git a/rhodecode/templates/admin/repos/repo_edit_perms.html b/rhodecode/templates/admin/repos/repo_edit_perms.html --- a/rhodecode/templates/admin/repos/repo_edit_perms.html +++ b/rhodecode/templates/admin/repos/repo_edit_perms.html @@ -25,7 +25,7 @@ ${h.radio('u_perm_%s' % r2p.user.username,'repository.write')} ${h.radio('u_perm_%s' % r2p.user.username,'repository.admin')} - ${r2p.user.username} + ${r2p.user.username} %if r2p.user.username !='default': @@ -46,7 +46,7 @@ ${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.write')} ${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.admin')} - ${g2p.users_group.users_group_name} + ${g2p.users_group.users_group_name} @@ -117,165 +117,12 @@ YUE.onDOMReady(function () { YUD.setStyle('add_perm', 'opacity', '0.6'); YUD.setStyle('add_perm', 'cursor', 'default'); }); + MembersAutoComplete( + ${c.users_array|n}, + ${c.users_groups_array|n}, + "${_('Group')}", + "${_('members')}" + ); }); -YAHOO.example.FnMultipleFields = function () { - var myUsers = ${c.users_array|n}; - var myGroups = ${c.users_groups_array|n}; - - // Define a custom search function for the DataSource of users - var matchUsers = function (sQuery) { - // Case insensitive matching - var query = sQuery.toLowerCase(); - var i = 0; - var l = myUsers.length; - var matches = []; - - // Match against each name of each contact - for (; i < l; i++) { - contact = myUsers[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; - }; - - // Define a custom search function for the DataSource of usersGroups - var matchGroups = function (sQuery) { - // Case insensitive matching - var query = sQuery.toLowerCase(); - var i = 0; - var l = myGroups.length; - var matches = []; - - // Match against each name of each contact - for (; i < l; i++) { - matched_group = myGroups[i]; - if (matched_group.grname.toLowerCase().indexOf(query) > -1) { - matches[matches.length] = matched_group; - } - } - return matches; - }; - - //match all - var matchAll = function (sQuery) { - u = matchUsers(sQuery); - g = matchGroups(sQuery); - return u.concat(g); - }; - - // DataScheme for members - var memberDS = new YAHOO.util.FunctionDataSource(matchAll); - memberDS.responseSchema = { - fields: ["id", "fname", "lname", "nname", "grname", "grmembers"] - }; - - // DataScheme for owner - var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers); - ownerDS.responseSchema = { - fields: ["id", "fname", "lname", "nname"] - }; - - // Instantiate AutoComplete for perms - var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS); - membersAC.useShadow = false; - membersAC.resultTypeList = false; - - // Instantiate AutoComplete for owner - var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS); - ownerAC.useShadow = false; - ownerAC.resultTypeList = false; - - - // Helper highlight function for the formatter - var highlightMatch = function (full, snippet, matchindex) { - return full.substring(0, matchindex) + "" + full.substr(matchindex, snippet.length) + "" + full.substring(matchindex + snippet.length); - }; - - // Custom formatter to highlight the matching letters - var custom_formatter = function (oResultData, sQuery, sResultMatch) { - var query = sQuery.toLowerCase(); - - if (oResultData.grname != undefined) { - var grname = oResultData.grname; - var grmembers = oResultData.grmembers; - var grnameMatchIndex = grname.toLowerCase().indexOf(query); - var grprefix = "${_('Group')}: "; - var grsuffix = " (" + grmembers + " ${_('members')})"; - - if (grnameMatchIndex > -1) { - return grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix; - } - - return grprefix + oResultData.grname + grsuffix; - } else if (oResultData.fname != undefined) { - - var fname = oResultData.fname, - lname = oResultData.lname, - nname = oResultData.nname || "", - // Guard against null value - 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; - } else { - return ''; - } - }; - membersAC.formatResult = custom_formatter; - ownerAC.formatResult = custom_formatter; - - 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 - //fill the autocomplete with value - if (oData.nname != undefined) { - //users - myAC.getInputEl().value = oData.nname; - YUD.get('perm_new_member_type').value = 'user'; - } else { - //groups - myAC.getInputEl().value = oData.grname; - YUD.get('perm_new_member_type').value = 'users_group'; - } - - }; - - membersAC.itemSelectEvent.subscribe(myHandler); - if(ownerAC.itemSelectEvent){ - ownerAC.itemSelectEvent.subscribe(myHandler); - } - - return { - memberDS: memberDS, - ownerDS: ownerDS, - membersAC: membersAC, - ownerAC: ownerAC, - }; -}(); - diff --git a/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html b/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html --- a/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html +++ b/rhodecode/templates/admin/repos_groups/repos_group_edit_perms.html @@ -15,7 +15,7 @@ ${h.radio('u_perm_%s' % r2p.user.username,'group.write')} ${h.radio('u_perm_%s' % r2p.user.username,'group.admin')} - ${r2p.user.username} + ${r2p.user.username} %if r2p.user.username !='default': @@ -35,7 +35,7 @@ ${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.write')} ${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.admin')} - ${g2p.users_group.users_group_name} + ${g2p.users_group.users_group_name} @@ -106,165 +106,12 @@ YUE.onDOMReady(function () { YUD.setStyle('add_perm', 'opacity', '0.6'); YUD.setStyle('add_perm', 'cursor', 'default'); }); + MembersAutoComplete( + ${c.users_array|n}, + ${c.users_groups_array|n}, + "${_('Group')}", + "${_('members')}" + ); }); -YAHOO.example.FnMultipleFields = function () { - var myUsers = ${c.users_array|n}; - var myGroups = ${c.users_groups_array|n}; - - // Define a custom search function for the DataSource of users - var matchUsers = function (sQuery) { - // Case insensitive matching - var query = sQuery.toLowerCase(); - var i = 0; - var l = myUsers.length; - var matches = []; - - // Match against each name of each contact - for (; i < l; i++) { - contact = myUsers[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; - }; - - // Define a custom search function for the DataSource of usersGroups - var matchGroups = function (sQuery) { - // Case insensitive matching - var query = sQuery.toLowerCase(); - var i = 0; - var l = myGroups.length; - var matches = []; - - // Match against each name of each contact - for (; i < l; i++) { - matched_group = myGroups[i]; - if (matched_group.grname.toLowerCase().indexOf(query) > -1) { - matches[matches.length] = matched_group; - } - } - return matches; - }; - - //match all - var matchAll = function (sQuery) { - u = matchUsers(sQuery); - g = matchGroups(sQuery); - return u.concat(g); - }; - - // DataScheme for members - var memberDS = new YAHOO.util.FunctionDataSource(matchAll); - memberDS.responseSchema = { - fields: ["id", "fname", "lname", "nname", "grname", "grmembers"] - }; - - // DataScheme for owner - var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers); - ownerDS.responseSchema = { - fields: ["id", "fname", "lname", "nname"] - }; - - // Instantiate AutoComplete for perms - var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS); - membersAC.useShadow = false; - membersAC.resultTypeList = false; - - // Instantiate AutoComplete for owner - var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS); - ownerAC.useShadow = false; - ownerAC.resultTypeList = false; - - - // Helper highlight function for the formatter - var highlightMatch = function (full, snippet, matchindex) { - return full.substring(0, matchindex) + "" + full.substr(matchindex, snippet.length) + "" + full.substring(matchindex + snippet.length); - }; - - // Custom formatter to highlight the matching letters - var custom_formatter = function (oResultData, sQuery, sResultMatch) { - var query = sQuery.toLowerCase(); - - if (oResultData.grname != undefined) { - var grname = oResultData.grname; - var grmembers = oResultData.grmembers; - var grnameMatchIndex = grname.toLowerCase().indexOf(query); - var grprefix = "${_('Group')}: "; - var grsuffix = " (" + grmembers + " ${_('members')})"; - - if (grnameMatchIndex > -1) { - return grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix; - } - - return grprefix + oResultData.grname + grsuffix; - } else if (oResultData.fname != undefined) { - - var fname = oResultData.fname, - lname = oResultData.lname, - nname = oResultData.nname || "", - // Guard against null value - 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; - } else { - return ''; - } - }; - membersAC.formatResult = custom_formatter; - ownerAC.formatResult = custom_formatter; - - 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 - //fill the autocomplete with value - if (oData.nname != undefined) { - //users - myAC.getInputEl().value = oData.nname; - YUD.get('perm_new_member_type').value = 'user'; - } else { - //groups - myAC.getInputEl().value = oData.grname; - YUD.get('perm_new_member_type').value = 'users_group'; - } - - }; - - membersAC.itemSelectEvent.subscribe(myHandler); - if(ownerAC.itemSelectEvent){ - ownerAC.itemSelectEvent.subscribe(myHandler); - } - - return { - memberDS: memberDS, - ownerDS: ownerDS, - membersAC: membersAC, - ownerAC: ownerAC, - }; -}(); -