summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Young <ayoung@redhat.com>2010-07-09 11:40:38 -0400
committerAdam Young <ayoung@redhat.com>2010-07-09 11:40:38 -0400
commit6271b4ddaf8a21e824102adbb113f670428cef16 (patch)
treec05356d97076a247926904dbb2ba108cdc06a1cb
parentc6ec11bfca4bf05fb8683675f7a58b5d42b20179 (diff)
parentea94d08dd5d67baeed620f403365e2905f88dd81 (diff)
downloadfreeipa-6271b4ddaf8a21e824102adbb113f670428cef16.tar.gz
freeipa-6271b4ddaf8a21e824102adbb113f670428cef16.tar.xz
freeipa-6271b4ddaf8a21e824102adbb113f670428cef16.zip
Merge branch 'pzuna-master' into pzuna-merge
-rw-r--r--install/static/ipa.css58
-rw-r--r--install/webui/user.html300
-rw-r--r--ipa.spec.in5
-rw-r--r--ipalib/plugins/baseldap.py41
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)">
- &#8211; 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)">&#8722; 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)">
- &#8211; 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)">&#8722; 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)">
- &#8211; Uncategorized Information
- </caption>
- </table>
+ <h2 onclick="h2_on_click(this)">&#8722; 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)