diff options
author | Adam Young <ayoung@redhat.com> | 2010-07-09 11:40:38 -0400 |
---|---|---|
committer | Adam Young <ayoung@redhat.com> | 2010-07-09 11:40:38 -0400 |
commit | 6271b4ddaf8a21e824102adbb113f670428cef16 (patch) | |
tree | c05356d97076a247926904dbb2ba108cdc06a1cb | |
parent | c6ec11bfca4bf05fb8683675f7a58b5d42b20179 (diff) | |
parent | ea94d08dd5d67baeed620f403365e2905f88dd81 (diff) | |
download | freeipa-6271b4ddaf8a21e824102adbb113f670428cef16.tar.gz freeipa-6271b4ddaf8a21e824102adbb113f670428cef16.tar.xz freeipa-6271b4ddaf8a21e824102adbb113f670428cef16.zip |
Merge branch 'pzuna-master' into pzuna-merge
-rw-r--r-- | install/static/ipa.css | 58 | ||||
-rw-r--r-- | install/webui/user.html | 300 | ||||
-rw-r--r-- | ipa.spec.in | 5 | ||||
-rw-r--r-- | ipalib/plugins/baseldap.py | 41 |
4 files changed, 289 insertions, 115 deletions
diff --git a/install/static/ipa.css b/install/static/ipa.css index 64ea9f855..c7b692cc8 100644 --- a/install/static/ipa.css +++ b/install/static/ipa.css @@ -16,7 +16,7 @@ div#view { position: fixed; right: 0; top: 0; -} +} div#header { background: -moz-linear-gradient(top, #65646e,#1f1f1f); @@ -46,6 +46,14 @@ div#header div#loggedinas a { color: #fff; } +h1 { + font-size: 26pt; + font-weight: bold; + margin-bottom: 30px; + margin-left: 15px; + margin-top: 18px; +} + div#content ul#viewtype { padding-left: 20px; } @@ -80,35 +88,57 @@ div#content div#buttons img { border: 0; } +h2 { + font-size: 18pt; + font-weight: bold; + margin-left: 15px; + margin-top: 0; + margin-bottom: 0px; + text-align: left; +} + hr { background-color: #b2b2b2; + clear: both; color: #b2b2b2; height: 1px; margin-left: 15px; margin-right: 15px; + margin-top: 10px; } -table.entrytable { +dl.entryattrs { + clear: both; margin-left: 15px; + margin-top: 18px; white-space: nowrap; } -table.entrytable caption { - font-size: 18pt; - font-weight: bold; - text-align: left; -} - -table.entrytable th { - font-weight: normal; +dl.entryattrs dt { + clear: left; + float: left; + padding-bottom: 18px; padding-right: 18px; - padding-top: 18px; text-align: right; - width: 150px; + width: 160px; +} + +dl.entryattrs dd { + float: left; + padding-bottom: 18px; +} + +dl.entryattrs dd.first { + margin-left: 0px; +} + +dl.entryattrs dd.other { + clear: both; + margin-left: 178px; } -table.entrytable td { - padding-top: 18px; +dl.entryattrs input { + margin-right: 5px; } div#backtotop { diff --git a/install/webui/user.html b/install/webui/user.html index 1a1ece253..afb2b0114 100644 --- a/install/webui/user.html +++ b/install/webui/user.html @@ -9,10 +9,10 @@ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>jQuery test page for IPA</title> - <link href="/static/ipa.css" rel="stylesheet" type="text/css" /> + <link href="static/ipa.css" rel="stylesheet" type="text/css" /> - <script src="/static/jquery.js" type="text/javascript"> </script> - <script src="/static/ipa.js" type="text/javascript"> </script> + <script src="static/jquery.js" type="text/javascript"> </script> + <script src="static/ipa.js" type="text/javascript"> </script> <script py:for="obj_name in obj.split(',')" type="text/javascript"> ipa_objs['${obj_name}'] = ${get_plugin_data(obj_name)}; @@ -41,43 +41,97 @@ function on_win(data, textStatus, xhr) { + if (data['error']) { + alert(data['error']['message']); + return; + } + var result = data.result.result; cache = $.extend(true, {}, result); process_entry(result); } + function on_lock_win(data, textStatus, xhr) + { + if (data['error']) { + alert(data['error']['message']); + return; + } + + var jobj = $('a[title=Active]'); + if (jobj.length) { + if (cache) { + var memberof = cache['memberof']; + if (memberof) { + memberof.push( + 'cn=inactivated,cn=account inactivation' + ); + } else { + memberof = ['cn=inactivated,cn=account inactivation']; + } + cache['memberof'] = memberof; + a_status(jobj.parent().prev(), cache); + jobj.parent().remove() + } + return; + } + + var jobj = $('a[title=Inactive]'); + if (jobj.length) { + if (cache) { + var memberof = cache['memberof']; + if (memberof) { + for (var i = 0; i < memberof.length; ++i) { + if (memberof[i].indexOf('cn=inactivated,cn=account inactivation') != -1) { + memberof.splice(i, 1); + break; + } + } + } else { + memberof = []; + } + cache['memberof'] = memberof; + a_status(jobj.parent().prev(), cache); + jobj.parent().remove(); + } + return; + } + } + + var first_temp = '<dd class="first">I</dd>'; + var other_temp = '<dd class="other">I</dd>'; var add_temp = '<a href="dummy" onclick="return (add_on_click(this));" title="A">Add</a>'; function process_entry(result) { - $('.entrytable tr').each(function () { - var jobj = $(this); - if (!jobj.children().first().attr('title')) - jobj.remove(); - }); + $('dd').remove(); - $('.entrytable th').each(function () { + $('h1').text( + 'Viewing ' + PluginData['object_name'] + ': ' + qs['pkey'] + ); + + $('.entryattrs dt').each(function () { var jobj = $(this); - jobj.next().empty(); var attr = jobj.attr('title'); if (attr.indexOf('call_') == 0) { func = window[attr.substr(5)]; if (func) - jobj.next().append(func(result)); + func(jobj, result); else - jobj.next().text('-'); + jobj.after(first_temp.replace('I', '-')); } else { var value = result[attr]; if (value) { - for (var i = 0; i < value.length; ++i) { - jobj.next().append(create_input(attr, value[i])); - if ((i + 1) < value.length) { - jobj.parent().after('<tr><td></td><td></td></tr>'); - jobj = jobj.parent().next().children().first(); - } + var input = create_input(attr, value[0]); + jobj.after(first_temp.replace('I', input)); + for (var i = 1; i < value.length; ++i) { + var input = create_input(attr, value[i]); + jobj.after(other_temp.replace('I', input)); } } else { - jobj.next().append(add_temp.replace('A', attr)); + jobj.after( + first_temp.replace('I', add_temp.replace('A', attr)) + ); } } }); @@ -103,50 +157,51 @@ } var text_temp = '<input type="text" name="A" value="V" />'; + var pwd_temp = '<a href="dummy" onclick="return (resetpwd_on_click(this))" title="A">Reset Password</a>'; + var rem_temp = '<a href="dummy" onclick="return (remove_on_click(this))" title="A">Remove</a>'; function create_input(attr, value) { var param_info = get_param_info(attr); if (!param_info) { return ( - text_temp.replace('A', attr).replace('V', value.toString()) + text_temp.replace('A', attr).replace('V', value.toString()) + + rem_temp.replace('A', attr) ); } if (param_info['primary_key'] || ('no_update' in param_info['flags'])) - return (document.createTextNode(value.toString())); + return (value.toString()); var param_class = param_info['class']; if (param_class == 'Str') - return ( - text_temp.replace('A', attr).replace('V', value.toString()) - ); + var ret = text_temp.replace('A', attr).replace('V', value.toString()); else if (param_class == 'Int') - return ( - text_temp.replace('A', attr).replace('V', value.toString()) - ); + var ret = text_temp.replace('A', attr).replace('V', value.toString()); else if (param_class == 'Bool') - return ( - text_temp.replace('A', attr).replace('V', value.toString()) - ); + var ret = text_temp.replace('A', attr).replace('V', value.toString()); + else if (param_class == 'Password') + var ret = pwd_temp.replace('A', attr); + else + var ret = text_temp.replace('A', attr).replace('V', value.toString()); - return ( - text_temp.replace('A', attr).replace('V', value.toString()) - ); + if ((!param_info['required']) && (param_class != 'Password')) + ret += rem_temp.replace('A', attr); + + return (ret); } - function caption_on_click(obj) + function h2_on_click(obj) { var jobj = $(obj); - var txt = jobj.text().replace(/^\s*/, '').replace(/\s*$/, ''); - if (txt.charCodeAt(0) == 8211) { - obj.siblings = jobj.nextAll().detach(); + var txt = jobj.text().replace(/^\s*/, ''); + if (txt.charCodeAt(0) == 8722) { + obj.dl = jobj.next().detach(); jobj.text('+' + txt.substr(1)); } else { - if (obj.siblings) { - obj.siblings.insertAfter(jobj); - } + if (obj.dl) + obj.dl.insertAfter(obj); jobj.text( - String.fromCharCode(8211) + txt.substr(1) + String.fromCharCode(8722) + txt.substr(1) ); } } @@ -163,17 +218,43 @@ if (!qs['pkey']) return; - var modlist = {'all': true, 'addattr': []}; - $('input').each(function () { + var modlist = {'all': true, 'setattr': [], 'addattr': []}; + var attrs_wo_option = {}; + + $('.entryattrs input').each(function () { var jobj = $(this); var attr = jobj.attr('name'); + var param_info = get_param_info(attr); - if (param_info) + if (param_info) { modlist[attr] = jobj.val(); - else - modlist['addattr'].push(attr + '=' + jobj.val()); + return; + } + + if (!attrs_wo_option[attr]) + attrs_wo_option[attr] = []; + attrs_wo_option[attr].push(jobj.val()); + }); + + $('.entryattrs dt').each(function () { + var jobj = $(this); + + var attr = jobj.attr('title'); + if (attr.indexOf('call_') == 0) + return; + + var next = jobj.next('dd'); + if (!next.length || !next.children('input').length) + attrs_wo_option[attr] = ['']; }); + for (attr in attrs_wo_option) { + var values = attrs_wo_option[attr]; + modlist['setattr'].push(attr + '=' + values[0]); + for (var i = 1; i < values.length; ++i) + modlist['addattr'].push(attr + '=' + values[i]); + } + ipa_cmd( 'mod', [qs['pkey']], modlist, on_win, on_fail, PluginData['name'] @@ -184,11 +265,73 @@ function add_on_click(obj) { - jobj = $(obj); - jobj.parent().append(create_input(jobj.attr('title'), '')); + var jobj = $(obj); + var par = jobj.parent(); + par.append(create_input(jobj.attr('title'), '')); jobj.remove(); return (false); } + + function remove_on_click(obj) + { + var jobj = $(obj); + var attr = jobj.attr('title'); + var par = jobj.parent(); + + var next = par.next('dd'); + if (next.length) { + if (par.hasClass('first')) { + next.addClass('first'); + next.removeClass('other'); + } + par.remove(); + } else { + par.empty(); + par.append(add_temp.replace('A', attr)); + } + + return (false); + } + + function toggle_on_click(obj) + { + var jobj = $(obj); + var val = jobj.attr('title'); + if (val == 'Active') { + ipa_cmd( + 'lock', [qs['pkey']], {}, on_lock_win, on_fail, + PluginData['name'] + ); + } else { + ipa_cmd( + 'unlock', [qs['pkey']], {}, on_lock_win, on_fail, + PluginData['name'] + ); + } + return (false); + } + + var toggle_temp = 'S <a href="dummy" onclick="return (toggle_on_click(this))" title="S">Toggle</a>'; + function a_status(jobj, result) + { + var memberof = result['memberof']; + if (memberof) { + for (var i = 0; i < memberof.length; ++i) { + if (memberof[i].indexOf('cn=inactivated,cn=account inactivation') != -1) { + jobj.after( + first_temp.replace('I', toggle_temp.replace(/S/g, 'Inactive')) + ); + return; + } + } + } + jobj.after(first_temp.replace('I', toggle_temp.replace(/S/g, 'Active'))); + } + + function a_password(jobj, result) + { + jobj.after(first_temp.replace('I', create_input('userpassword', ''))); + } //]]> </script> </head> @@ -198,7 +341,7 @@ <div id="header"> <div id="logo"> <a href="#"> - <img src="/static/ipa_logo_180x50.png" /> + <img src="static/ipa_logo_180x50.png" /> </a> </div> <div id="loggedinas"> @@ -207,54 +350,51 @@ </div> <div id="content"> + <h1>Viewing User: Pavel Zuna</h1> <div id="buttons"> - <a href="dummy"><img id="butreset" src="/static/but-reset.png" alt="Reset" /></a> - <a href="dummy"><img id="butupdate" src="/static/but-update.png" alt="Update" /></a> + <a href="dummy"><img id="butreset" src="static/but-reset.png" alt="Reset" /></a> + <a href="dummy"><img id="butupdate" src="static/but-update.png" alt="Update" /></a> </div> <ul id="viewtype"> <li id="viewcaption">View:</li> <li> - <img src="/static/but-selected.png" alt="" /> + <img src="static/but-selected.png" alt="" /> Personal Details </li> <li> - <img src="/static/but-unselected.png" alt="" /> + <img src="static/but-unselected.png" alt="" /> <a href="memberof?pkey=${pkey}">Memberships</a> </li> </ul> <hr /> - <table id="identity" class="entrytable"> - <caption onclick="caption_on_click(this)"> - – Identity Details - </caption> - <tr><th title="title">Title:</th><td></td></tr> - <tr><th title="givenname">First Name:</th><td></td></tr> - <tr><th title="sn">Last Name:</th><td></td></tr> - <tr><th title="cn">Full Name:</th><td></td></tr> - <tr><th title="displayname">Display Name:</th><td></td> - </tr> - </table> + <h2 onclick="h2_on_click(this)">− Identity Details</h2> + <dl id="identity" class="entryattrs"> + <dt title="title">Title:</dt> + <dt title="givenname">First Name:</dt> + <dt title="sn">Last Name:</dt> + <dt title="cn">Full Name:</dt> + <dt title="displayname">Display Name:</dt> + <dt title="initials">Initials:</dt> + </dl> <hr /> - <table id="account" class="entrytable"> - <caption onclick="caption_on_click(this)"> - – Account Details - </caption> - <tr><th title="call_a_status">Account Status:</th><td></td></tr> - <tr><th title="uid">Login:</th><td></td></tr> - <tr><th title="call_a_password">Password:</th><td></td></tr> - <tr><th title="uidnumber">UID:</th><td></td></tr> - <tr><th title="gidnumber">GID:</th><td></td></tr> - <tr><th title="homedirectory">Home Directory:</th><td></td></tr> - </table> + <h2 onclick="h2_on_click(this)">− Account Details</h2> + <dl id="account" class="entryattrs"> + <dt title="call_a_status">Account Status:</dt> + <dt title="uid">Login:</dt> + <dt title="call_a_password">Password:</dt> + <dt title="uidnumber">UID:</dt> + <dt title="gidnumber">GID:</dt> + <dt title="homedirectory">Home Directory:</dt> + </dl> <hr /> - <table id="uncategorized" class="entrytable"> - <caption onclick="caption_on_click(this)"> - – Uncategorized Information - </caption> - </table> + <h2 onclick="h2_on_click(this)">− Contact Details</h2> + <dl id="contact" class="entryattrs"> + <dt title="mail">E-mail Address:</dt> + <dt title="call_a_numbers">Numbers:</dt> + </dl> <hr /> <div id="backtotop"> diff --git a/ipa.spec.in b/ipa.spec.in index bc1ee7e28..235f96233 100644 --- a/ipa.spec.in +++ b/ipa.spec.in @@ -394,6 +394,11 @@ fi %{_usr}/share/ipa/migration/invalid.html %{_usr}/share/ipa/migration/migration.css %{_usr}/share/ipa/migration/migration.py* +%dir %{_usr}/share/ipa/static +%{_usr}/share/ipa/static/*.png +%{_usr}/share/ipa/static/*.css +%{_usr}/share/ipa/static/*.js +%dir %{_usr}/share/ipa/webui %{_usr}/share/ipa/webui/*.html %dir %{_usr}/share/ipa/static %{_usr}/share/ipa/static/* diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py index a05f7f29a..92b42d4ee 100644 --- a/ipalib/plugins/baseldap.py +++ b/ipalib/plugins/baseldap.py @@ -48,11 +48,12 @@ def get_attributes(attrs): """ Given a list of values in the form name=value, return a list of name. """ + if not attrs: + return [] attrlist=[] for attr in attrs: m = re.match("\s*(.*?)\s*=\s*(.*?)\s*$", attr) attrlist.append(str(m.group(1)).lower()) - return attrlist @@ -112,7 +113,6 @@ class LDAPObject(Object): entry_attrs.setdefault(new_attr, []).append( ldap_obj.get_primary_key_from_dn(member) ) - del entry_attrs[attr] def handle_not_found(self, *keys): raise errors.NotFound( @@ -399,7 +399,6 @@ class LDAPUpdate(LDAPQuery, crud.Update): """ Update an LDAP entry. """ - takes_options = _attr_options def execute(self, *keys, **options): @@ -437,26 +436,26 @@ class LDAPUpdate(LDAPQuery, crud.Update): set. """ if 'addattr' in options: - try: - (dn, old_entry) = ldap.get_entry( - dn, attrs_list, normalize=self.obj.normalize_dn - ) - except errors.ExecutionError, e: + setset = set(get_attributes(options['setattr'])) + addset = set(get_attributes(options['addattr'])) + difflist = list(addset.difference(setset)) + if difflist: try: - (dn, old_entry) = self._call_exc_callbacks( - keys, options, e, ldap.get_entry, dn, attrs_list, - normalize=self.obj.normalize_dn + (dn, old_entry) = ldap.get_entry( + dn, difflist, normalize=self.obj.normalize_dn ) - except errors.NotFound: - self.obj.handle_not_found(*keys) - attrlist = get_attributes(options['addattr']) - for attr in attrlist: - if attr in old_entry: - if type(entry_attrs[attr]) in (tuple,list): - entry_attrs[attr] = old_entry[attr] + entry_attrs[attr] - else: - old_entry[attr].append(entry_attrs[attr]) - entry_attrs[attr] = old_entry[attr] + except errors.ExecutionError, e: + try: + (dn, old_entry) = self._call_exc_callbacks( + keys, options, e, ldap.get_entry, dn, attrs_list, + normalize=self.obj.normalize_dn + ) + except errors.NotFound: + self.obj.handle_not_found(*keys) + for a in old_entry: + if not isinstance(entry_attrs[a], (list, tuple)): + entry_attrs[a] = [entry_attrs[a]] + entry_attrs[a] += old_entry[a] try: ldap.update_entry(dn, entry_attrs, normalize=self.obj.normalize_dn) |