Passed
Push — codeStyle ( 2e6332...8ac4c9 )
by Jan
02:03
created

graph.oval_graph.OvalNode.get_result_counts()   C

Complexity

Conditions 9

Size

Total Lines 28
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 9

Importance

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