Passed
Push — codeStyle ( 8ac4c9...8912bb )
by Jan
02:48
created

graph.oval_graph.OvalNode.count_max_y()   A

Complexity

Conditions 3

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 7
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 3
nop 2
crap 3
1
'''
2
    Modules form my lib and for create ID
3
'''
4 1
import graph.xml_parser
5 1
import graph.evaluate
6 1
import uuid
7 1
import collections
8
9
'''
10
    This module contains methods and classes for
11
    constructing and controlling an oval tree.
12
'''
13
14
15 1
class OvalNode():
16
    '''
17
    The OvalNode object is one node of oval graph.
18
19
    Args:
20
        node_id (str|int): identifies node
21
        input_node_type (str): type of node (value or operator)
22
        input_value (str): value of node
23
        children ([OvalNode]): array of children of node
24
25
    Attributes:
26
        node_id (str): id of node
27
        node_type (str): type node
28
        value (str): value of node for operator and,
29
        or, one etc... and for value true, false, error etc...
30
        children ([OvalNode]): children of node
31
    '''
32
33 1
    def __init__(self, node_id, input_node_type, input_value, children=None):
34 1
        self.node_id = node_id
35 1
        value = input_value.lower()
36 1
        node_type = input_node_type.lower()
37 1
        if node_type == "value" or node_type == "operator":
38 1
            self.node_type = node_type
39
        else:
40 1
            raise ValueError("err- unknown type")
41 1
        allowed_operators = [
42
            "or",
43
            "and",
44
            "one",
45
            "xor"]
46 1
        allowed_values = [
47
            "true",
48
            "false",
49
            "error",
50
            "unknown",
51
            "noteval",
52
            "notappl"]
53 1
        if self.node_type == "value":
54 1
            if value in allowed_values:
55 1
                self.value = value
56
            else:
57 1
                raise ValueError("err- unknown value")
58 1
        if self.node_type == "operator":
59 1
            if value in allowed_operators:
60 1
                self.value = value
61
            else:
62 1
                raise ValueError("err- unknown operator")
63 1
        self.children = []
64 1
        if children is not None:
65 1
            for child in children:
66 1
                self.add_child(child)
67
        else:
68 1
            if self.node_type == "operator":
69 1
                raise ValueError('err- OR, XOR, ONE, AND have child!')
70
71 1
    def __repr__(self):
72 1
        return self.value
73
74 1
    def add_child(self, node):
75 1
        if self.node_type == "operator":
76 1
            assert isinstance(node, OvalNode)
77 1
            self.children.append(node)
78
        else:
79 1
            self.children = None
80 1
            raise ValueError(
81
                "err- true, false, error, unknown. noteval, notappl have not child!")
82
83 1
    def get_result_counts(self):
84 1
        result = {
85
            'true_cnt': 0,
86
            'false_cnt': 0,
87
            'error_cnt': 0,
88
            'unknown_cnt': 0,
89
            'noteval_cnt': 0,
90
            'notappl_cnt': 0
91
        }
92
93 1
        for child in self.children:
94 1
            if child.value == 'true':
95 1
                result['true_cnt'] += 1
96 1
            elif child.value == 'false':
97 1
                result['false_cnt'] += 1
98 1
            elif child.value == 'error':
99 1
                result['error_cnt'] += 1
100 1
            elif child.value == 'unknown':
101 1
                result['unknown_cnt'] += 1
102 1
            elif child.value == 'noteval':
103 1
                result['noteval_cnt'] += 1
104 1
            elif child.value == 'notappl':
105 1
                result['notappl_cnt'] += 1
106
            else:
107 1
                if self.node_type == "operator":
108 1
                    result[child.evaluate_tree() + "_cnt"] += 1
109
110 1
        return result
111
112 1
    def evaluate_tree(self):
113 1
        result = self.get_result_counts()
114
115 1
        if result['notappl_cnt'] > 0\
116
                and graph.evaluate.eq_zero(result, 'false_cnt')\
117
                and graph.evaluate.error_unknown_noteval_eq_zero(result)\
118
                and graph.evaluate.eq_zero(result, 'true_cnt'):
119 1
            return "notappl"
120
        else:
121 1
            if self.value == "or":
122 1
                return graph.evaluate.oval_operator_or(result)
123 1
            elif self.value == "and":
124 1
                return graph.evaluate.oval_operator_and(result)
125 1
            elif self.value == "one":
126 1
                return graph.evaluate.oval_operator_one(result)
127 1
            elif self.value == "xor":
128 1
                return graph.evaluate.oval_operator_xor(result)
129
130 1
    def save_tree_to_dict(self):
131 1
        if not self.children:
132 1
            return {
133
                'node_id': self.node_id,
134
                'type': self.node_type,
135
                'value': self.value,
136
                'child': None
137
            }
138 1
        return {
139
            'node_id': self.node_id,
140
            'type': self.node_type,
141
            'value': self.value,
142
            'child': [child.save_tree_to_dict() for child in self.children]
143
        }
144
145 1
    def find_node_with_ID(self, node_id):
146 1
        if self.node_id == node_id:
147 1
            return self
148
        else:
149 1
            for child in self.children:
150 1
                if child.node_id == node_id:
151 1
                    return child
152 1
            for child in self.children:
153 1
                if child.children != []:
154 1
                    return child.find_node_with_ID(node_id)
155
156 1
    def add_to_tree(self, node_id, newNode):
157 1
        self.find_node_with_ID(node_id).add_child(newNode)
158
159 1
    def change_tree_value(self, node_id, value):
160 1
        self.find_node_with_ID(node_id).value = value
161
162
    # Methods for interpreting oval tree with SigmaJS
163
164 1
    def _create_node(self, x, y):
165
        # print(self.evaluate_tree(),self.value)
166 1
        if self.value == 'true':
167 1
            return {
168
                'id': self.node_id,
169
                'label': self.value,
170
                'label': str(self.node_id).replace(
171
                    'xccdf_org.ssgproject.content_rule_',
172
                    '').replace(
173
                    'oval:ssg-',
174
                    '').replace(
175
                    ':def:1',
176
                    '').replace(
177
                    ':tst:1',
178
                    '').replace('test_', ''),
179
                'url': 'null',
180
                'text': 'null',
181
                'title': self.node_id,
182
                "x": x,
183
                "y": y,
184
                "size": 3,
185
                "color": '#00ff00'}
186 1
        elif self.value == 'false':
187 1
            return {
188
                'id': self.node_id,
189
                'label': self.value,
190
                'label': str(self.node_id).replace(
191
                    'xccdf_org.ssgproject.content_rule_',
192
                    '').replace(
193
                    'oval:ssg-',
194
                    '').replace(
195
                    ':def:1',
196
                    '').replace(
197
                    ':tst:1',
198
                    '').replace('test_', ''),
199
                'url': 'null',
200
                'text': 'null',
201
                'title': self.node_id,
202
                "x": x,
203
                "y": y,
204
                "size": 3,
205
                "color": '#ff0000'}
206
        else:
207 1
            if self.evaluate_tree() == 'true':
208 1
                return {
209
                    'id': self.node_id,
210
                    'label': self.value,
211
                    'url': 'null',
212
                    'text': 'null',
213
                    'title': self.node_id,
214
                    "x": x,
215
                    "y": y,
216
                    "size": 3,
217
                    "color": '#00ff00'
218
                }
219 1
            elif self.evaluate_tree() == 'false':
220 1
                return {
221
                    'id': self.node_id,
222
                    'label': self.value,
223
                    'url': 'null',
224
                    'text': 'null',
225
                    'title': self.node_id,
226
                    "x": x,
227
                    "y": y,
228
                    "size": 3,
229
                    "color": '#ff0000'
230
                }
231
            else:
232 1
                return {
233
                    'id': self.node_id,
234
                    'label': self.value,
235
                    'url': 'null',
236
                    'text': 'null',
237
                    'title': str(self.node_id) + ' ' + self.value,
238
                    "x": x,
239
                    "y": y,
240
                    "size": 3,
241
                    "color": '#000000'
242
                }
243
244 1
    def _create_edge(self, id_source, id_target):
245 1
        return {
246
            "id": str(uuid.uuid4()),
247
            "source": id_source,
248
            "target": id_target
249
        }
250
251 1
    def create_list_of_id(self, array_of_ids=None):
252 1
        if array_of_ids is None:
253 1
            array_of_ids = []
254 1
            array_of_ids.append(self.node_id)
255 1
        for child in self.children:
256 1
            if child.node_type != "operator":
257 1
                array_of_ids.append(child.node_id)
258
            else:
259 1
                array_of_ids.append(child.node_id)
260 1
                child.create_list_of_id(array_of_ids)
261 1
        return array_of_ids
262
263 1
    def _remove_Duplication(self, graph_data):
264 1
        array_of_ids = self.create_list_of_id()
265 1
        out = dict(nodes=[], edges=graph_data['edges'])
266 1
        duplicate_ids = [item for item, count in collections.Counter(
267
            array_of_ids).items() if count > 1]
268
269 1
        for node in graph_data['nodes']:
270 1
            if node['id'] not in duplicate_ids:
271 1
                out['nodes'].append(node)
272
273 1
        for id in duplicate_ids:
274 1
            for node in graph_data['nodes']:
275 1
                if node['id'] == id:
276 1
                    out['nodes'].append(node)
277 1
                    break
278 1
        return out
279
280 1
    def _fix_graph(self, preprocessed_graph_data):
281 1
        for node in preprocessed_graph_data['nodes']:
282 1
            for node1 in preprocessed_graph_data['nodes']:
283 1
                if node['x'] == node1['x'] and node['y'] == node1['y']:
284 1
                    node['x'] = node['x'] - 1
285 1
        return preprocessed_graph_data
286
287 1
    def _help_to_sigma_dict(self, x, y, preprocessed_graph_data=None):
288 1
        if preprocessed_graph_data is None:
289 1
            preprocessed_graph_data = dict(nodes=[], edges=[])
290 1
            preprocessed_graph_data['nodes'].append(self._create_node(x, y))
291 1
        y_row = y + 1
292 1
        x_row = x
293 1
        for node in self.children:
294 1
            preprocessed_graph_data['nodes'].append(
295
                node._create_node(x_row, y_row))
296 1
            preprocessed_graph_data['edges'].append(
297
                node._create_edge(self.node_id, node.node_id))
298 1
            x_row = x_row + 1
299 1
            if node.children is not None:
300 1
                preprocessed_graph_data = node._help_to_sigma_dict(
301
                    x_row + 1, y_row + 1, preprocessed_graph_data)
302 1
        return self._fix_graph(preprocessed_graph_data)
303
304 1
    def count_max_y(self, out):
305 1
        max_y = 0
306
307 1
        for node in out['nodes']:
308 1
            if max_y < node['y']:
309 1
                max_y = node['y']
310 1
        return max_y
311
312 1
    def create_nodes_in_rows(self, rows):
313 1
        nodes_in_rows = dict()
314
315 1
        for i in range(rows + 1):
316 1
            nodes_in_rows[i] = []
317 1
        return nodes_in_rows
318
319 1
    def push_nodes_to_nodes_in_row(self, out, nodes_in_rows):
320 1
        for node in out['nodes']:
321 1
            nodes_in_rows[node['y']].append(node)
322
323 1
    def remove_empty_rows(self, nodes_in_rows, max_y):
324 1
        for row in range(max_y + 1):
325 1
            if not nodes_in_rows[row]:
326 1
                del nodes_in_rows[row]
327
328 1
    def move_rows(self, nodes_in_rows):
329 1
        count = 0
330 1
        nodes_in_rows1 = dict()
331
332 1
        for row in nodes_in_rows:
333 1
            nodes_in_rows1[count] = nodes_in_rows[row]
334 1
            for node in nodes_in_rows1[count]:
335 1
                node['y'] = count
336 1
            count += 1
337 1
        return nodes_in_rows1
338
339 1
    def create_positions(self, nodes_in_rows):
340 1
        positions = []
341 1
        for row in nodes_in_rows:
342 1
            len_of_row = len(nodes_in_rows[row])
343 1
            if len_of_row > 1:
344 1
                if (len_of_row % 2) == 1:
345 1
                    len_of_row += 1
346
347 1
                for i in range((int(-(len_of_row / 2))) * 2,
348
                               (int(+(len_of_row / 2)) + 1) * 2, 2):
349 1
                    positions.append(i)
350
351 1
                if len_of_row == 2:
352 1
                    positions.remove(0)
353
354 1
                if len(nodes_in_rows[row]) < len(positions):
355 1
                    positions.pop()
356 1
                    if len(nodes_in_rows[row]) < len(positions):
357 1
                        positions.pop(0)
358
359 1
                count = 0
360
361 1
                for pos in positions:
362 1
                    nodes_in_rows[row][count]['x'] = pos
363 1
                    count += 1
364 1
                positions = []
365
            else:
366 1
                nodes_in_rows[row][0]['x'] = 0
367
368 1
        return positions
369
370 1
    def convert_nodes_in_rows_to_nodes(self, nodes_in_rows):
371 1
        nodes = []
372 1
        for row in nodes_in_rows:
373 1
            for node in nodes_in_rows[row]:
374 1
                nodes.append(node)
375 1
        return nodes
376
377 1
    def change_position(self, positions, nodes_in_rows):
378 1
        x = 0.6
379 1
        up_and_down = True
380 1
        down = False
381 1
        down_row = False
382 1
        save_x = 0
383
384 1
        for row in nodes_in_rows:
385 1
            for node in nodes_in_rows[row]:
386 1
                if len(node['label']) > 6 and len(node['label']) < 40:
387 1
                    if up_and_down:
388 1
                        node['y'] = node['y'] + (0.6 * x)
389 1
                        up_and_down = False
390
                    else:
391 1
                        up_and_down = True
392 1
                elif len(node['label']) > 30:
393 1
                    node['y'] = node['y'] + (0.6 * x)
394 1
                    x += 0.6
395 1
                    save_x = x
396 1
                    down = True
397
                else:
398 1
                    if down:
399 1
                        node['y'] = node['y'] + (0.6 * save_x)
400
401 1
                    if down_row:
402 1
                        node['y'] = node['y'] + (0.6 * save_x) - 0.7
403 1
            if down:
404 1
                down = False
405 1
                down_row = True
406 1
            x = 0.6
407
408 1
    def sort(self, array):
409 1
        less = []
410 1
        equal = []
411 1
        greater = []
412
413 1
        if len(array) > 1:
414 1
            pivot = array[0]['x']
415 1
            for node in array:
416 1
                if node['x'] < pivot:
417
                    less.append(node)
418 1
                if node['x'] == pivot:
419 1
                    equal.append(node)
420 1
                if node['x'] > pivot:
421 1
                    greater.append(node)
422 1
            return self.sort(less) + equal + self.sort(greater)
423
        else:
424 1
            return array
425
426 1
    def sort_nodes(self, nodes_in_rows):
427 1
        for row in nodes_in_rows:
428 1
            nodes_in_rows[row] = self.sort(nodes_in_rows[row])
429
430 1
    def center_graph(self, out):
431 1
        max_y = self.count_max_y(out)
432 1
        nodes_in_rows = self.create_nodes_in_rows(max_y)
433 1
        self.push_nodes_to_nodes_in_row(out, nodes_in_rows)
434 1
        self.remove_empty_rows(nodes_in_rows, max_y)
435 1
        nodes_in_rows = self.move_rows(nodes_in_rows)
436 1
        self.sort_nodes(nodes_in_rows)
437 1
        positions = self.create_positions(nodes_in_rows)
438 1
        self.change_position(positions, nodes_in_rows)
439 1
        out['nodes'] = self.convert_nodes_in_rows_to_nodes(nodes_in_rows)
440 1
        return out
441
442 1
    def to_sigma_dict(self, x, y):
443 1
        return self.center_graph(
444
            self._remove_Duplication(
445
                self._help_to_sigma_dict(
446
                    x, y)))
447
448
449 1
def build_nodes_form_xml(xml_src, rule_id):
450 1
    parser = graph.xml_parser.xml_parser(xml_src)
451 1
    return parser.get_oval_graph(rule_id)
452
453
454 1
def restore_dict_to_tree(dict_of_tree):
455 1
    if dict_of_tree["child"] is None:
456 1
        return OvalNode(
457
            dict_of_tree["node_id"],
458
            dict_of_tree["type"],
459
            dict_of_tree["value"])
460 1
    return OvalNode(
461
        dict_of_tree["node_id"],
462
        dict_of_tree["type"],
463
        dict_of_tree["value"],
464
        [restore_dict_to_tree(i) for i in dict_of_tree["child"]])
465