3web2ldap.app.read: Read single entry and output as HTML or vCard
5web2ldap - a web-based LDAP Client,
6see https://www.web2ldap.de for details
8(C) 1998-2022 by Michael Stroeder <michael@stroeder.com>
10This software is distributed under the terms of the
11Apache License Version 2.0 (Apache-2.0)
12https://www.apache.org/licenses/LICENSE-2.0
15from collections
import UserDict
18from ldap0.cidict
import CIDict
19from ldap0.schema.models
import SchemaElementOIDSet, AttributeType
21from .schema
import no_humanreadable_attr, no_userapp_attr
22from .schema.syntaxes
import syntax_registry
23from .schema.viewer
import schema_anchor
24from .
import ErrorExit
25from .tmpl
import get_variant_filename
27 context_menu_single_entry,
33from .form
import ExportFormatSelect, InclOpAttrsCheckbox
34from .entry
import DisplayEntry
39 def __init__(self, app, entry, out_charset='utf-8'):
40 UserDict.__init__(self, entry)
46 raise KeyError(
'Not human-readable attribute %r not usable in vCard' % (nameoroid,))
47 return UserDict.__getitem__(self, nameoroid)[0].decode(self.
_app.ls.charset)
51 for line
in template_str.decode(
'utf-8').split(
'\n'):
53 res_line = line % self
57 res.append(res_line.strip())
58 return '\r\n'.join(res)
62 template_dict = CIDict(app.cfg_param(
'vcard_template', {}))
63 current_oc_set = {s.lower().decode(
'ascii')
for s
in object_classes}
64 template_oc = list(current_oc_set.intersection(template_dict.data.keys()))
72 Send a table of attributes to outf
83 show_attrs.sort(key=str.lower)
85 read_expandattr_set = {
87 for at
in app.form.getInputValue(
'read_expandattr', [])
90 if '*' in read_expandattr_set:
91 read_tablemaxcount_dict = {}
93 read_tablemaxcount_dict = ldap0.cidict.CIDict(
94 app.cfg_param(
'read_tablemaxcount', {})
96 for at
in read_expandattr_set:
98 del read_tablemaxcount_dict[at]
101 app.outf.write(
'<h2>%s</h2>\n<table class="ReadAttrTable">' % (comment))
104 for attr_type_name
in show_attrs:
105 attr_type_anchor_id =
'readattr_%s' % app.form.s2d(attr_type_name)
109 ldap0.schema.models.AttributeType,
110 name_template=
'<var>{name}</var>\n{anchor}',
113 attr_value_disp_list = (
114 entry[attr_type_name]
or
115 [
'<strong><Empty attribute value list!></strong>']
117 attr_value_count = len(attr_value_disp_list)
119 '<span id="%s">%s</span>\n' % (attr_type_anchor_id, attr_type_str),
121 read_tablemaxcount = min(
122 read_tablemaxcount_dict.get(attr_type_name, attr_value_count),
125 if attr_value_count > 1:
126 if attr_value_count > read_tablemaxcount:
127 dt_list.append(app.anchor(
129 '(%d of %d values)' % (read_tablemaxcount, attr_value_count),
130 app.form.allInputFields(
132 (
'read_expandattr', attr_type_name),
135 anchor_id=attr_type_anchor_id
138 dt_list.append(
'(%d values)' % (attr_value_count))
141 dt_list.append(app.anchor(
143 [(
'dn', app.dn), (
'delete_attr', attr_type_name)]
145 dt_list.append(app.anchor(
146 'read',
'Save to disk',
149 (
'read_attr', attr_type_name),
150 (
'read_attrmimetype',
'application/octet-stream'),
151 (
'read_attrindex',
'0'),
154 dt_str =
'<br>'.join(dt_list)
156 '<tr>\n<th rowspan="%d">\n%s\n</th>\n<td>%s</td>\n</tr>\n' % (
159 attr_value_disp_list[0],
162 if read_tablemaxcount >= 2:
163 for i
in range(1, read_tablemaxcount):
165 '<tr>\n<td>%s</td>\n</tr>\n' % (
166 attr_value_disp_list[i],
169 app.outf.write(
'</table>\n')
175 read_output = app.form.getInputValue(
'read_output', [
'template'])[0]
176 filterstr = app.form.getInputValue(
'filterstr', [
'(objectClass=*)'])[0]
178 read_nocache =
int(app.form.getInputValue(
'read_nocache', [
'0'])[0]
or '0')
181 wanted_attr_set = SchemaElementOIDSet(
183 ldap0.schema.models.AttributeType,
184 app.form.getInputValue(
'read_attr', app.ldap_url.attrs
or []),
186 wanted_attrs = wanted_attr_set.names
189 search_attrs = app.form.getInputValue(
'search_attrs', [
''])[0]
191 wanted_attrs.extend([
192 a.strip()
for a
in search_attrs.split(
',')
197 if app.ls.supports_allop_attr:
198 wanted_attrs = [
'*',
'+']
202 search_result = app.ls.l.read_s(
204 attrlist=wanted_attrs,
206 cache_ttl=
None if read_nocache
else -1.0,
209 if not search_result:
210 raise ErrorExit(
'Empty search result.')
212 entry = ldap0.schema.models.Entry(app.schema, app.dn, search_result.entry_as)
214 requested_attrs = SchemaElementOIDSet(
217 app.cfg_param(
'requested_attrs', []),
219 if not wanted_attrs
and requested_attrs:
221 search_result = app.ls.l.read_s(
224 attrlist=requested_attrs.names,
225 cache_ttl=
None if read_nocache
else -1.0,
228 ldap0.NO_SUCH_ATTRIBUTE,
229 ldap0.INSUFFICIENT_ACCESS,
235 entry.update(search_result.entry_as)
237 display_entry =
DisplayEntry(app, app.dn, app.schema, entry,
'read_sep', 1)
241 and len(wanted_attrs) == 1
242 and not wanted_attrs[0]
in {b
'*', b
'+'}
249 attr_type = wanted_attrs[0]
251 if attr_type
not in entry:
252 if attr_type+
';binary' in entry:
253 attr_type = attr_type+
';binary'
256 'Attribute <em>%s</em> not in entry.' % (
257 app.form.s2d(attr_type)
262 read_attrindex =
int(app.form.getInputValue(
'read_attrindex', [
'0'])[0])
263 syntax_se = syntax_registry.get_syntax(app.schema, attr_type, entry.get_structural_oc())
266 attr_instance = syntax_se(app, app.dn, app.schema, attr_type,
None, entry)
270 app.form.getInputValue(
272 [attr_instance.mime_type],
274 app.form.accept_charset,
277 'Content-Disposition',
278 'inline; filename=web2ldap-export.%s' % (attr_instance.file_ext,)
283 app.outf.write_bytes(entry[attr_type][read_attrindex])
287 if read_output
in {
'table',
'template'}:
297 dds_link=b
'dynamicObject' in entry.get(
'objectClass', []),
299 entry[
'entryUUID'][0].decode(app.ls.charset)
300 if 'entryUUID' in entry
307 export_field.charset = app.form.accept_charset
310 app.outf.write(
'%s\n' % (
312 'search',
'Export',
'GET',
316 (
'filterstr',
'(objectClass=*)'),
317 (
'search_resnumber',
'0'),
318 (
'search_attrs',
','.join(map(str, wanted_attrs
or []))),
321 export_field.input_html(),
325 target=
'web2ldapexport',
329 displayed_attrs = set()
331 if read_output ==
'template':
333 displayed_attrs.update(display_entry.template_output(
'read_template'))
336 if not displayed_attrs:
338 h1_display_name =
'Root DSE'
340 h1_display_name = entry.get(
342 entry.get(
'cn', [b
''])
343 )[0].decode(app.ls.charset)
or str(app.dn_obj.slice(0, 1))
345 '<h1>{0}</h1>\n<p class="EntryDN">{1}</p>\n'.format(
346 app.form.s2d(h1_display_name),
347 display_entry[
'entryDN'],
355 required_attrs_dict, allowed_attrs_dict = entry.attribute_types(raise_keyerror=0)
360 collective_attrs = []
361 nomatching_attrs = []
362 for a
in entry.keys():
363 at_se = app.schema.get_obj(ldap0.schema.models.AttributeType, a,
None)
365 nomatching_attrs.append(a)
368 if at_oid
in displayed_attrs:
370 if at_oid
in required_attrs_dict:
371 required_attrs.append(a)
372 elif at_oid
in allowed_attrs_dict:
373 allowed_attrs.append(a)
376 collective_attrs.append(a)
378 nomatching_attrs.append(a)
380 display_entry.sep_attr =
None
385 display_entry.sep_attr =
'read_sep'
388 """%s\n%s\n%s<p>\n%s\n
389 <input type=submit value="Request"> attributes:
390 <input name=
"search_attrs" value=
"%s" size=
"40" maxlength=
"255">
393 app.begin_form('read',
'GET'),
394 app.form.hidden_field_html(
'read_nocache',
'1',
''),
395 app.form.hidden_field_html(
'dn', app.dn,
''),
396 app.form.hidden_field_html(
'read_output', read_output,
''),
398 app.form.s2d(at, sp_entity=
' ')
401 or {
False:[
'*'],
True:[
'*',
'+']}[app.ls.supports_allop_attr]
409 elif read_output ==
'vcard':
417 if not vcard_template_filename:
418 raise ErrorExit(
'No vCard template file found for object class(es) of this entry.')
422 with open(vcard_template_filename,
'rb')
as fileobj:
423 template_str = fileobj.read()
425 raise ErrorExit(
'I/O error during reading vCard template file!')
427 vcard_filename =
'web2ldap-vcard'
428 for vcard_name_attr
in (
'displayName',
'cn',
'o'):
430 vcard_filename = entry[vcard_name_attr][0].decode(app.ls.charset)
431 except (KeyError, IndexError):
435 entry[
'dn'] = [app.ldap_dn]
440 app.form.accept_charset,
443 'Content-Disposition',
444 'inline; filename={0}.vcf'.format(vcard_filename)
448 app.outf.write(display_entry.generate_vcard(template_str))
def generate_vcard(self, template_str)
def __init__(self, app, entry, out_charset='utf-8')
def __getitem__(self, nameoroid)
def top_section(app, title, main_menu_list, context_menu_list=None, main_div_id='Message')
def header(app, content_type, charset, more_headers=None)
def context_menu_single_entry(app, vcard_link=0, dds_link=0, entry_uuid=None)
def get_vcard_template(app, object_classes)
def display_attribute_table(app, entry, attrs, comment)
def no_humanreadable_attr(schema, attr_type)
def no_userapp_attr(schema, attr_type_name, relax_rules=False)
def schema_anchor(app, se_nameoroid, se_class, name_template='{name}\n{anchor}', link_text=None)
def get_variant_filename(pathname, variantlist)