Commit 214fd623719fa8934a2a56a4674f9f5e296752b5
1 parent
c7f367aa
Add code for a clickable HTML representation.
Showing
10 changed files
with
321 additions
and
35 deletions
@@ -8,7 +8,6 @@ from struct import pack | @@ -8,7 +8,6 @@ from struct import pack | ||
8 | from collections import deque | 8 | from collections import deque |
9 | 9 | ||
10 | from os.path import dirname, realpath | 10 | from os.path import dirname, realpath |
11 | -from sys import argv, path | ||
12 | path.append(dirname(realpath(__file__)) + '/lib') | 11 | path.append(dirname(realpath(__file__)) + '/lib') |
13 | 12 | ||
14 | from Server import Server | 13 | from Server import Server |
@@ -20,10 +19,12 @@ from Communication.EndPoint import CommunicationEndPoint | @@ -20,10 +19,12 @@ from Communication.EndPoint import CommunicationEndPoint | ||
20 | from Protocol.Http.Http import Http | 19 | from Protocol.Http.Http import Http |
21 | from Protocol.Websocket.Websocket import Websocket | 20 | from Protocol.Websocket.Websocket import Websocket |
22 | 21 | ||
22 | +from jinja2 import Environment, FileSystemLoader | ||
23 | + | ||
23 | from LdapTree import LdapTree | 24 | from LdapTree import LdapTree |
24 | 25 | ||
25 | class Application(EventHandler): | 26 | class Application(EventHandler): |
26 | - def __init__(self, hosturi, binddn, basedn, password): | 27 | + def __init__(self, ip, port, hosturi, binddn, basedn, password): |
27 | super(Application, self).__init__() | 28 | super(Application, self).__init__() |
28 | 29 | ||
29 | self._event_methods = { | 30 | self._event_methods = { |
@@ -35,17 +36,16 @@ class Application(EventHandler): | @@ -35,17 +36,16 @@ class Application(EventHandler): | ||
35 | 36 | ||
36 | self._websockets = [] | 37 | self._websockets = [] |
37 | 38 | ||
38 | - self._wstest = open('websocket.html', 'r+b') | ||
39 | - self._wstestmm = mmap.mmap(self._wstest.fileno(), 0) | 39 | + env = Environment(loader=FileSystemLoader( |
40 | + dirname(realpath(__file__)) + '/templates')) | ||
41 | + template = env.get_template('websocket.html.j2') | ||
42 | + # TODO get ip and port or better our complete base uri here. | ||
43 | + self._page = template.render(ip=ip, port=port) | ||
40 | 44 | ||
41 | random.seed() | 45 | random.seed() |
42 | 46 | ||
43 | self.ldaptree = LdapTree(hosturi, binddn, basedn, password, False) | 47 | self.ldaptree = LdapTree(hosturi, binddn, basedn, password, False) |
44 | 48 | ||
45 | - def __del__(self): | ||
46 | - self._wstestmm.close() | ||
47 | - self._wstest.close() | ||
48 | - | ||
49 | def _upgrade(self, event): | 49 | def _upgrade(self, event): |
50 | self._websockets.append(event.subject) | 50 | self._websockets.append(event.subject) |
51 | # let other also handle the upgrade .. no return True | 51 | # let other also handle the upgrade .. no return True |
@@ -64,13 +64,14 @@ class Application(EventHandler): | @@ -64,13 +64,14 @@ class Application(EventHandler): | ||
64 | if event.data.isRequest(): | 64 | if event.data.isRequest(): |
65 | if event.data.getUri() == '/': | 65 | if event.data.getUri() == '/': |
66 | resp = protocol.createResponse(event.data, 200, 'OK') | 66 | resp = protocol.createResponse(event.data, 200, 'OK') |
67 | - resp.setBody(self._wstestmm[0:]) | 67 | + resp.setBody(self._page) |
68 | elif event.data.getUri() == '/ldap': | 68 | elif event.data.getUri() == '/ldap': |
69 | resp = protocol.createResponse(event.data, 200, 'OK') | 69 | resp = protocol.createResponse(event.data, 200, 'OK') |
70 | resp.setHeader('Content-Type', 'image/svg+xml') | 70 | resp.setHeader('Content-Type', 'image/svg+xml') |
71 | resp.setBody(self.ldaptree.graph()) | 71 | resp.setBody(self.ldaptree.graph()) |
72 | else: | 72 | else: |
73 | - resp = protocol.createResponse(event.data, 404, 'Not Found') | 73 | + resp = protocol.createResponse( |
74 | + event.data, 404, 'Not Found') | ||
74 | resp.setBody('<h1>404 - Not Found</h1>') | 75 | resp.setBody('<h1>404 - Not Found</h1>') |
75 | 76 | ||
76 | self.issueEvent(event.subject, 'send_msg', resp) | 77 | self.issueEvent(event.subject, 'send_msg', resp) |
@@ -133,7 +134,9 @@ def main(): | @@ -133,7 +134,9 @@ def main(): | ||
133 | usage() | 134 | usage() |
134 | sys.exit(2) | 135 | sys.exit(2) |
135 | 136 | ||
136 | - server = Server(Application(hosturi, binddn, basedn, password)) | 137 | + server = Server( |
138 | + Application( | ||
139 | + args[0], int(args[1], hosturi, binddn, basedn, password)) | ||
137 | server.bindTcp(args[0], int(args[1]), Http()) | 140 | server.bindTcp(args[0], int(args[1]), Http()) |
138 | server.start(1.0) | 141 | server.start(1.0) |
139 | 142 |
LdapService2.py
0 → 100755
1 | +#!/usr/bin/python | ||
2 | + | ||
3 | +import time | ||
4 | +import random | ||
5 | +import mmap | ||
6 | +from struct import pack | ||
7 | +from collections import deque | ||
8 | + | ||
9 | +from os.path import dirname, realpath | ||
10 | +import sys | ||
11 | +reload(sys) | ||
12 | +from sys import argv, path, setdefaultencoding | ||
13 | +path.append(dirname(realpath(__file__)) + '/lib') | ||
14 | +setdefaultencoding('utf-8') | ||
15 | +import re | ||
16 | + | ||
17 | +from Server import Server | ||
18 | + | ||
19 | +from Event.EventHandler import EventHandler | ||
20 | +from Event.EventDispatcher import EventDispatcher | ||
21 | +from Communication.EndPoint import CommunicationEndPoint | ||
22 | + | ||
23 | +from Protocol.Http.Http import Http | ||
24 | +from Protocol.Websocket.Websocket import Websocket | ||
25 | +from jinja2 import Environment, FileSystemLoader | ||
26 | + | ||
27 | +from LdapTree import LdapTree | ||
28 | + | ||
29 | +class Application(EventHandler): | ||
30 | + def __init__(self, ip, port, hosturi, binddn, basedn, password): | ||
31 | + super(Application, self).__init__() | ||
32 | + | ||
33 | + self._event_methods = { | ||
34 | + CommunicationEndPoint.eventId('new_msg') : self._handle_data, | ||
35 | + } | ||
36 | + | ||
37 | + self._ldaptree = LdapTree(hosturi, binddn, basedn, password, False) | ||
38 | + | ||
39 | + env = Environment(loader=FileSystemLoader( | ||
40 | + dirname(realpath(__file__)) + '/templates')) | ||
41 | + self._template = env.get_template('simple.html.j2') | ||
42 | + | ||
43 | + random.seed() | ||
44 | + | ||
45 | + @property | ||
46 | + def _body(self): | ||
47 | + return self._template.render(ldaptree=self._ldaptree).encode('utf8') | ||
48 | + | ||
49 | + def _handle_data(self, event): | ||
50 | + protocol = event.subject.getProtocol() | ||
51 | + | ||
52 | + if event.subject.hasProtocol(Http): | ||
53 | + if event.data.isRequest(): | ||
54 | + if event.data.getUri() == '/': | ||
55 | + resp = protocol.createResponse(event.data, 200, 'OK') | ||
56 | + resp.setBody(self._body) | ||
57 | + else: | ||
58 | + resp = protocol.createResponse(event.data, 404, 'Not Found') | ||
59 | + resp.setBody('<h1>404 - Not Found</h1>') | ||
60 | + | ||
61 | + self.issueEvent(event.subject, 'send_msg', resp) | ||
62 | + | ||
63 | + return True | ||
64 | + | ||
65 | + | ||
66 | +def usage(): | ||
67 | + print "Usage: " + sys.argv[0] + " ARGUMENT... [OPTIONS]... bindip bindport\n" | ||
68 | + print "Start a webserver on the given bindip and bindport. On the page a" | ||
69 | + print "tree representation of all DNs starting with a given base DN is" | ||
70 | + print "visualized." | ||
71 | + print "Only simple binds to the directory with DN and password are supported.\n" | ||
72 | + print "ARGUMENTS:\n" | ||
73 | + print " {:30s} : {:s}".format('-H, --hosturi=URI', 'The URI to the ldap server to query in the form:') | ||
74 | + print " {:30s} {:s}".format('', 'ldap[s]://host.uri[:port]') | ||
75 | + print " {:30s} : {:s}".format('-D, --binddn=DN', 'The DN to use for the LDAP bind.') | ||
76 | + print " {:30s} : {:s}".format('-p, --password=PASSWORD', 'The password to use for the LDAP bind.') | ||
77 | + print " {:30s} : {:s}\n".format('-b, --basedn=DN', 'The DN to start the tree with.') | ||
78 | + print "OPTIONS:\n" | ||
79 | + print " {:30s} : {:s}".format('-h, --help', 'Show this help page') | ||
80 | + | ||
81 | +def main(): | ||
82 | + try: | ||
83 | + opts, args = getopt.getopt( | ||
84 | + sys.argv[1:], | ||
85 | + 'hH:D:b:p:', | ||
86 | + ['help', 'hosturi=', 'binddn=', 'basedn=', 'password=']) | ||
87 | + except getopt.GetoptError as err: | ||
88 | + print str(err) | ||
89 | + usage() | ||
90 | + sys.exit(2) | ||
91 | + | ||
92 | + hosturi = binddn = basedn = password = None | ||
93 | + | ||
94 | + for o, a in opts: | ||
95 | + if o in ["-h", "--help"]: | ||
96 | + usage() | ||
97 | + sys.exit(0) | ||
98 | + elif o in ["-H", "--hosturi"]: | ||
99 | + hosturi = a | ||
100 | + elif o in ["-D", "--binddn"]: | ||
101 | + binddn = a | ||
102 | + elif o in ["-b", "--basedn"]: | ||
103 | + basedn = a | ||
104 | + elif o in ["-p", "--password"]: | ||
105 | + password = a | ||
106 | + else: | ||
107 | + print "unknown parameter: " + a | ||
108 | + usage() | ||
109 | + sys.exit(2) | ||
110 | + | ||
111 | + if not hosturi or not binddn or not basedn or not password: | ||
112 | + usage() | ||
113 | + sys.exit(2) | ||
114 | + | ||
115 | + server = Server( | ||
116 | + Application( | ||
117 | + args[0], int(args[1], hosturi, binddn, basedn, password)) | ||
118 | + server.bindTcp(args[0], int(args[1]), Http()) | ||
119 | + server.start(1.0) | ||
120 | + | ||
121 | +if __name__ == '__main__': | ||
122 | + main() | ||
123 | +# vim: set ft=python et ts=8 sw=4 sts=4: |
1 | #!/usr/bin/python | 1 | #!/usr/bin/python |
2 | from os.path import dirname, realpath | 2 | from os.path import dirname, realpath |
3 | import getopt, sys | 3 | import getopt, sys |
4 | +reload(sys) | ||
4 | sys.path.append(dirname(realpath(__file__)) + '/lib') | 5 | sys.path.append(dirname(realpath(__file__)) + '/lib') |
6 | +sys.setdefaultencoding('utf-8') | ||
5 | 7 | ||
6 | import getpass | 8 | import getpass |
7 | from LdapTree import LdapTree | 9 | from LdapTree import LdapTree |
@@ -31,7 +31,7 @@ class Connection(CommunicationEndPoint): | @@ -31,7 +31,7 @@ class Connection(CommunicationEndPoint): | ||
31 | if not self._current_msg or self._current_msg.ready(): | 31 | if not self._current_msg or self._current_msg.ready(): |
32 | self._current_msg = self._protocol.createMessage( | 32 | self._current_msg = self._protocol.createMessage( |
33 | self.getTransport().remote) | 33 | self.getTransport().remote) |
34 | - | 34 | + |
35 | end = self._protocol.getParser().parse( | 35 | end = self._protocol.getParser().parse( |
36 | self._current_msg, self._read_buffer) | 36 | self._current_msg, self._read_buffer) |
37 | 37 |
1 | +from os.path import dirname, realpath | ||
2 | + | ||
1 | import ldap | 3 | import ldap |
2 | import pygraphviz as pgv | 4 | import pygraphviz as pgv |
3 | 5 | ||
6 | +from jinja2 import Environment, FileSystemLoader | ||
7 | + | ||
4 | class LdapTree(object): | 8 | class LdapTree(object): |
5 | def __init__(self, hosturi, binddn, basedn, password, use_gssapi): | 9 | def __init__(self, hosturi, binddn, basedn, password, use_gssapi): |
6 | #ldap.set_option(ldap.OPT_DEBUG_LEVEL, 1) | 10 | #ldap.set_option(ldap.OPT_DEBUG_LEVEL, 1) |
@@ -19,16 +23,23 @@ class LdapTree(object): | @@ -19,16 +23,23 @@ class LdapTree(object): | ||
19 | self._basedn = basedn | 23 | self._basedn = basedn |
20 | self._ldap_result = [] | 24 | self._ldap_result = [] |
21 | 25 | ||
26 | + self._data = None | ||
27 | + | ||
22 | def text(self, filename = None): | 28 | def text(self, filename = None): |
23 | """ | 29 | """ |
24 | Returns a text representing the directory. | 30 | Returns a text representing the directory. |
25 | If filename is given it will be written in that file. | 31 | If filename is given it will be written in that file. |
26 | """ | 32 | """ |
33 | + env = Environment(loader=FileSystemLoader( | ||
34 | + dirname(dirname(realpath(__file__))) + '/templates')) | ||
35 | + template = env.get_template('simple.txt.j2') | ||
36 | + text = template.render(ldaptree=self).encode('utf8') | ||
37 | + | ||
27 | if filename: | 38 | if filename: |
28 | with open(filename, "w") as text_file: | 39 | with open(filename, "w") as text_file: |
29 | - text_file.write(self._text(self._basedn, 0)) | 40 | + text_file.write(text) |
30 | else: | 41 | else: |
31 | - return self._text(self._basedn, 0) | 42 | + return text |
32 | 43 | ||
33 | def graph(self, filename = None): | 44 | def graph(self, filename = None): |
34 | """ | 45 | """ |
@@ -54,26 +65,11 @@ class LdapTree(object): | @@ -54,26 +65,11 @@ class LdapTree(object): | ||
54 | else: | 65 | else: |
55 | return graph.draw(format='svg') | 66 | return graph.draw(format='svg') |
56 | 67 | ||
57 | - def _text(self, dn, level): | ||
58 | - """ | ||
59 | - Recursive function that returns a string representation of the | ||
60 | - directory where each depth is indicated by a dash. | ||
61 | - """ | ||
62 | - result = self._ldap.search_s(dn, ldap.SCOPE_ONELEVEL) | ||
63 | - indent = '-' * level | ||
64 | - text = indent + dn + "\n" | ||
65 | - | ||
66 | - for entry in (entry[0] for entry in result): | ||
67 | - if entry: | ||
68 | - text += self._text(entry, level + 1) | ||
69 | - | ||
70 | - return text | ||
71 | - | ||
72 | def _graph(self, graph, dn): | 68 | def _graph(self, graph, dn): |
73 | """ | 69 | """ |
74 | Recursive function creating a graphviz graph from the directory. | 70 | Recursive function creating a graphviz graph from the directory. |
75 | """ | 71 | """ |
76 | - result = self._ldap.search_s(dn, ldap.SCOPE_ONELEVEL) | 72 | + result = self.node(dn) |
77 | minlen = thislen = 1 | 73 | minlen = thislen = 1 |
78 | edge_start = dn | 74 | edge_start = dn |
79 | 75 | ||
@@ -85,6 +81,7 @@ class LdapTree(object): | @@ -85,6 +81,7 @@ class LdapTree(object): | ||
85 | sub.add_node( | 81 | sub.add_node( |
86 | point, shape='circle', fixedsize='true', width='0.04', | 82 | point, shape='circle', fixedsize='true', width='0.04', |
87 | label='', fillcolor='transparent') | 83 | label='', fillcolor='transparent') |
84 | + #sub.add_node(entry, URL='https://www.google.de/') | ||
88 | sub.add_node(entry) | 85 | sub.add_node(entry) |
89 | graph.add_edge(edge_start, point, arrowhead='none', | 86 | graph.add_edge(edge_start, point, arrowhead='none', |
90 | minlen=str(minlen)) | 87 | minlen=str(minlen)) |
@@ -94,3 +91,62 @@ class LdapTree(object): | @@ -94,3 +91,62 @@ class LdapTree(object): | ||
94 | thislen += minlen | 91 | thislen += minlen |
95 | 92 | ||
96 | return thislen | 93 | return thislen |
94 | + | ||
95 | + @property | ||
96 | + def all(self): | ||
97 | + if self._data == None: | ||
98 | + self._data = {} | ||
99 | + result = self._ldap.search_s(self._basedn, ldap.SCOPE_SUBTREE) | ||
100 | + for entry in result: | ||
101 | + self._data[entry[0]] = entry[1:][0] | ||
102 | + | ||
103 | + return self._data | ||
104 | + | ||
105 | + @property | ||
106 | + def dn_tree(self): | ||
107 | + retval = {} | ||
108 | + for d in self.all.keys(): | ||
109 | + current = retval | ||
110 | + for k in reversed(d.split(',')): | ||
111 | + try: | ||
112 | + current = current[k] | ||
113 | + except: | ||
114 | + current[k] = {} | ||
115 | + current = current[k] | ||
116 | + return retval | ||
117 | + | ||
118 | + @property | ||
119 | + def hirarchy(self): | ||
120 | + return self._hirarchy(self.dn_tree) | ||
121 | + | ||
122 | + def _hirarchy(self, dn, base=[], depth=0): | ||
123 | + """ | ||
124 | + Hirarchie generates a flat list where each parent is | ||
125 | + followed by all its childs, so that in a template one | ||
126 | + can simple iterate over it to display the complete tree. | ||
127 | + Recently I learned that "recursive loops" are possible | ||
128 | + within jinja2. So we can alter the template that it | ||
129 | + ensures child displays correctly | ||
130 | + """ | ||
131 | + retval = [] | ||
132 | + for d in dn.keys(): | ||
133 | + base_name = ','.join(reversed(base)) | ||
134 | + name = ','.join(reversed(base + [d])) | ||
135 | + retval.append((depth, base_name, name)) | ||
136 | + retval += self._hirarchy(dn[d], base + [d], depth+1) | ||
137 | + return retval | ||
138 | + | ||
139 | + def childs(self, dn): | ||
140 | + """ | ||
141 | + Recently I learned that "recursive loops" are possible | ||
142 | + within jinja2. So we can alter the template that it | ||
143 | + ensures child displays correctly. So this function should | ||
144 | + return all child dn's to a given dn. | ||
145 | + """ | ||
146 | + return [d for d in self.hirarchy if d[1] == dn] | ||
147 | + | ||
148 | + def node(self, dn): | ||
149 | + if dn in self.all: | ||
150 | + return self.all[dn] | ||
151 | + else: | ||
152 | + return {} |
@@ -62,13 +62,13 @@ class TcpSocket(Socket): | @@ -62,13 +62,13 @@ class TcpSocket(Socket): | ||
62 | 62 | ||
63 | def recv(self, size): | 63 | def recv(self, size): |
64 | data = '' | 64 | data = '' |
65 | - try: | 65 | + try: |
66 | data = self.socket.recv(size) | 66 | data = self.socket.recv(size) |
67 | except socket.error as error: | 67 | except socket.error as error: |
68 | if error.errno not in CONTINUE: | 68 | if error.errno not in CONTINUE: |
69 | raise Transport.Error(Transport.Error.ERR_FAILED) | 69 | raise Transport.Error(Transport.Error.ERR_FAILED) |
70 | return None | 70 | return None |
71 | - | 71 | + |
72 | if not data: | 72 | if not data: |
73 | raise Transport.Error(Transport.Error.ERR_REMOTE_CLOSE) | 73 | raise Transport.Error(Transport.Error.ERR_REMOTE_CLOSE) |
74 | 74 | ||
@@ -76,7 +76,7 @@ class TcpSocket(Socket): | @@ -76,7 +76,7 @@ class TcpSocket(Socket): | ||
76 | 76 | ||
77 | def send(self, data, remote=None): | 77 | def send(self, data, remote=None): |
78 | send = 0 | 78 | send = 0 |
79 | - try: | 79 | + try: |
80 | if self.socket: | 80 | if self.socket: |
81 | send = self.socket.send(data) | 81 | send = self.socket.send(data) |
82 | except socket.error as error: | 82 | except socket.error as error: |
templates/simple.html.j2
0 → 100644
1 | +<!DOCTYPE html> | ||
2 | +<html> | ||
3 | + <head> | ||
4 | + <meta charset="utf-8"/> | ||
5 | + <title>Ldap</title> | ||
6 | + <style type="text/css"> | ||
7 | + ul { | ||
8 | + list-style-type: none; | ||
9 | + } | ||
10 | + ul.attributes { | ||
11 | + border: 1px solid black; | ||
12 | + font-weight: normal; | ||
13 | + display: none; | ||
14 | + padding: 5px; | ||
15 | + margin: 0; | ||
16 | + } | ||
17 | + ul.childs { | ||
18 | + display: none; | ||
19 | + } | ||
20 | + button { | ||
21 | + cursor: pointer; | ||
22 | + background-color: rgba(0,0,0,0); | ||
23 | + border: none; | ||
24 | + color: black; | ||
25 | + padding: 2px; | ||
26 | + text-align: center; | ||
27 | + text-decoration: none; | ||
28 | + display: inline-block; | ||
29 | + font-size: 16px; | ||
30 | + } | ||
31 | + span.linked { | ||
32 | + font-weight: bold; | ||
33 | + cursor: pointer; | ||
34 | + } | ||
35 | + </style> | ||
36 | + </head> | ||
37 | + | ||
38 | + <body> | ||
39 | + <h1>Ldap</h1> | ||
40 | + | ||
41 | + <script language="Javascript"> | ||
42 | + function toggle(e, cls) { | ||
43 | + attr = e.parentElement.getElementsByClassName(cls)[0]; | ||
44 | + if(attr.style.display == 'block') | ||
45 | + attr.style.display = 'none'; | ||
46 | + else | ||
47 | + attr.style.display = 'block'; | ||
48 | + } | ||
49 | + </script> | ||
50 | + | ||
51 | + <ul class="tree"> | ||
52 | + {% set depth=0 -%} | ||
53 | + {% for d in ldaptree.hirarchy -%} | ||
54 | + {% if depth>=d[0] and depth!=0 -%} | ||
55 | + <ul class="childs" {% if depth < 3 -%}style="display: block;"{% endif -%}> | ||
56 | + </ul> | ||
57 | + </li> | ||
58 | + {% endif -%} | ||
59 | + {% if depth < d[0] -%} | ||
60 | + {% set depth=d[0] -%} | ||
61 | + <ul class="childs" {% if depth < 3 -%}style="display: block;"{% endif -%}> | ||
62 | + {% endif -%} | ||
63 | + {% if depth > d[0] -%} | ||
64 | + {% for i in range(depth-d[0]) -%} | ||
65 | + </ul> | ||
66 | + </li> | ||
67 | + {% endfor -%} | ||
68 | + {% set depth=d[0] -%} | ||
69 | + {% endif -%} | ||
70 | + <li> | ||
71 | + <span {% if ldaptree.childs(d[2]) -%}class="linked"{% endif -%} | ||
72 | + onclick="toggle(this, 'childs')">dn: {{ d[2]|e }}</span> | ||
73 | + <button onclick="toggle(this, 'attributes')">[Attributes]</button> | ||
74 | + <ul class="attributes"> | ||
75 | + {% for k in ldaptree.node(d[2]).keys() -%} | ||
76 | + {% if ldaptree.node(d[2]) is string -%} | ||
77 | + <li>{{ k }}: {{ ldaptree.node(d[2])[k]|e }}</li> | ||
78 | + {% else -%} | ||
79 | + {% for v in ldaptree.node(d[2])[k] -%} | ||
80 | + <li>{{ k }}: {{ v|e }}</li> | ||
81 | + {% endfor -%} | ||
82 | + {% endif -%} | ||
83 | + {% endfor -%} | ||
84 | + </ul> | ||
85 | + {% endfor -%} | ||
86 | + </ul> | ||
87 | + </body> | ||
88 | +</html> | ||
89 | +<!-- vim: set et ts=2 sw=2: --> |
templates/simple.txt.j2
0 → 100644
1 | +{% for d in ldaptree.hirarchy -%} | ||
2 | +{{ '--'*d[0] }} dn: {{ d[2] }} | ||
3 | +{% for k in ldaptree.node(d[2]).keys() -%} | ||
4 | +{% if ldaptree.node(d[2]) is string -%} | ||
5 | +{{ ' '*d[0] }} {{ k }}: {{ ldaptree.node(d[2])[k] }} | ||
6 | +{% else -%} | ||
7 | +{% for v in ldaptree.node(d[2])[k] -%} | ||
8 | +{{ ' '*d[0] }} {{ k }}: {{ v }} | ||
9 | +{% endfor -%} | ||
10 | +{% endif -%} | ||
11 | +{% endfor -%} | ||
12 | +{% endfor -%} |
@@ -80,7 +80,7 @@ | @@ -80,7 +80,7 @@ | ||
80 | var interval = null | 80 | var interval = null |
81 | 81 | ||
82 | wstest.data = 'Websockets are supported'; | 82 | wstest.data = 'Websockets are supported'; |
83 | - connection = new WebSocket('ws://127.0.0.1:8080/'); | 83 | + connection = new WebSocket('ws://172.27.1.139:8080/'); |
84 | console.log('Websockets test'); | 84 | console.log('Websockets test'); |
85 | 85 | ||
86 | connection.onopen = function() { | 86 | connection.onopen = function() { |
@@ -114,7 +114,8 @@ | @@ -114,7 +114,8 @@ | ||
114 | } | 114 | } |
115 | }/* ]]> */ | 115 | }/* ]]> */ |
116 | </script> | 116 | </script> |
117 | - <img src="http://127.0.0.1:8080/ldap" /> | 117 | + <object data="http://{{ ip }}:{{ port }}/ldap" type="image/svg+xml" class="mailicon"> |
118 | + </object> | ||
118 | </body> | 119 | </body> |
119 | </html> | 120 | </html> |
120 | <!-- vim: set ts=4 sw=4: --> | 121 | <!-- vim: set ts=4 sw=4: --> |
tests/.TestAll.py.swp
0 → 100644
No preview for this file type
Please
register
or
login
to post a comment