Passed
Push — codeStyle ( 6bdde0...c4a87f )
by Jan
01:48
created

graph.oval_graph.OvalNode.create_positions()   C

Complexity

Conditions 9

Size

Total Lines 30
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 9

Importance

Changes 0
Metric Value
eloc 23
dl 0
loc 30
ccs 22
cts 22
cp 1
rs 6.6666
c 0
b 0
f 0
cc 9
nop 2
crap 9
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 1
        return result
110
111 1
    def evaluate_tree(self):
112 1
        result = self.get_result_counts()
113
114 1
        if result['notappl_cnt'] > 0\
115
                and graph.evaluate.eq_zero(result, 'false_cnt')\
116
                and graph.evaluate.error_unknown_noteval_eq_zero(result)\
117
                and graph.evaluate.eq_zero(result, 'true_cnt'):
118 1
            return "notappl"
119
        else:
120 1
            if self.value == "or":
121 1
                return graph.evaluate.oval_operator_or(result)
122 1
            elif self.value == "and":
123 1
                return graph.evaluate.oval_operator_and(result)
124 1
            elif self.value == "one":
125 1
                return graph.evaluate.oval_operator_one(result)
126 1
            elif self.value == "xor":
127 1
                return graph.evaluate.oval_operator_xor(result)
128
129 1
    def save_tree_to_dict(self):
130 1
        if not self.children:
131 1
            return {
132
                'node_id': self.node_id,
133
                'type': self.node_type,
134
                'value': self.value,
135
                'child': None
136
            }
137 1
        return {
138
            'node_id': self.node_id,
139
            'type': self.node_type,
140
            'value': self.value,
141
            'child': [child.save_tree_to_dict() for child in self.children]
142
        }
143
144 1
    def find_node_with_ID(self, node_id):
145 1
        if self.node_id == node_id:
146 1
            return self
147
        else:
148 1
            for child in self.children:
149 1
                if child.node_id == node_id:
150 1
                    return child
151 1
            for child in self.children:
152 1
                if child.children != []:
153 1
                    return child.find_node_with_ID(node_id)
154
155 1
    def add_to_tree(self, node_id, newNode):
156 1
        self.find_node_with_ID(node_id).add_child(newNode)
157
158 1
    def change_tree_value(self, node_id, value):
159 1
        self.find_node_with_ID(node_id).value = value
160
161
    # Methods for interpreting oval tree with SigmaJS
162
163 1
    def _get_label(self):
164 1
        return str(self.node_id).replace(
165
                'xccdf_org.ssgproject.content_rule_',
166
                '').replace(
167
                'oval:ssg-',
168
                '').replace(
169
                ':def:1',
170
                '').replace(
171
                ':tst:1',
172
                '').replace('test_', '')
173
174 1
    def _create_node(self, x, y):
175
        # print(self.evaluate_tree(),self.value)
176 1
        if self.value == 'true':
177 1
            return {
178
                'id': self.node_id,
179
                'label': self._get_label(),
180
                'url': 'null',
181
                'text': 'null',
182
                'title': self.node_id,
183
                "x": x,
184
                "y": y,
185
                "size": 3,
186
                "color": '#00ff00'}
187 1
        elif self.value == 'false':
188 1
            return {
189
                'id': self.node_id,
190
                'label': self._get_label(),
191
                'url': 'null',
192
                'text': 'null',
193
                'title': self.node_id,
194
                "x": x,
195
                "y": y,
196
                "size": 3,
197
                "color": '#ff0000'}
198
        else:
199 1
            if self.evaluate_tree() == 'true':
200 1
                return {
201
                    'id': self.node_id,
202
                    'label': self.value,
203
                    'url': 'null',
204
                    'text': 'null',
205
                    'title': self.node_id,
206
                    "x": x,
207
                    "y": y,
208
                    "size": 3,
209
                    "color": '#00ff00'
210
                }
211 1
            elif self.evaluate_tree() == 'false':
212 1
                return {
213
                    'id': self.node_id,
214
                    'label': self.value,
215
                    'url': 'null',
216
                    'text': 'null',
217
                    'title': self.node_id,
218
                    "x": x,
219
                    "y": y,
220
                    "size": 3,
221
                    "color": '#ff0000'
222
                }
223
            else:
224 1
                return {
225
                    'id': self.node_id,
226
                    'label': self.value,
227
                    'url': 'null',
228
                    'text': 'null',
229
                    'title': str(self.node_id) + ' ' + self.value,
230
                    "x": x,
231
                    "y": y,
232
                    "size": 3,
233
                    "color": '#000000'
234
                }
235
236 1
    def _create_edge(self, id_source, id_target):
237 1
        return {
238
            "id": str(uuid.uuid4()),
239
            "source": id_source,
240
            "target": id_target
241
        }
242
243 1
    def create_list_of_id(self, array_of_ids=None):
244 1
        if array_of_ids is None:
245 1
            array_of_ids = []
246 1
            array_of_ids.append(self.node_id)
247 1
        for child in self.children:
248 1
            if child.node_type != "operator":
249 1
                array_of_ids.append(child.node_id)
250
            else:
251 1
                array_of_ids.append(child.node_id)
252 1
                child.create_list_of_id(array_of_ids)
253 1
        return array_of_ids
254
255 1
    def _remove_Duplication(self, graph_data):
256 1
        array_of_ids = self.create_list_of_id()
257 1
        out = dict(nodes=[], edges=graph_data['edges'])
258 1
        duplicate_ids = [item for item, count in collections.Counter(
259
            array_of_ids).items() if count > 1]
260
261 1
        for node in graph_data['nodes']:
262 1
            if node['id'] not in duplicate_ids:
263 1
                out['nodes'].append(node)
264
265 1
        for id in duplicate_ids:
266 1
            for node in graph_data['nodes']:
267 1
                if node['id'] == id:
268 1
                    out['nodes'].append(node)
269 1
                    break
270 1
        return out
271
272 1
    def _fix_graph(self, preprocessed_graph_data):
273 1
        for node in preprocessed_graph_data['nodes']:
274 1
            for node1 in preprocessed_graph_data['nodes']:
275 1
                if node['x'] == node1['x'] and node['y'] == node1['y']:
276 1
                    node['x'] = node['x'] - 1
277 1
        return preprocessed_graph_data
278
279 1
    def _help_to_sigma_dict(self, x, y, preprocessed_graph_data=None):
280 1
        if preprocessed_graph_data is None:
281 1
            preprocessed_graph_data = dict(nodes=[], edges=[])
282 1
            preprocessed_graph_data['nodes'].append(self._create_node(x, y))
283 1
        y_row = y + 1
284 1
        x_row = x
285 1
        for node in self.children:
286 1
            preprocessed_graph_data['nodes'].append(
287
                node._create_node(x_row, y_row))
288 1
            preprocessed_graph_data['edges'].append(
289
                node._create_edge(self.node_id, node.node_id))
290 1
            x_row = x_row + 1
291 1
            if node.children is not None:
292 1
                preprocessed_graph_data = node._help_to_sigma_dict(
293
                    x_row + 1, y_row + 1, preprocessed_graph_data)
294 1
        return self._fix_graph(preprocessed_graph_data)
295
296 1
    def count_max_y(self, out):
297 1
        max_y = 0
298
299 1
        for node in out['nodes']:
300 1
            if max_y < node['y']:
301 1
                max_y = node['y']
302 1
        return max_y
303
304 1
    def create_nodes_in_rows(self, rows):
305 1
        nodes_in_rows = dict()
306
307 1
        for i in range(rows + 1):
308 1
            nodes_in_rows[i] = []
309 1
        return nodes_in_rows
310
311 1
    def push_nodes_to_nodes_in_row(self, out, nodes_in_rows):
312 1
        for node in out['nodes']:
313 1
            nodes_in_rows[node['y']].append(node)
314
315 1
    def remove_empty_rows(self, nodes_in_rows, max_y):
316 1
        for row in range(max_y + 1):
317 1
            if not nodes_in_rows[row]:
318 1
                del nodes_in_rows[row]
319
320 1
    def move_rows(self, nodes_in_rows):
321 1
        count = 0
322 1
        nodes_in_rows1 = dict()
323
324 1
        for row in nodes_in_rows:
325 1
            nodes_in_rows1[count] = nodes_in_rows[row]
326 1
            for node in nodes_in_rows1[count]:
327 1
                node['y'] = count
328 1
            count += 1
329 1
        return nodes_in_rows1
330
331 1
    def create_positions(self, nodes_in_rows):
332 1
        positions = []
333 1
        for row in nodes_in_rows:
334 1
            len_of_row = len(nodes_in_rows[row])
335 1
            if len_of_row > 1:
336 1
                if (len_of_row % 2) == 1:
337 1
                    len_of_row += 1
338
339 1
                for i in range((int(-(len_of_row / 2))) * 2,
340
                               (int(+(len_of_row / 2)) + 1) * 2, 2):
341 1
                    positions.append(i)
342
343 1
                if len_of_row == 2:
344 1
                    positions.remove(0)
345
346 1
                if len(nodes_in_rows[row]) < len(positions):
347 1
                    positions.pop()
348 1
                    if len(nodes_in_rows[row]) < len(positions):
349 1
                        positions.pop(0)
350
351 1
                count = 0
352
353 1
                for pos in positions:
354 1
                    nodes_in_rows[row][count]['x'] = pos
355 1
                    count += 1
356 1
                positions = []
357
            else:
358 1
                nodes_in_rows[row][0]['x'] = 0
359
360 1
        return positions
361
362 1
    def convert_nodes_in_rows_to_nodes(self, nodes_in_rows):
363 1
        nodes = []
364 1
        for row in nodes_in_rows:
365 1
            for node in nodes_in_rows[row]:
366 1
                nodes.append(node)
367 1
        return nodes
368
369 1
    def change_position(self, positions, nodes_in_rows):
370 1
        x = 0.6
371 1
        up_and_down = True
372 1
        down = False
373 1
        down_row = False
374 1
        save_x = 0
375 1
        continue_move = False
376
377 1
        for row in nodes_in_rows:
378 1
            for node in nodes_in_rows[row]:
379 1
                if len(
380
                        node['label']) > 6 and len(
381
                        node['label']) < 40 or continue_move:
382 1
                    if up_and_down:
383 1
                        node['y'] = node['y'] + (0.6 * x)
384 1
                        up_and_down = False
385
                    else:
386 1
                        up_and_down = True
387 1
                    continue_move = True
388 1
                elif len(node['label']) > 30:
389 1
                    node['y'] = node['y'] + (0.6 * x)
390 1
                    x += 0.6
391 1
                    save_x = x
392 1
                    down = True
393
                else:
394 1
                    if down:
395 1
                        node['y'] = node['y'] + (0.6 * save_x)
396
397 1
                    if down_row:
398 1
                        node['y'] = node['y'] + (0.6 * save_x) - 0.7
399 1
            if down:
400 1
                down = False
401 1
                down_row = True
402 1
            continue_move = False
403 1
            x = 0.6
404
405 1
    def sort(self, array):
406 1
        less = []
407 1
        equal = []
408 1
        greater = []
409
410 1
        if len(array) > 1:
411 1
            pivot = array[0]['x']
412 1
            for node in array:
413 1
                if node['x'] < pivot:
414
                    less.append(node)
415 1
                if node['x'] == pivot:
416 1
                    equal.append(node)
417 1
                if node['x'] > pivot:
418 1
                    greater.append(node)
419 1
            return self.sort(less) + equal + self.sort(greater)
420
        else:
421 1
            return array
422
423 1
    def sort_nodes(self, nodes_in_rows):
424 1
        for row in nodes_in_rows:
425 1
            nodes_in_rows[row] = self.sort(nodes_in_rows[row])
426
427 1
    def center_graph(self, out):
428 1
        max_y = self.count_max_y(out)
429 1
        nodes_in_rows = self.create_nodes_in_rows(max_y)
430 1
        self.push_nodes_to_nodes_in_row(out, nodes_in_rows)
431 1
        self.remove_empty_rows(nodes_in_rows, max_y)
432 1
        nodes_in_rows = self.move_rows(nodes_in_rows)
433 1
        self.sort_nodes(nodes_in_rows)
434 1
        positions = self.create_positions(nodes_in_rows)
435 1
        self.change_position(positions, nodes_in_rows)
436 1
        out['nodes'] = self.convert_nodes_in_rows_to_nodes(nodes_in_rows)
437 1
        return out
438
439 1
    def to_sigma_dict(self, x, y):
440 1
        return self.center_graph(
441
            self._remove_Duplication(
442
                self._help_to_sigma_dict(
443
                    x, y)))
444
445
446 1
def build_nodes_form_xml(xml_src, rule_id):
447 1
    parser = graph.xml_parser.xml_parser(xml_src)
448 1
    return parser.get_oval_graph(rule_id)
449
450
451 1
def restore_dict_to_tree(dict_of_tree):
452 1
    if dict_of_tree["child"] is None:
453 1
        return OvalNode(
454
            dict_of_tree["node_id"],
455
            dict_of_tree["type"],
456
            dict_of_tree["value"])
457 1
    return OvalNode(
458
        dict_of_tree["node_id"],
459
        dict_of_tree["type"],
460
        dict_of_tree["value"],
461
        [restore_dict_to_tree(i) for i in dict_of_tree["child"]])
462