The Javascript code for the new web UI

Now with whitespace cleanup.
This commit is contained in:
Adam Young 2010-08-06 10:01:44 -04:00
parent a63fd83e89
commit 125bd09faf
33 changed files with 10392 additions and 0 deletions

View File

@ -0,0 +1,43 @@
NULL =
appdir = $(IPA_DATA_DIR)/static
app_DATA = \
but-reset.png \
but-update.png \
but-selected.png \
but-unselected.png \
ipa_logo_180x50.png \
ipa.js \
ipa.css \
jquery.js \
group.js \
group-details.inc \
host.js \
hostgroup.js \
index.xhtml \
jquery.cookie.js \
navigation.js \
netgroup.js \
pageparams.js \
search.js \
details.js \
user.js \
user-add.inc \
user-details.inc \
ipalogo.png \
gray-fade-line.png \
Mainnav-background.png \
Mainnav-offtab.png \
Mainnav-ontab.png \
Subnav-background.png \
Subnav-offbutton.png \
Subnav-onbutton.png \
$(NULL)
EXTRA_DIST = \
$(app_DATA) \
$(NULL)
MAINTAINERCLEANFILES = \
*~ \
Makefile.in

559
install/static/details.js Normal file
View File

@ -0,0 +1,559 @@
/* Authors:
* Pavel Zuna <pzuna@redhat.com>
*
* Copyright (C) 2010 Red Hat
* see file 'COPYING' for use and warranty information
*
* 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 only
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* IPA Object Details - populating definiton lists from entry data */
/* REQUIRES: ipa.js */
var IPA_DETAILS_POPULATE = 1;
var IPA_DETAILS_UPDATE = 2;
/* name of IPA object, that we're populating the lists for */
var _ipa_obj_name = '';
/* initialize the IPA Object Details library */
function ipa_details_init(obj_name, url)
{
ipa_init(url);
_ipa_obj_name = obj_name;
}
var _ipa_load_on_win_callback = null;
var _ipa_load_on_fail_callback = null;
var ipa_details_cache = null;
function ipa_details_load(pkey, on_win, on_fail)
{
if (!pkey)
return;
_ipa_load_on_win_callback = on_win;
_ipa_load_on_fail_callback = on_fail;
ipa_cmd(
'show', [pkey], {all: true}, _ipa_load_on_win, _ipa_load_on_fail,
_ipa_obj_name
);
}
function _ipa_load_on_win(data, text_status, xhr)
{
if (_ipa_load_on_win_callback)
_ipa_load_on_win_callback(data, text_status, xhr);
if (data['error'])
return;
var result = data.result.result;
ipa_details_cache = $.extend(true, {}, result);
ipa_details_display(result);
}
function _ipa_load_on_fail(xhr, text_status, error_thrown)
{
if (_ipa_load_on_fail_callback)
_ipa_load_on_fail_callback(xhr, text_status, error_thrown);
}
var _ipa_update_on_win_callback = null;
var _ipa_update_on_fail_callback = null;
function ipa_details_update(pkey, on_win, on_fail)
{
if (!pkey)
return;
var modlist = {'all': true, 'setattr': [], 'addattr': []};
var attrs_wo_option = {};
$('.entryattrs input').each(function () {
var jobj = $(this);
var dt = jobj.parent().prevAll('dt').slice(0, 1);
if (!dt)
return;
var attr = dt.attr('title');
if (!attr)
return;
if (attr.indexOf('call_') == 0) {
var func = window[attr.substr(5)];
if (!func)
return;
func(dt, modlist, IPA_DETAILS_UPDATE);
return;
}
var param_info = ipa_get_param_info(attr);
if (param_info) {
modlist[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 || 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_update_on_win_callback = on_win;
_ipa_update_on_fail_callback = on_fail;
ipa_cmd(
'mod', [pkey], modlist, _ipa_update_on_win, _ipa_update_on_fail,
_ipa_obj_name
);
}
function _ipa_update_on_win(data, text_status, xhr)
{
if (_ipa_update_on_win_callback)
_ipa_update_on_win_callback(data, text_status, xhr);
if (data['error'])
return;
var result = data.result.result;
ipa_details_cache = $.extend(true, {}, result);
ipa_details_display(result);
}
function _ipa_update_on_fail(xhr, text_status, error_thrown)
{
if (_ipa_update_on_fail_callback)
_ipa_update_on_fail_callback(xhr, text_status, error_thrown);
}
function ipa_details_create(dls)
{
for (var i = 0; i < def_lists.length; ++i) {
var d = dls[i];
ipa_generate_dl($('hr').last(), d[0], d[1], d[2]);
}
}
var _ipa_h2_template = '<h2 onclick="_h2_on_click(this)">&#8722; I</h2>';
var _ipa_dl_template = '<dl id="I" class="entryattrs"></dl>';
var _ipa_dt_template = '<dt title="T">N:</dt>';
function ipa_generate_dl(jobj, id, name, dts)
{
if (!dts)
return;
jobj.after(_ipa_h2_template.replace('I', name));
jobj = jobj.next();
jobj.after(_ipa_dl_template.replace('I', id));
jobj = jobj.next();
jobj.after('<hr />');
for (var i = 0; i < dts.length; ++i) {
var label = '';
if (dts[i][0].indexOf('call_') != 0) {
var param_info = ipa_get_param_info(dts[i][0]);
if (param_info)
label = param_info['label'];
}
if ((!label) && (dts[i].length > 1))
label = dts[i][1];
jobj.append(
_ipa_dt_template.replace('T', dts[i][0]).replace('N', label)
);
}
}
/* HTML templates for ipa_details_display() */
var _ipa_a_add_template =
'<a href="jslink" onclick="return (_ipa_add_on_click(this))" title="A">Add</a>';
/* populate definition lists with the class 'entryattrs' with entry attributes
*
* The list has to be specially crafted for this function to work properly:
* <dt> tags should have the 'title' attribute set to an LDAP attribute name
* OR to a javascript function name prefixed with 'call_', which will be given
* the <dt> object and entry_attrs as arguments.
* Example:
* <dl class="entryattrs">
* <dt title="givenname">First Name:</dt>
* <dt title="call_some_callback">Some Attribute:</dt>
* </dl>
*
* arguments:
* entry_attrs - 'result' field as returned by ipa *-show commnads
* (basically an associative array with attr:value pairs) */
function ipa_details_display(entry_attrs)
{
/* remove all <dd> tags i.e. all attribute values */
$('.entryattrs dd').remove();
/* go through all <dt> tags and pair them with newly created <dd>s */
$('.entryattrs dt').each(function () {
var jobj = $(this);
var attr = jobj.attr('title');
if (attr.indexOf('call_') == 0) {
/* title contains callback instead of attribute name */
var func = window[attr.substr(5)];
if (func)
func(jobj, entry_attrs, IPA_DETAILS_POPULATE);
else
jobj.after(_ipa_dd_first_template.replace('I', '-'));
} else {
/* title contains attribute name - default behaviour */
var value = entry_attrs[attr];
if (value) {
ipa_insert_first_dd(jobj, ipa_create_input(attr, value[0]));
for (var i = 1; i < value.length; ++i) {
jobj = jobj.next();
ipa_insert_other_dd(jobj, ipa_create_input(attr, value[i]));
}
} else {
ipa_insert_first_dd(jobj, _ipa_a_add_template.replace('A', attr));
}
}
});
}
var _ipa_dd_first_template = '<dd class="first">I</dd>';
function ipa_insert_first_dd(jobj, content)
{
jobj.after(_ipa_dd_first_template.replace('I', content));
}
var _ipa_dd_other_template = '<dd class="other">I</dd>';
function ipa_insert_other_dd(jobj, content)
{
jobj.after(_ipa_dd_other_template.replace('I', content));
}
/* mapping of parameter types to handlers used to create inputs */
var _ipa_param_type_2_handler_map = {
'Str': _ipa_create_text_input,
'Int': _ipa_create_text_input,
'Bool': _ipa_create_text_input,
};
/* create an HTML element for displaying/editing an attribute
* arguments:
* attr - LDAP attribute name
* value - the attributes value */
function ipa_create_input(attr, value)
{
var param_info = ipa_get_param_info(attr);
if (!param_info) {
/* no information about the param is available, default to text input */
return (
_ipa_create_text_input(attr, value, null) +
_ipa_create_remove_link(attr, null)
);
}
/* check if the param value can be modified */
if (param_info['primary_key'] || ('no_update' in param_info['flags']))
return (value.toString());
/* call handler by param class */
var handler = _ipa_param_type_2_handler_map[param_info['class']];
if (handler) {
return (
handler(attr, value, param_info) +
_ipa_create_remove_link(attr, param_info)
);
}
/* no handler for this type? don't allow modification */
return (value.toString());
}
/* HTML template for _ipa_create_remove_link() */
var _ipa_a_remove_template =
'<a href="jslink" onclick="return (_ipa_remove_on_click(this))" title="A">Remove</a>';
/* creates a Remove link for deleting attribute values */
function _ipa_create_remove_link(attr, param_info)
{
if (!param_info)
return (_ipa_a_remove_template.replace('A', attr));
/* check if the param is required or of the Password type
* if it is, then we don't want people to be able to remove it */
if ((param_info['required']) || (param_info['class'] == 'Password'))
return ('');
return (_ipa_a_remove_template.replace('A', attr));
}
/* HTML template for _ipa_create_text_input() */
var _ipa_input_text_template =
'<input type="text" name="A" value="V" />';
/* creates a input box for editing a string attribute */
function _ipa_create_text_input(attr, value, param_info)
{
return (
_ipa_input_text_template.replace('A', attr).replace(
'V', value.toString()
)
);
}
function ipa_details_reset()
{
if (ipa_details_cache)
ipa_details_display(ipa_details_cache);
}
/* Event handlers */
function _ipa_add_on_click(obj)
{
var jobj = $(obj);
var par = jobj.parent();
par.append(ipa_create_input(jobj.attr('title'), ''));
jobj.next('input').focus();
jobj.remove();
return (false);
}
function _ipa_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(_ipa_a_add_template.replace('A', attr));
}
return (false);
}
var qs = ipa_parse_qs();
/* "Top-level" code */
function load_object(body,obj)
{
if (!qs['pkey'])
return;
ipa_details_init(obj);
$('#butreset').click(reset_on_click);
$('#butupdate').click(update_on_click);
ipa_details_load(qs['pkey'], on_win);
$('h1').text('Managing user: ' + qs['pkey']);
}
function on_win(data, textStatus, xhr)
{
if (data['error'])
alert(data['error']['message']);
}
function reset_on_click()
{
if (ipa_details_cache)
ipa_details_display(ipa_details_cache);
return (false);
}
function update_on_click()
{
ipa_details_update(qs['pkey'], on_win);
return (false);
}
/* H2 expand/collapse */
function _h2_on_click(obj)
{
var jobj = $(obj);
var txt = jobj.text().replace(/^\s*/, '');
if (txt.charCodeAt(0) == 8722) {
obj.dl = jobj.next().detach();
jobj.text('+' + txt.substr(1));
} else {
if (obj.dl)
obj.dl.insertAfter(obj);
jobj.text(
String.fromCharCode(8722) + txt.substr(1)
);
}
}
/* Account status Toggle button */
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);
}
function on_lock_win(data, textStatus, xhr)
{
if (data['error']) {
alert(data['error']['message']);
return;
}
var jobj = $('a[title=Active]');
if (jobj.length) {
if (ipa_details_cache) {
var memberof = ipa_details_cache['memberof'];
if (memberof) {
memberof.push(
'cn=inactivated,cn=account inactivation'
);
} else {
memberof = ['cn=inactivated,cn=account inactivation'];
}
ipa_details_cache['memberof'] = memberof;
a_status(jobj.parent().prev(), ipa_details_cache);
jobj.parent().remove()
}
return;
}
var jobj = $('a[title=Inactive]');
if (jobj.length) {
if (ipa_details_cache) {
var memberof = ipa_details_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 = [];
}
ipa_details_cache['memberof'] = memberof;
a_status(jobj.parent().prev(), ipa_details_cache);
jobj.parent().remove();
}
return;
}
}
/* ATTRIBUTE CALLBACKS */
var toggle_temp = 'S <a href="jslink" onclick="return (toggle_on_click(this))" title="S">Toggle</a>';
function a_status(jobj, result, mode)
{
if (mode != IPA_DETAILS_POPULATE)
return;
var memberof = result['memberof'];
if (memberof) {
for (var i = 0; i < memberof.length; ++i) {
if (memberof[i].indexOf('cn=inactivated,cn=account inactivation') != -1) {
var t = toggle_temp.replace(/S/g, 'Inactive');
ipa_insert_first_dd(jobj, t);
return;
}
}
}
ipa_insert_first_dd(jobj, toggle_temp.replace(/S/g, 'Inactive'));
}
var pwd_temp = '<a href="jslink" onclick="return (resetpwd_on_click(this))" title="A">Reset Password</a>';
function a_password(jobj, result, mode)
{
if (mode == IPA_DETAILS_POPULATE)
ipa_insert_first_dd(jobj, pwd_temp.replace('A', 'userpassword'));
}
var select_temp = '<select title="st"></select>';
var option_temp = '<option value="V">V</option>';
var states = [
'AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FM',
'FL', 'GA', 'GU', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA',
'ME', 'MH', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV',
'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PW',
'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VI', 'VA',
'WA', 'WV', 'WI', 'WY', '',
];
function a_st(jobj, result, mode)
{
if (mode != IPA_DETAILS_POPULATE)
return;
var next = jobj.next();
next.css('clear', 'none');
next.css('width', '70px');
ipa_insert_first_dd(jobj, select_temp);
var sel = jobj.next().children().first();
for (var i = 0; i < states.length; ++i)
sel.append(option_temp.replace(/V/g, states[i]));
var st = result['st'];
if (st)
sel.val(st);
else
sel.val('');
}

View File

@ -0,0 +1,32 @@
<script type="text/javascript">
$(document).ready(function(){
load_object($('body'),'group');
});
</script>
<h1>Managing group:</h1>
<div id="buttons">
<a href="dummy"><img id="butreset" src="but-reset.png" alt="Reset" /></a>
<a href="dummy"><img id="butupdate" src="but-update.png" alt="Update" /></a>
</div>
<ul id="viewtype">
<li id="viewcaption">View:</li>
<li>
<img src="but-selected.png" alt="" />
Personal Details
</li>
<li>
<img src="but-unselected.png" alt="" />
<a href="memberof?pkey=${pkey}">Memberships</a>
</li>
</ul>
<hr />
<h2 onclick="h2_on_click(this)">&#8722; Group Details</h2>
<dl id="identity" class="entryattrs">
<dt title="cn">Group Name:</dt>
<dt title="description">Description:</dt>
<dt title="gidnumber">GID</dt>
</dl>
<hr />

41
install/static/group.js Normal file
View File

@ -0,0 +1,41 @@
function setupGroup(facet){
if (facet == "details"){
setupGroupDetails();
}else{
setupGroupSearch();
}
}
function setupGroupDetails(){
$('#search').css("visibility","hidden");
$('#content').css("visibility","visible");
$('#content').load("group-details.inc");
sampleData = "sampledata/groupshow.json";
}
function setupGroupSearch(){
var columns = [
{title:"Group Name", column:"cn",render: function(current,cell){
renderDetailColumn(current,cell,current[this.column],"group");
}},
{title:"GID", column:"gidnumber",render: renderSimpleColumn},
{title:"Description", column:"description",render: renderSimpleColumn}
];
var groupSearchForm = new SearchForm("group", "find", columns);
$("#query").unbind();
$("#query").click(function(){
sampleData = "sampledata/grouplist.json";
executeSearch(groupSearchForm);
});
$("#new").unbind();
$("#new").click( function() {
alert("New Group...");
});
}

253
install/static/groupmeta.js Normal file
View File

@ -0,0 +1,253 @@
var PluginData = {
"primary_key": "cn",
"default_attributes": [
"cn",
"description",
"gidnumber",
"member",
"memberof"
],
"object_name_plural": "groups",
"container_dn": "cn=groups,cn=accounts",
"object_class_config": "ipagroupobjectclasses",
"hidden_attributes": [
"objectclass",
"aci"
],
"uuid_attribute": "ipauniqueid",
"label": "User Groups",
"methods": [
"add",
"add_member",
"del",
"find",
"mod",
"remove_member",
"show"
],
"object_name": "group",
"takes_params": [
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "name",
"primary_key": true,
"name": "cn",
"default": null,
"doc": "Group name",
"required": true,
"flags": [],
"label": "Group name",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "desc",
"primary_key": false,
"name": "description",
"default": null,
"doc": "Group description",
"required": true,
"flags": [],
"label": "Description",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"include": null,
"cli_name": "gid",
"primary_key": false,
"minvalue": null,
"doc": "GID (use this option to set it manually)",
"required": false,
"flags": [],
"label": "GID",
"default": null,
"autofill": false,
"multivalue": false,
"attribute": false,
"query": false,
"maxvalue": null,
"cli_short_name": null,
"type": "int",
"class": "Int",
"name": "gidnumber"
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "member_group",
"primary_key": false,
"name": "member_group",
"default": null,
"doc": "Member groups",
"required": false,
"flags": [
"no_update",
"no_create",
"no_search"
],
"label": "Member groups",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "member_user",
"primary_key": false,
"name": "member_user",
"default": null,
"doc": "Member users",
"required": false,
"flags": [
"no_update",
"no_create",
"no_search"
],
"label": "Member users",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "member",
"primary_key": false,
"name": "member",
"default": null,
"doc": "Failed members",
"required": false,
"flags": [
"no_update",
"no_create",
"no_search"
],
"label": "Failed members",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "user",
"primary_key": false,
"name": "user",
"default": null,
"doc": "Users",
"required": false,
"flags": [
"no_update",
"no_create",
"no_search"
],
"label": "Users",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "group",
"primary_key": false,
"name": "group",
"default": null,
"doc": "Groups",
"required": false,
"flags": [
"no_update",
"no_create",
"no_search"
],
"label": "Groups",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
}
],
"attribute_members": {
"member": [
"user",
"group"
],
"memberof": [
"group",
"netgroup",
"rolegroup",
"taskgroup"
]
},
"parent_object": "",
"object_class": [
"ipausergroup"
],
"name": "group"
}
ipa_objs['group'] = PluginData;

38
install/static/host.js Normal file
View File

@ -0,0 +1,38 @@
function setupHost(facet){
if (facet == "details"){
setupHostDetails();
}else{
setupHostSearch();
}
}
function setupHostDetails(){
var detailsForm = new DetailsForm();
}
function setupHostSearch(){
sampleData = "sampledata/hostlist.json";
var columns = [
{title:"Host",column:"fqdn",render: function(current,cell){
renderDetailColumn(current,cell,current[this.column],"group");
}},
{title:"Comment", column: "description", render: renderSimpleColumn},
{title:"Enrolled?", render: renderUnknownColumn},
{title:"Manages?", render: renderUnknownColumn}
];
var hostSearchForm = new SearchForm("host", "find", columns);
$("#query").unbind();
$("#query").click(function(){
sampleData = "sampledata/hostlist.json";
executeSearch(hostSearchForm);
});
$("#new").unbind();
$("#new").click( function() {
alert("New Host...");
});
}

View File

@ -0,0 +1,35 @@
function setupHostgroup(facet){
if (facet == "details"){
setupHostgroupDetails();
}else{
setupHostgroupSearch();
}
}
function setupHostgroupDetails(){
var detailsForm = new DetailsForm();
}
function setupHostgroupSearch(){
var columns = [
{title:"Hostgroup",column:"cn",render: function(current,cell){
renderDetailColumn(current,cell,current[this.column],"hostgroup");
}},
{title:"Description", column:"description",render: renderSimpleColumn}];
var hostgroupSearchForm = new SearchForm("hostgroup", "find", columns);
$("#query").unbind();
$("#query").click(function(){
sampleData = "sampledata/hostgrouplist.json";
executeSearch(hostgroupSearchForm);
});
$("#new").unbind();
$("#new").click( function() {
alert("New Hostgroup...");
});
}

View File

@ -0,0 +1,69 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>IPA: Identity Policy Audit</title>
<link href="ipa.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.cookie.js"></script>
<script type="text/javascript" src="ipa.js" />
<script type="text/javascript" src="pageparams.js" />
<script type="text/javascript" src="navigation.js" />
<script type="text/javascript" src="sampledata/develop.js" />
<script type="text/javascript" src="search.js" />
<script type="text/javascript" src="details.js" />
<script type="text/javascript" src="user.js" />
<script type="text/javascript" src="usermeta.js" />
<script type="text/javascript" src="group.js" />
<script type="text/javascript" src="groupmeta.js" />
<script type="text/javascript" src="host.js" />
<script type="text/javascript" src="hostgroup.js" />
<script type="text/javascript" src="netgroup.js" />
<script type="text/javascript">
$(document).ready(function(){
buildNavigation();
});
</script>
</head>
<body>
<div class="header" >
<span class="logo">
<a href="#"><img src="ipalogo.png" /></a>
</span>
<span class="LoggedInAs" id="loggedinas">
Logged in as <strong>hardcoded@FREEIP.ORG</strong>
</span>
</div>
<div id="navigation">
<div id="main-nav" />
<div id="sub-nav">Edit: </div>
</div>
<div id="content" border="1" style="visibility:hidden" >
</div>
<div id="search" style="visibility:hidden">
<div class="searchControls" >
<span class="filter" >
<input id="queryFilter" type="text"/>
<input id="query" type="submit" value="find" />
<input id="new" type="submit" value="new" />
</span>
<span class="filter" id="searchButtons" />
</div>
<table id="searchResultsTable" class="SearchResults" >
<thead></thead>
<tfoot></tfoot>
<tbody></tbody>
</table>
</div>
</body>
</html>

271
install/static/ipa.css Normal file
View File

@ -0,0 +1,271 @@
/* Authors:
* Pavel Zuna <pzuna@redhat.com>
* Adam Young <ayoung@redhat.com>
*
* Copyright (C) 2010 Red Hat
*/
body {
font-family: sans-serif;
font-size: 14pt;
}
a {
text-decoration: none;
border: 0;
}
a img { border-width: 0; }
a:link, a:visited {
text-decoration: none;
border: 0;
}
/* ---- Header ---- */
div.header {
background-image: url(header_background.png);
background: -moz-linear-gradient(top, #65646e, #1f1f1f);
background-color: #1f1f1f;
height: 70px;
}
div.header span.LoggedInAs {
color: #fff;
padding-right: 10px;
line-height: 35px;
float: right;
}
div.header div.logo {
float: left;
padding: 10px 10px 0 10px;
}
div.header div.logo img {
border: 0;
}
div#view {
bottom: 0;
left: 0;
overflow: auto;
position: fixed;
right: 0;
top: 0;
}
div#header {
background: -moz-linear-gradient(top, #65646e, #1f1f1f);
background-color: #1f1f1f;
height: 70px;
}
div#header div#logo img {
border: 0;
}
div#header div#loggedinas {
color: #fff;
font-size: 12pt;
font-weight: bold;
line-height: 35px;
padding-right: 10px;
text-align: right;
}
div#header div#loggedinas a {
color: #fff;
text-decoration: underline;
}
h1 {
font-size: 26pt;
font-weight: bold;
margin-bottom: 30px;
margin-left: 15px;
margin-top: 18px;
}
div#content {
float: left;
}
div#content ul#viewtype {
padding-left: 20px;
}
div#content ul#viewtype li {
color: #656565;
display: inline;
font-weight: bold;
list-style-type: none;
padding-right: 20px;
}
div#content ul#viewtype li#viewcaption {
color: #000;
padding-right: 10px;
}
div#content ul#viewtype li img {
vertical-align: middle;
}
div#content ul#viewtype li a {
font-weight: normal;
}
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;
}
dl.entryattrs {
clear: both;
margin-left: 15px;
margin-top: 18px;
white-space: nowrap;
}
dl.entryattrs dt {
clear: left;
float: left;
padding-bottom: 18px;
padding-right: 18px;
text-align: right;
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;
}
dl.entryattrs input {
margin-right: 5px;
}
div#backtotop {
margin-left: 20px;
margin-right: 20px;
text-align: right;
}
/*Navigation */
span.sub-nav-off > a:link, span.sub-nav-off > a:visited{
color:white;
}
span.main-nav-off > a:link, span.main-nav-off > a:visited{
color:white;
}
#main-nav{
background-image: url(Mainnav-background.png);
font-size: 100%;
}
span.main-nav-on{
background-image: url(Mainnav-ontab.png);
}
span.main-nav-off{
background-image: url(Mainnav-offtab.png);
}
span.main-separator{
background: #333339;
padding:1px;
}
#sub-nav{
background-image: url(Subnav-background.png);
padding:5px;
color: white;
font-size: 80%;
}
span.sub-nav-on{
background-image: url(Subnav-onbutton.png);
margin: 10px;
}
span.sub-nav-off{
background-image: url(Subnav-offbutton.png);
margin: 10px;
}
/* Search */
#search{
float: left;
width: 80%;
margin: 10px;
padding: 10px;
background: #e8e8e8;
}
div.searchControls{
background:#a5a5a5;
}
#searchResultsTable{
padding: 0px;
width:100%;
border-width: thin;
border-style: solid;
border-color: black;
}
#searchResultsTable > a:link,a:visted{
color:black;
}
#searchResultsTable th{
background-color:gray;
color:white;
}
#searchResultsTable tr:nth-child(even){
background-color:#CCC;
}
#searchResultsTable tr:nth-child(odd){
background-color:#FFF;
}

128
install/static/ipa.js Normal file
View File

@ -0,0 +1,128 @@
/* Authors:
* Pavel Zuna <pzuna@redhat.com>
*
* Copyright (C) 2010 Red Hat
* see file 'COPYING' for use and warranty information
*
* 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 only
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//the develop.js file that follows will set this to true.
//that file should only exist in the source file system
//and should not get deployed to the web server
var useSampleData = false;
//Maximum number of records to return on any query.
var sizelimit=100;
/* IPA JSON-RPC helper */
/* JSON-RPC ID counter */
var ipa_jsonrpc_id = 0;
/* IPA objects data in JSON format */
var ipa_objs = {};
/* initialize the IPA JSON-RPC helper
* arguments:
* url - JSON-RPC URL to use (optional) */
function ipa_init(url)
{
}
/* call an IPA command over JSON-RPC
* arguments:
* name - name of the command or method if objname is set
* args - list of positional arguments, e.g. [username]
* options - dict of options, e.g. {givenname: 'Pavel'}
* win_callback - function to call if the JSON request succeeds
* fail_callback - function to call if the JSON request fails
* objname - name of an IPA object (optional) */
function ipa_cmd(name, args, options, win_callback, fail_callback, objname)
{
id = ipa_jsonrpc_id++;
if (objname)
name = objname + '_' + name;
options.sizelimit = sizelimit;
var data = {
method: name,
params: [args, options],
id: id,
};
var jsonUrl = '/ipa/json';
if (useSampleData){
jsonUrl = sampleData;
}
$.ajax({
beforeSend: function(xhrObj){
xhrObj.setRequestHeader("Content-Type","application/json");
xhrObj.setRequestHeader("Accept","application/json");
},
type: "POST",
url: jsonUrl,
processData: false,
data: JSON.stringify(data),
dataType: "json",
success: win_callback,
error: fail_callback,
});
return (id);
}
/* parse query string into key:value dict
* arguments:
* qs - query string (optional) */
function ipa_parse_qs(qs)
{
var dict = {};
if (!qs)
qs = location.search.substring(1, location.search.length);
qs = qs.replace(/\+/g, ' ');
var args = qs.split('&');
for (var i = 0; i < args.length; ++i) {
var parts = args[i].split('=', 2);
var key = decodeURIComponent(parts[0]);
if (parts.length == 2)
dict[key] = decodeURIComponent(parts[1]);
else
dict[key] = key;
}
return (dict);
}
/* helper function used to retrieve information about an attribute */
function ipa_get_param_info(attr)
{
var takes_params = ipa_objs[_ipa_obj_name]['takes_params'];
if (!takes_params)
return (null);
for (var i = 0; i < takes_params.length; ++i) {
if (takes_params[i]['name'] == attr)
return (takes_params[i]);
}
return (null);
}

View File

@ -0,0 +1,96 @@
/**
* Cookie plugin
*
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
/**
* Create a cookie with the given name and value and other optional parameters.
*
* @example $.cookie('the_cookie', 'the_value');
* @desc Set the value of a cookie.
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
* @desc Create a cookie with all available options.
* @example $.cookie('the_cookie', 'the_value');
* @desc Create a session cookie.
* @example $.cookie('the_cookie', null);
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
* used when the cookie was set.
*
* @param String name The name of the cookie.
* @param String value The value of the cookie.
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
* If set to null or omitted, the cookie will be a session cookie and will not be retained
* when the the browser exits.
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
* require a secure protocol (like HTTPS).
* @type undefined
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
/**
* Get the value of a cookie with the given name.
*
* @example $.cookie('the_cookie');
* @desc Get the value of a cookie.
*
* @param String name The name of the cookie.
* @return The value of the cookie.
* @type String
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
jQuery.cookie = function(name, value, options) {
if (typeof value != 'undefined') { // name and value given, set cookie
options = options || {};
if (value === null) {
value = '';
options.expires = -1;
}
var expires = '';
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
} else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
// CAUTION: Needed to parenthesize options.path and options.domain
// in the following expressions, otherwise they evaluate to undefined
// in the packed version for some reason...
var path = options.path ? '; path=' + (options.path) : '';
var domain = options.domain ? '; domain=' + (options.domain) : '';
var secure = options.secure ? '; secure' : '';
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
} else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
};

6240
install/static/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

482
install/static/json2.js Normal file
View File

@ -0,0 +1,482 @@
/*
http://www.JSON.org/json2.js
2010-03-20
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, strict: false */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (!this.JSON) {
this.JSON = {};
}
(function () {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ?
'"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' :
'"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' :
gap ? '[\n' + gap +
partial.join(',\n' + gap) + '\n' +
mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' :
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
mind + '}' : '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());

View File

@ -0,0 +1,158 @@
function setLoggedInText(principal){
$("#loggedinas").html( "Logged in as " + principal);
}
function whoamiSuccess(response){
$.cookie("whoami", response.result.summary);
setLoggedInText(response.result.summary);
}
function unimplemented(facet){
showContent();
$('#content').append("<div>Not yet implemented.</div>");
}
function buildNavigation(){
params= getPageParams();
var tab = params["tab"];
if (!tab){
tab=$.cookie("lastpage");
}
if ( !tab ) {
tab="user";
}
var facet = params["facet"];
var siteMap = [{name:"IDENTITY",
tab:"user",
children : [
{name:"Users",tab:"user", setup: setupUser},
{name:"Groups",tab:"group",setup: setupGroup},
{name:"Hosts",tab:"host", setup: setupHost},
{name:"Hostgroups",
tab:"hostgroup",
setup: setupHostgroup},
{name:"Netgroups",tab:"netgroup", setup:setupNetgroup}
]},
{name:"POLICY", tab:"policy", setup: unimplemented},
{name:"CONFIG", tab:"config", setup: unimplemented }];
var separator = $("<span class='main-separator' />");
var currentMain = siteMap[0];
for (var i = 0 ; i < siteMap.length; i++){
current = siteMap[i];
if (i > 0){
$('#main-nav').append(separator.clone());
}
var tabClass = "main-nav-off";
if (tab == current.tab){
currentMain = current;
tabClass = "main-nav-on";
}
var span = $("<span/>", {
"class": tabClass,
id: "span-tab-"+current.tab,
});
$("<a/>",{
"id": "tab-"+current.tab,
href: "#?tab="+current.tab,
text: current.name,
click: setActiveTab
}).appendTo(span);
span.appendTo("#main-nav")
}
if (currentMain.children){
var selectedSub;
for (var i =0; i < currentMain.children.length; i++){
var currentSub = currentMain.children[i];
var tabClass = "sub-nav-off";
if (tab == currentSub.tab){
tabClass = "sub-nav-on";
selectedSub = currentSub;
}
var span = $("<span/>", {
"class": tabClass,
id: "span-subtab-"+currentSub.tab
});
$("<a/>",{
"id": "subtab-"+currentSub.tab,
href: "#?tab="+currentSub.tab,
text: currentSub.name,
click: setActiveSubtab,
}).appendTo(span);
span.appendTo("#sub-nav");
}
if (selectedSub && selectedSub.setup){
selectedSub.setup(facet);
}
}else if (currentMain && currentMain.setup){
currentMain.setup(facet);
}
sampleData = "sampledata/whoami.json";
var whoami = $.cookie("whoami");
if (whoami == null){
ipa_cmd( 'whoami', [], {}, whoamiSuccess);
}else{
setLoggedInText(whoami);
}
}
function setActiveTab(){
var setupFunctions = {
user: setupUser,
policy: unimplemented,
config: unimplemented};
var tabName = this.id.substring("tab-".length);
$(".main-nav-on").removeClass('main-nav-on').addClass("main-nav-off")
var activeTab = "#span-tab-"+tabName;
$(activeTab).removeClass('main-nav-off').addClass("main-nav-on")
setupFunctions[tabName]();
}
function setActiveSubtab(){
var setupFunctions = {
user: setupUser,
group: setupGroup,
host: setupHost,
hostgroup:setupHostgroup,
netgroup:setupNetgroup,
};
var subtabName = this.id.substring("subtab-".length);
$(".sub-nav-on").removeClass('sub-nav-on').addClass("sub-nav-off")
var active = "#span-subtab-"+subtabName;
$(active).removeClass('sub-nav-off').addClass("sub-nav-on")
setupFunctions[subtabName]();
}

View File

@ -0,0 +1,39 @@
function setupNetgroup(facet){
if (facet == "details"){
setupNetgroupDetails();
}else{
setupNetgroupSearch();
}
}
function setupNetgroupDetails(){
var detailsForm = new DetailsForm();
}
function setupNetgroupSearch(){
var columns = [
{title:"Netgroup",column:"cn",render: function(current,cell){
renderDetailColumn(current,cell,current[this.column],"netgroup");
}},
{title:"Description", column:"description",render: renderSimpleColumn}];
var netgroupSearchForm = new SearchForm("netgroup", "find", columns);
$("#query").unbind();
$("#query").click(function(){
sampleData = "sampledata/netgrouplist.json";
executeSearch(netgroupSearchForm);
});
$("#new").unbind();
$("#new").click( function() {
alert("New Netgroup...");
});
}

View File

@ -0,0 +1,15 @@
function getPageParams(){
var qsParm = new Array();
var query = window.location.search.substring(1);
var parms = query.split("&");
for (var i=0; i<parms.length; i++) {
var pos = parms[i].indexOf('=');
if (pos > 0) {
var key = parms[i].substring(0,pos);
var val = parms[i].substring(pos+1);
qsParm[key] = val;
}
}
return qsParm;
}

View File

@ -0,0 +1,3 @@
//This should not be packaged up, and so we should only get a true value when working inside the file system
useSampleData = true;

View File

@ -0,0 +1,75 @@
{
"error": null,
"id": 0,
"result": {
"count": 5,
"result": [
{
"cn": [
"admins"
],
"description": [
"Account administrators group"
],
"dn": "cn=admins,cn=groups,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com",
"gidnumber": [
"1948497956"
],
"member_user": [
"admin"
]
},
{
"cn": [
"ipausers"
],
"description": [
"Default group for all users"
],
"dn": "cn=ipausers,cn=groups,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com",
"gidnumber": [
"1948497957"
],
"member_user": [
"kfrog",
"moi"
]
},
{
"cn": [
"editors"
],
"description": [
"Limited admins who can edit other users"
],
"dn": "cn=editors,cn=groups,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com",
"gidnumber": [
"1948497958"
]
},
{
"cn": [
"deleteme"
],
"description": [
"This is a group that should go away."
],
"dn": "cn=deleteme,cn=groups,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com"
},
{
"cn": [
"testgroup"
],
"description": [
"Detlete this if you see it"
],
"dn": "cn=testgroup,cn=groups,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com",
"gidnumber": [
"1948497959"
]
}
],
"summary": "5 groups matched",
"truncated": false
}
}

View File

@ -0,0 +1,38 @@
{
"error": null,
"id": 0,
"result": {
"result": {
"cn": [
"ipausers"
],
"description": [
"Default group for all users"
],
"dn": "cn=ipausers,cn=groups,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"gidnumber": [
"1079249048"
],
"member": [
"uid=gsmile,cn=users,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"uid=kfrog,cn=users,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"uid=count123,cn=users,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com"
],
"member_user": [
"gsmile",
"kfrog",
"count123"
],
"memberof": [],
"objectclass": [
"top",
"groupofnames",
"nestedgroup",
"ipausergroup",
"posixgroup"
]
},
"summary": null,
"value": "ipausers"
}
}

View File

@ -0,0 +1,33 @@
{
"error": null,
"id": 0,
"result": {
"count": 2,
"result": [
{
"cn": [
"host-live"
],
"description": [
"Live servers"
],
"dn": "cn=host-live,cn=hostgroups,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"member": [],
"memberof": []
},
{
"cn": [
"stage-live"
],
"description": [
"Staging servers"
],
"dn": "cn=stage-live,cn=hostgroups,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"member": [],
"memberof": []
}
],
"summary": "2 hostgroups matched",
"truncated": false
}
}

View File

@ -0,0 +1,45 @@
{
"error": null,
"id": 0,
"result": {
"count": 2,
"result": [
{
"dn": "fqdn=vm-121.idm.lab.bos.redhat.com,cn=computers,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"enrolledby": [],
"fqdn": [
"vm-121.idm.lab.bos.redhat.com"
],
"krbprincipalname": [
"host/vm-121.idm.lab.bos.redhat.com@IDM.LAB.BOS.REDHAT.COM"
],
"memberof": []
},
{
"description": [
"sample host"
],
"dn": "fqdn=ayounghost1.idm.lab.bos.redhat.com,cn=computers,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"enrolledby": [],
"fqdn": [
"ayounghost1.idm.lab.bos.redhat.com"
],
"l": [
"VM-lab"
],
"memberof": [],
"nshardwareplatform": [
"kvm"
],
"nshostlocation": [
"VM-lab"
],
"nsosversion": [
"F13"
]
}
],
"summary": "2 hosts matched",
"truncated": false
}
}

View File

@ -0,0 +1,56 @@
{
"error": null,
"id": 0,
"result": {
"result": {
"cn": [
"vm-121.idm.lab.bos.redhat.com"
],
"dn": "fqdn=vm-121.idm.lab.bos.redhat.com,cn=computers,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"enrolledby": [],
"fqdn": [
"vm-121.idm.lab.bos.redhat.com"
],
"ipauniqueid": [
"b54b73a8-8ba8-11df-80bc-00163e26b89e"
],
"krbextradata": [
{
"__base64__": "AAKOoTdMYWRtaW4vYWRtaW5ASURNLkxBQi5CT1MuUkVESEFULkNPTQA="
}
],
"krblastpwdchange": [
"20100709222414Z"
],
"krbpasswordexpiration": [
"19700101000000Z"
],
"krbprincipalname": [
"host/vm-121.idm.lab.bos.redhat.com@IDM.LAB.BOS.REDHAT.COM"
],
"krbticketflags": [
"0"
],
"managedby": [
"fqdn=vm-121.idm.lab.bos.redhat.com,cn=computers,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com"
],
"memberof": [],
"objectclass": [
"top",
"ipaobject",
"nshost",
"ipahost",
"ipaservice",
"pkiuser",
"krbprincipalaux",
"krbprincipal",
"krbticketpolicyaux"
],
"serverhostname": [
"vm-121"
]
},
"summary": null,
"value": "vm-121.idm.lab.bos.redhat.com"
}
}

View File

@ -0,0 +1,56 @@
{
"error": null,
"id": 0,
"result": {
"count": 2,
"result": [
{
"cn": [
"net-stage"
],
"description": [
"staging servers"
],
"dn": "ipauniqueid=f6ee9f40-9456-11df-973b-00163e26b89e,cn=ng,cn=alt,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"memberhost": [],
"memberof": [],
"memberuser": [
"cn=muppets,cn=groups,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com"
],
"memberuser_group": [
"muppets"
],
"nisdomainname": [
"idm.lab.bos.redhat.com"
]
},
{
"cn": [
"net-live"
],
"description": [
"live servers"
],
"dn": "ipauniqueid=f763e426-9456-11df-934d-00163e26b89e,cn=ng,cn=alt,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"memberhost": [
"cn=host-live,cn=hostgroups,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com"
],
"memberhost_hostgroup": [
"host-live"
],
"memberof": [],
"memberuser": [
"cn=muppets,cn=groups,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com"
],
"memberuser_group": [
"muppets"
],
"nisdomainname": [
"idm.lab.bos.redhat.com"
]
}
],
"summary": null,
"truncated": false
}
}

View File

@ -0,0 +1,246 @@
{
"error": null,
"id": 0,
"result": {
"count": 4,
"result": [
{
"cn": [
"Administrator"
],
"dn": "uid=admin,cn=users,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com",
"gecos": [
"Administrator"
],
"gidnumber": [
"444194797"
],
"homedirectory": [
"/home/admin"
],
"krblastpwdchange": [
"20100614200400Z"
],
"krbpasswordexpiration": [
"20100912200400Z"
],
"krbprincipalname": [
"admin@AYOUNG.BOSTON.DEVEL.REDHAT.COM"
],
"loginshell": [
"/bin/bash"
],
"memberof_group": [
"admins"
],
"memberof_rolegroup": [
"replicaadmin"
],
"memberof_taskgroup": [
"managereplica",
"deletereplica"
],
"objectclass": [
"top",
"person",
"posixaccount",
"krbprincipalaux",
"krbticketpolicyaux",
"inetuser"
],
"sn": [
"Administrator"
],
"uid": [
"admin"
],
"uidnumber": [
"444194797"
]
},
{
"cn": [
"Kermit Frog"
],
"dn": "uid=kfrog,cn=users,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com",
"gecos": [
"Some of my best friends are Geckos"
],
"gidnumber": [
"444194798"
],
"givenname": [
"Kermit"
],
"homedirectory": [
"/home/kfrog"
],
"ipauniqueid": [
"89dc1f68-77f3-11df-afb7-525400ed2d11"
],
"krbprincipalname": [
"kfrog"
],
"loginshell": [
"/bin/sh"
],
"mail": [
"kfrog@pbs.org"
],
"memberof_group": [
"ipausers"
],
"objectclass": [
"top",
"person",
"organizationalperson",
"inetorgperson",
"inetuser",
"posixaccount",
"krbprincipalaux",
"krbticketpolicyaux",
"radiusprofile",
"ipaobject"
],
"sn": [
"Frog"
],
"street": [
"55 Seasame Street"
],
"title": [
"Reporter"
],
"uid": [
"kfrog"
],
"uidnumber": [
"444194798"
]
},
{
"cn": [
"Oscar Grouch"
],
"dn": "uid=scram,cn=users,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com",
"gecos": [
"scram"
],
"gidnumber": [
"444194798"
],
"givenname": [
"Oscar"
],
"homedirectory": [
"/home/trash"
],
"ipauniqueid": [
"adba909c-77f3-11df-ae3f-525400ed2d11"
],
"krbprincipalname": [
"scram"
],
"loginshell": [
"/bin/sh"
],
"mail": [
"oscar@pbs.org"
],
"memberof_group": [
"ipausers"
],
"objectclass": [
"top",
"person",
"organizationalperson",
"inetorgperson",
"inetuser",
"posixaccount",
"krbprincipalaux",
"krbticketpolicyaux",
"radiusprofile",
"ipaobject"
],
"sn": [
"Grouch"
],
"street": [
"123a Sesame Street"
],
"title": [
"Sys Admin"
],
"uid": [
"scram"
],
"uidnumber": [
"444194799"
]
},
{
"cn": [
"Sid Monster"
],
"dn": "uid=cookie,cn=users,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com",
"gecos": [
"cookie"
],
"gidnumber": [
"444194798"
],
"givenname": [
"Sid"
],
"homedirectory": [
"cookie"
],
"ipauniqueid": [
"c7d10507-77f3-11df-ac53-525400ed2d11"
],
"krbprincipalname": [
"cookie"
],
"loginshell": [
"/bin/sh"
],
"mail": [
"cookie@pbs.org"
],
"memberof_group": [
"ipausers"
],
"objectclass": [
"top",
"person",
"organizationalperson",
"inetorgperson",
"inetuser",
"posixaccount",
"krbprincipalaux",
"krbticketpolicyaux",
"radiusprofile",
"ipaobject"
],
"sn": [
"Monster"
],
"street": [
"123 Sesame Street"
],
"title": [
"Chef"
],
"uid": [
"cookie"
],
"uidnumber": [
"444194800"
]
}
],
"summary": "4 users matched",
"truncated": false
}
}

View File

@ -0,0 +1,71 @@
{
"error": null,
"id": 0,
"result": {
"result": {
"cn": [
"Kermit Frog"
],
"dn": "uid=kfrog,cn=users,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com",
"gecos": [
"kfrog"
],
"gidnumber": [
"1079249051"
],
"givenname": [
"Kermit"
],
"homedirectory": [
"/home/kfrog"
],
"ipauniqueid": [
"41bcf085-8baa-11df-8155-00163e26b89e"
],
"krbprincipalname": [
"kfrog@IDM.LAB.BOS.REDHAT.COM"
],
"loginshell": [
"/bin/sh"
],
"mail": [
"kfrog@redhat.com"
],
"memberof": [
"cn=ipausers,cn=groups,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com",
"cn=muppets,cn=groups,cn=accounts,dc=ayoung,dc=boston,dc=devel,dc=redhat,dc=com"
],
"memberof_group": [
"ipausers",
"muppets"
],
"mepmanagedentry": [
"cn=kfrog,cn=groups,cn=accounts,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com"
],
"objectclass": [
"top",
"person",
"organizationalperson",
"inetorgperson",
"inetuser",
"posixaccount",
"krbprincipalaux",
"krbticketpolicyaux",
"radiusprofile",
"ipaobject",
"mepOriginEntry"
],
"sn": [
"Frog"
],
"uid": [
"kfrog"
],
"uidnumber": [
"1079249051"
]
},
"summary": null,
"value": "kfrog"
}
}

View File

@ -0,0 +1,7 @@
{
"error": null,
"id": 0,
"result": {
"summary": "admin@AYOUNG.BOSTON.DEVEL.REDHAT.COM"
}
}

127
install/static/search.js Normal file
View File

@ -0,0 +1,127 @@
//useSampleData is defined in index.xhtml. Work around for development
var sampleData;
function clearOld(){
$('#searchResultsTable thead').html("");
$('#searchResultsTable tfoot').html("");
$('#searchResultsTable tbody').find("tr").remove();
$('#content').html("");
}
function showSearch(){
clearOld();
$('#search').css("visibility","visible");
$('#content').css("visibility","hidden");
$('#search').css("display","block");
$('#content').css("display","none");
}
function showContent(){
clearOld();
$('#search').css("visibility","hidden");
$('#content').css("visibility","visible");
$('#search').css("display","none");
$('#content').css("display","block");
}
//Columns is an array of items in the form
// {title, column, render}
//title: the the value that goes at the head of the column
//filed: the column in the response used for populating the value
//render: the function used to generate cell.innerHtml
// it is in the form:
// render(current, cell)
// current is the row in response
// cell is the td in the table
//These are helper functions, either assigned to the rneder method
//Or called from a thin wrapper render method
function renderSimpleColumn(current,cell){
cell.innerHTML = current[this.column];
}
function renderUnknownColumn(current,cell){
cell.innerHTML = "Unknown";
}
function renderDetailColumn(current,cell,pkey,obj){
link = document.createElement("a");
link.href= "?tab=" +obj+"&facet=details&pkey="+pkey;
link.innerHTML = pkey;
cell.appendChild(link);
}
function SearchForm(obj, method, cols){
this.buildColumnHeaders = function (){
var columnHeaders = document.createElement("tr");
for (var i =0 ; i != this.columns.length ;i++){
var th = document.createElement("th");
th.innerHTML = this.columns[i].title;
columnHeaders.appendChild(th);
}
$('#searchResultsTable thead:last').append(columnHeaders);
}
this.renderResultRow = function(current){
var row = document.createElement("tr");
var cell;
var link;
for(var index = 0 ; index < this.columns.length; index++){
this.columns[index].render(current, row.insertCell(-1));
}
return row;
}
this.searchSuccess = function (json){
if (json.result.truncated){
$("#searchResultsTable tfoot").html("More than "+sizelimit+" results returned. First "+ sizelimit+" results shown." );
}else{
$("#searchResultsTable tfoot").html(json.result.summary);
}
$("#searchResultsTable tbody").find("tr").remove();
for (var index = 0; index != json.result.result.length; index++){
var current = json.result.result[index];
$('#searchResultsTable tbody:last').append(this.renderResultRow(current));
}
}
this.obj = obj;
this.method = method;
this.columns = cols;
showSearch();
$('#searchResultsTable thead').html("");
$('#searchResultsTable tbody').html("");
$("#new").click(function(){
location.href="?tab="+obj+"&facet=add";
});
this.buildColumnHeaders();
}
executeSearch = function(searchForm){
var queryFilter = $("#queryFilter").val();
$('#searchResultsTable tbody').html("");
ipa_cmd(searchForm.method,
[queryFilter],
{"all":"true"},
function(json){
searchForm.searchSuccess(json);
},
function(json){
alert("Search Failed");
},searchForm.obj);
}

View File

@ -0,0 +1,25 @@
<script type="text/javascript">
$(document).ready(function(){
$("#addEdit").click(addEditUser);
$("#addAnother").click(addAnotherUser);
/*this is a placeholder. We will need to I18N */
$("#content h1").text( "Add a User.");
});
</script>
<div id="buttons">
<span>Add and :</span>
<input id="addEdit" type='button' value="Edit" />
<span>|</span>
<input id="addAnother" type='button' value="Add Another" />
</div>
<h1></h1>
<dl class="entryattrs">
<dt title="login">login</dt>
<dd><input id='login' type='text' value=''/></dd>
<dt title ="firstname">First Name</dt>
<dd><input id='firstname' type='text' value=''/></dd>
<dt title="lastname">Last Name</dt>
<dd><input id='lastname' type='text' value=''/></dd>
</dl>

View File

@ -0,0 +1,267 @@
<script type="text/javascript">
//<![CDATA[
var qs = ipa_parse_qs();
var def_lists = [
['identity', 'Identity Details', [
['title', 'Title'],
['givenname', 'First Name'],
['sn', 'Last Name'],
['cn', 'Full Name'],
['displayname', 'Dispaly Name'],
['initials', 'Initials']
]
],
['account', 'Account Details', [
['call_a_status', 'Account Status'],
['uid', 'Login'],
['call_a_password', 'Password'],
['uidnumber', 'UID'],
['gidnumber', 'GID'],
['homedirectory', 'homedirectory']
]
],
['contact', 'Contact Details', [
['mail', 'E-mail Address'],
['call_a_numbers', 'Numbers']
]
],
['address', 'Mailing Address', [
['street', 'Address'],
['location', 'City'],
['call_a_st', 'State'],
['postalcode', 'ZIP']
]
],
['employee', 'Employee Information', [
['ou', 'Org. Unit'],
['call_a_manager', 'Manager']
]
],
['misc', 'Misc. Information', [
['carlicense', 'Car License']
]
]
];
/* "Top-level" code */
function load_object(body)
{
ipa_details_init('user');
ipa_details_create(def_lists);
$('#butreset').click(reset_on_click);
$('#butupdate').click(update_on_click);
if (qs['principal']) {
ipa_cmd(
'find', [], {'krbprincipalname': qs['principal']},
on_win_find, null, 'user'
);
return;
}
if (!qs['pkey'])
return;
ipa_details_load(qs['pkey'], on_win);
$('h1').text('Managing user: ' + qs['pkey']);
}
function on_win(data, textStatus, xhr)
{
if (data['error'])
alert(data['error']['message']);
}
function on_win_find(data, textStatus, xhr)
{
if (data['error']) {
alert(data['error']['message']);
return;
}
var result = data.result.result;
if (result.length == 1) {
var entry_attrs = result[0];
qs['pkey'] = entry_attrs['uid'][0];
ipa_details_load(qs['pkey'], on_win);
$('h1').text('Managing user: ' + qs['pkey']);
}
}
function reset_on_click()
{
ipa_details_reset();
return (false);
}
function update_on_click()
{
ipa_details_update(qs['pkey'], on_win);
return (false);
}
/* Account status Toggle button */
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,
ipa_objs['user']['name']
);
} else {
ipa_cmd(
'unlock', [qs['pkey']], {}, on_lock_win, on_fail,
ipa_objs['user']['name']
);
}
return (false);
}
function on_lock_win(data, textStatus, xhr)
{
if (data['error']) {
alert(data['error']['message']);
return;
}
var jobj = $('a[title=Active]');
if (jobj.length) {
if (ipa_details_cache) {
var memberof = ipa_details_cache['memberof'];
if (memberof) {
memberof.push(
'cn=inactivated,cn=account inactivation'
);
} else {
memberof = ['cn=inactivated,cn=account inactivation'];
}
ipa_details_cache['memberof'] = memberof;
a_status(jobj.parent().prev(), ipa_details_cache);
jobj.parent().remove()
}
return;
}
var jobj = $('a[title=Inactive]');
if (jobj.length) {
if (ipa_details_cache) {
var memberof = ipa_details_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 = [];
}
ipa_details_cache['memberof'] = memberof;
a_status(jobj.parent().prev(), ipa_details_cache);
jobj.parent().remove();
}
return;
}
}
/* ATTRIBUTE CALLBACKS */
var toggle_temp = 'S <a href="jslink" onclick="return (toggle_on_click(this))" title="S">Toggle</a>';
function a_status(jobj, result, mode)
{
if (mode != IPA_DETAILS_POPULATE)
return;
var memberof = result['memberof'];
if (memberof) {
for (var i = 0; i < memberof.length; ++i) {
if (memberof[i].indexOf('cn=inactivated,cn=account inactivation') != -1) {
var t = toggle_temp.replace(/S/g, 'Inactive');
ipa_insert_first_dd(jobj, t);
return;
}
}
}
ipa_insert_first_dd(jobj, toggle_temp.replace(/S/g, 'Inactive'));
}
var pwd_temp = '<a href="jslink" onclick="return (resetpwd_on_click(this))" title="A">Reset Password</a>';
function a_password(jobj, result, mode)
{
if (mode == IPA_DETAILS_POPULATE)
ipa_insert_first_dd(jobj, pwd_temp.replace('A', 'userpassword'));
}
var select_temp = '<select title="st"></select>';
var option_temp = '<option value="V">V</option>';
var states = [
'AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FM',
'FL', 'GA', 'GU', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA',
'ME', 'MH', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV',
'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PW',
'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VI', 'VA',
'WA', 'WV', 'WI', 'WY', '',
];
function a_st(jobj, result, mode)
{
if (mode != IPA_DETAILS_POPULATE)
return;
var next = jobj.next();
next.css('clear', 'none');
next.css('width', '70px');
ipa_insert_first_dd(jobj, select_temp);
var sel = jobj.next().children().first();
for (var i = 0; i < states.length; ++i)
sel.append(option_temp.replace(/V/g, states[i]));
var st = result['st'];
if (st)
sel.val(st);
else
sel.val('');
}
//]]>
$(document).ready(function(){
sampleData = "sampledata/usershow.json";
load_object($('body'),'user');
});
</script>
<h1>Managing user:</h1>
<div id="buttons">
<a href="dummy"><img id="butreset" src="but-reset.png" alt="Reset" /></a>
<a href="dummy"><img id="butupdate" src="but-update.png" alt="Update" /></a>
</div>
<ul id="viewtype">
<li id="viewcaption">View:</li>
<li>
<img src="but-selected.png" alt="" />
Identity Details
</li>
<li>
<img src="but-unselected.png" alt="" />
<a href="memberof?pkey=${pkey}">Memberships</a>
</li>
</ul>
<hr />
<div id="backtotop">
<a href="#viewtype">Back to Top</a>
</div>

View File

@ -0,0 +1,49 @@
<script type="text/javascript">
$(document).ready( initializeUserGroupEnrollments);
</script>
<h1>Enroll in Groups</h1>
<form>
<div style="border-width:1px">
<div >
<input type="text"/>
<input id="query" type="button" value="Find Groups"/>
<span style="float:right">
<input id="cancelEnrollGroups" type="button" value="Cancel"/>
<input id="enrollGroups" type="button" value="Enroll"/>
</span>
</div>
<div id="results" style="border: 2px solid rgb(0, 0, 0); position:relative; height:200px;" >
<div style="float:left;">
<div>Groups</div>
<select id="grouplist" width="150px" size="10" multiple="true" >
</select>
</div>
<div style="float:left;">
<p><input id="removeFromList" type="button" value="&lt;&lt;"/> </p>
<p><input id="addToList" type="button" value="&gt;&gt;"/></p>
</div>
<div style="float:left;">
<div>Prospective Enrollments</div>
<select id="enrollments" width="150px" size="10" multiple="true" >
</select>
</div>
</div>
<hr/>
<div>Message Area</div>
<hr/>
<div>
<span style="float:left">
<p>*Enter Group Names and Press Groups</p>
<p>*More stuff</p>
<p>*More stuff</p>
</span>
</div>
</div>
</form>

112
install/static/user.html Normal file
View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3c.org/1999/xhtml" lang="en" xml:lang="en"
xmlns:py="http://genshi.edgewall.org/">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>jQuery test page for IPA</title>
<link href="ipa.css" rel="stylesheet" type="text/css" />
<script src="jquery.js" type="text/javascript"> </script>
<script src="ipa.js" type="text/javascript"> </script>
<script src="user.js" type="text/javascript"> </script>
<script src="details.js" type="text/javascript"> </script>
</head>
<body onload="load_object(this)">
<div id="view">
<div id="header">
<div id="logo">
<a href="#">
<img src="ipa_logo_180x50.png" />
</a>
</div>
<div id="loggedinas">
Logged in as <a href="user?principal=${context.principal}" py:content="context.principal"> </a>
</div>
</div>
<div id="content">
<h1>Managing user:</h1>
<div id="buttons">
<a href="dummy"><img id="butreset" src="but-reset.png" alt="Reset" /></a>
<a href="dummy"><img id="butupdate" src="but-update.png" alt="Update" /></a>
</div>
<ul id="viewtype">
<li id="viewcaption">View:</li>
<li>
<img src="but-selected.png" alt="" />
Personal Details
</li>
<li>
<img src="but-unselected.png" alt="" />
<a href="memberof?pkey=${pkey}">Memberships</a>
</li>
</ul>
<hr />
<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 />
<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 />
<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 />
<h2 onclick="h2_on_click(this)">&#8722; Mailing Address</h2>
<dl id="mailing" class="entryattrs">
<dt title="street">Address:</dt>
<dt title="location">City:</dt>
<dt title="call_a_st">State:</dt>
<dt title="postalCode">ZIP:</dt>
</dl>
<hr />
<h2 onclick="h2_on_click(this)">&#8722; Employee Information</h2>
<dl id="employee" class="entryattrs">
<dt title="ou">Org. Unit:</dt>
<dt title="call_a_manager">Manager:</dt>
</dl>
<hr />
<h2 onclick="h2_on_click(this)">&#8722; Misc. Information</h2>
<dl id="misc" class="entryattrs">
<dt title="carlicense">Car License:</dt>
</dl>
<hr />
<div id="backtotop">
<a href="#viewtype">Back to Top</a>
</div>
</div>
</div>
</body>
</html>

268
install/static/user.js Normal file
View File

@ -0,0 +1,268 @@
function setupUser(facet){
if (facet == "details"){
setupUserDetails()
}else if (facet == "add"){
setupAddUser();
}else if (facet == "group"){
setupUserGroupEnrollmentSearch();
}else if (facet == "groupmembership"){
setupUserGroupMembership();
}else{
setupUserSearch();
}
}
function add_user_fail(reason){
alert("Add User Failed:"+JSON.stringify(reason));
}
function addUser(on_success){
var options = { givenname: $("#firstname").val(),
sn: $("#lastname").val(),
uid : $("#login").val()};
ipa_cmd( 'add', [], options, on_success, add_user_fail, 'user' );
}
function addAnotherUser(){
addUser(setupAddUser);
}
function addEditUser(){
addUser(function (response){
location.href="index.xhtml?tab=user&facet=details&pkey="+$("#login").val();
});
}
function setupAddUser(){
showContent();
$('#content').load("user-add.inc");
}
function setupUserDetails(){
showContent();
$('#content').load("user-details.inc");
sampleData = "sampledata/usershow.json";
}
function renderSimpleColumn(current,cell){
cell.innerHTML = current[this.column];
}
function renderUserLinks(current, cell){
link = document.createElement("a");
cell.appendChild(link);
$("<a/>",{
href:"?tab=user&facet=details&pkey="+current.uid,
html: "[D]",
click:setupUserDetails,
}).appendTo(cell);
$("<a/>",{
href: "#tab=user&facet=details&pkey="+current.uid,
click:setupUserGroupMembership,
html: "[G]"
}).appendTo(cell);
$("<a/>",{
href:"?tab=user&facet=netgroup&pkey="+current.uid,
html: "[N]"
}).appendTo(cell);
$("<a/>",{
href:"?tab=user&facet=role&pkey="+current.uid,
html:"[R]"
}).appendTo(cell);
}
function renderUserDetailColumn(current,cell){
renderDetailColumn(current,cell,current[this.column],"user");
}
var columns = [
{title:"Name", column:"cn", render: renderSimpleColumn},
{title:"Login", column:"uid", render: renderUserDetailColumn},
{title:"UID", column:"uidnumber", render: renderSimpleColumn},
{title:"EMAIL", column:"mail", render: renderSimpleColumn},
{title:"Phone", column:"telephonenumber",render: renderSimpleColumn},
{title:"Job Title",column:"title", render: renderSimpleColumn},
{title:"Actions", column:"none", render: renderUserLinks}
];
function setupUserSearch(){
var userSearchForm = new SearchForm("user", "find", columns);
$("#query").unbind();
$("#query").click(function(){
sampleData = "sampledata/userlist.json";
executeSearch(userSearchForm);
});
$("#new").unbind();
$("#new").click(setupAddUser);
}
/*Usr group enrollement:
given a user, manage the groups in which they are enrolled */
function populateUserGroupFailure(){
alert("Can't find user");
}
function setupUserGroupEnrollmentSearch(pkey){
sampleData = "sampledata/usershow.json";
showContent();
$("#content").load("user-groups.inc");
}
function populateUserGroupSearch(searchResults){
results = searchResults.result;
$("#grouplist").html("");
for (var i =0; i != searchResults.result.count; i++){
var li = document.createElement("option");
li.value = searchResults.result.result[i].cn;
li.innerHTML = searchResults.result.result[i].cn;
$("#grouplist").append(li);
}
}
var currentUserToEnroll;
var groupsToEnroll;
function enrollUserInGroupSuccess(response){
enrollUserInNextGroup();
}
function enrollUserInGroupFailure(response){
alert("enrollUserInGroupFailure");
}
function enrollUserInNextGroup(){
var currentGroupToEnroll = groupsToEnroll.shift();
if (currentGroupToEnroll){
var options = {"user":currentUserToEnroll};
var args = [currentGroupToEnroll];
ipa_cmd( 'add_member',args, options ,
enrollUserInGroupSuccess,
enrollUserInGroupFailure, 'group' );
}else{
setupUserGroupMembership();
}
}
function initializeUserGroupEnrollments(){
$('h1').text('Enroll user ' + qs['pkey'] + ' in groups');
$("#enrollGroups").click(function(){
groupsToEnroll = [];
$('#enrollments').children().each(function(i, selected){
groupsToEnroll.push(selected.value);
});
currentUserToEnroll = qs['pkey'];
enrollUserInNextGroup();
});
$("#addToList").click(function(){
$('#grouplist :selected').each(function(i, selected){
$("#enrollments").append(selected);
});
$('#grouplist :selected').remove();
});
$("#removeFromList").click(function(){
$('#enrollments :selected').each(function(i, selected){
$("#grouplist").append(selected);
});
$('#enrollments :selected').remove();
});
$("#query").click(function(){
sampleData="sampledata/grouplist.json";
ipa_cmd( 'find', [], {}, populateUserGroupSearch, populateUserGroupFailure, 'group' );
});
}
function renderUserGroupColumn(){
}
/*Group Membership&*/
function renderUserGroupColumn(current,cell){
cell.innerHTML = "Nothing to see here";
}
var groupMembershipColumns = [
{title:"Group", column:"cn", render: renderUserGroupColumn},
{title:"GID", column:"gid", render: renderUserGroupColumn},
{title:"Description", column:"uidnumber", render: renderUserGroupColumn},
];
function populateUserEnrollments(userData){
var memberof_group = userData.result.result.memberof_group
for (var j = 0; j < memberof_group.length; j++){
var row = document.createElement("tr");
var td = document.createElement("td");
td.innerHTML = memberof_group[j];
row.appendChild(td);
td = document.createElement("td");
td.innerHTML = "TBD";
row.appendChild(td);
var td = document.createElement("td");
td.innerHTML = "TBD";
row.appendChild(td);
$('#searchResultsTable thead:last').append(row);
}
}
function setupUserGroupMembership(){
$("#searchButtons").html("");
$("<input/>",{
type: 'button',
value: 'enroll',
click: setupUserGroupEnrollmentSearch
}).appendTo("#searchButtons");
showSearch();
var columnHeaders = document.createElement("tr");
for (var i =0 ; i != groupMembershipColumns.length ;i++){
var th = document.createElement("th");
th.innerHTML = groupMembershipColumns[i].title;
columnHeaders.appendChild(th);
}
$('#searchResultsTable thead:last').append(columnHeaders);
sampleData="sampledata/usershow.json";
ipa_cmd( 'show', [qs['pkey']], {}, populateUserEnrollments, populateUserGroupFailure, 'user' );
}

415
install/static/usermeta.js Normal file
View File

@ -0,0 +1,415 @@
//TODO: This data should be fetched from a separate web URL and
//generated off the metadata for the user object
//but it is basically static.
var PluginData = {
"primary_key": "uid",
"default_attributes": [
"uid",
"givenname",
"sn",
"homedirectory",
"loginshell",
"ou",
"telephonenumber",
"title",
"memberof"
],
"object_name_plural": "users",
"container_dn": "cn=users,cn=accounts",
"object_class_config": "ipauserobjectclasses",
"hidden_attributes": [
"objectclass",
"aci"
],
"uuid_attribute": "ipauniqueid",
"label": "Users",
"methods": [
"add",
"del",
"find",
"lock",
"mod",
"show",
"unlock"
],
"object_name": "user",
"takes_params": [
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "login",
"primary_key": true,
"name": "uid",
"default": null,
"doc": "User login",
"required": true,
"flags": [],
"label": "User login",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "first",
"primary_key": false,
"name": "givenname",
"default": null,
"doc": "First name",
"required": true,
"flags": [],
"label": "First name",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "last",
"primary_key": false,
"name": "sn",
"default": null,
"doc": "Last name",
"required": true,
"flags": [],
"label": "Last name",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "homedir",
"primary_key": false,
"name": "homedirectory",
"default": null,
"doc": "Home directory",
"required": false,
"flags": [],
"label": "Home directory",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "gecos",
"primary_key": false,
"name": "gecos",
"default": null,
"doc": "GECOS field",
"required": false,
"flags": [],
"label": "GECOS field",
"autofill": true,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "shell",
"primary_key": false,
"name": "loginshell",
"default": "/bin/sh",
"doc": "Login shell",
"required": false,
"flags": [],
"label": "Login shell",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "principal",
"primary_key": false,
"name": "krbprincipalname",
"default": null,
"doc": "Kerberos principal",
"required": false,
"flags": [],
"label": "Kerberos principal",
"autofill": true,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "email",
"primary_key": false,
"name": "mail",
"default": null,
"doc": "Email address",
"required": false,
"flags": [],
"label": "Email address",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": [
"webui"
],
"minlength": null,
"include": null,
"cli_name": "password",
"primary_key": false,
"name": "userpassword",
"default": null,
"doc": "Set the user password",
"required": false,
"flags": [],
"label": "Password",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Password",
"maxlength": null
},
{
"exclude": null,
"include": null,
"cli_name": "uid",
"primary_key": false,
"minvalue": null,
"doc": "User ID Number (system will assign one if not provided)",
"required": false,
"flags": [],
"label": "UID",
"default": 999,
"autofill": true,
"multivalue": false,
"attribute": false,
"query": false,
"maxvalue": null,
"cli_short_name": null,
"type": "int",
"class": "Int",
"name": "uidnumber"
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "street",
"primary_key": false,
"name": "street",
"default": null,
"doc": "Street address",
"required": false,
"flags": [],
"label": "Street address",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "memberof_group",
"primary_key": false,
"name": "memberof_group",
"default": null,
"doc": "Groups",
"required": false,
"flags": [
"no_update",
"no_create",
"no_search"
],
"label": "Groups",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "memberof_netgroup",
"primary_key": false,
"name": "memberof_netgroup",
"default": null,
"doc": "Netgroups",
"required": false,
"flags": [
"no_update",
"no_create",
"no_search"
],
"label": "Netgroups",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "memberof_rolegroup",
"primary_key": false,
"name": "memberof_rolegroup",
"default": null,
"doc": "Rolegroups",
"required": false,
"flags": [
"no_update",
"no_create",
"no_search"
],
"label": "Rolegroups",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
},
{
"exclude": null,
"minlength": null,
"include": null,
"cli_name": "memberof_taskgroup",
"primary_key": false,
"name": "memberof_taskgroup",
"default": null,
"doc": "Taskgroups",
"required": false,
"flags": [
"no_update",
"no_create",
"no_search"
],
"label": "Taskgroups",
"autofill": false,
"multivalue": false,
"pattern": null,
"type": "unicode",
"attribute": false,
"query": false,
"cli_short_name": null,
"length": null,
"class": "Str",
"maxlength": null
}
],
"attribute_members": {
"memberof": [
"group",
"netgroup",
"rolegroup",
"taskgroup"
]
},
"parent_object": "",
"object_class": [
"posixaccount"
],
"name": "user"
}
ipa_objs['user'] = PluginData;