Passed
Pull Request — codeStyle (#2)
by Jan
02:08
created

graph.oval_graph.OvalNode.pushNodesToNodesInRow()   A

Complexity

Conditions 2

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 3
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 2
nop 3
crap 2
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 evaluate_tree(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
        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 _create_node(self, x, y):
164
        # print(self.evaluate_tree(),self.value)
165 1
        if self.value == 'true':
166 1
            return {
167
                'id': self.node_id,
168
                'label': self.value,
169
                'label': str(self.node_id).replace(
170
                    'xccdf_org.ssgproject.content_rule_',
171
                    '').replace(
172
                    'oval:ssg-',
173
                    '').replace(
174
                    ':def:1',
175
                    '').replace(
176
                    ':tst:1',
177
                    '').replace('test_', ''),
178
                'url': 'null',
179
                'text': 'null',
180
                'title': self.node_id,
181
                "x": x,
182
                "y": y,
183
                "size": 3,
184
                "color": '#00ff00'}
185 1
        elif self.value == 'false':
186 1
            return {
187
                'id': self.node_id,
188
                'label': self.value,
189
                'label': str(self.node_id).replace(
190
                    'xccdf_org.ssgproject.content_rule_',
191
                    '').replace(
192
                    'oval:ssg-',
193
                    '').replace(
194
                    ':def:1',
195
                    '').replace(
196
                    ':tst:1',
197
                    '').replace('test_', ''),
198
                'url': 'null',
199
                'text': 'null',
200
                'title': self.node_id,
201
                "x": x,
202
                "y": y,
203
                "size": 3,
204
                "color": '#ff0000'}
205
        else:
206 1
            if self.evaluate_tree() == 'true':
207 1
                return {
208
                    'id': self.node_id,
209
                    'label': self.value,
210
                    'url': 'null',
211
                    'text': 'null',
212
                    'title': self.node_id,
213
                    "x": x,
214
                    "y": y,
215
                    "size": 3,
216
                    "color": '#00ff00'
217
                }
218 1
            elif self.evaluate_tree() == 'false':
219 1
                return {
220
                    'id': self.node_id,
221
                    'label': self.value,
222
                    'url': 'null',
223
                    'text': 'null',
224
                    'title': self.node_id,
225
                    "x": x,
226
                    "y": y,
227
                    "size": 3,
228
                    "color": '#ff0000'
229
                }
230
            else:
231 1
                return {
232
                    'id': self.node_id,
233
                    'label': self.value,
234
                    'url': 'null',
235
                    'text': 'null',
236
                    'title': str(self.node_id) + ' ' + self.value,
237
                    "x": x,
238
                    "y": y,
239
                    "size": 3,
240
                    "color": '#000000'
241
                }
242
243 1
    def _create_edge(self, id_source, id_target):
244 1
        return {
245
            "id": str(uuid.uuid4()),
246
            "source": id_source,
247
            "target": id_target
248
        }
249
250 1
    def create_list_of_id(self, array_of_ids=None):
251 1
        if array_of_ids is None:
252 1
            array_of_ids = []
253 1
            array_of_ids.append(self.node_id)
254 1
        for child in self.children:
255 1
            if child.node_type != "operator":
256 1
                array_of_ids.append(child.node_id)
257
            else:
258 1
                array_of_ids.append(child.node_id)
259 1
                child.create_list_of_id(array_of_ids)
260 1
        return array_of_ids
261
262 1
    def _remove_Duplication(self, graph_data):
263 1
        array_of_ids = self.create_list_of_id()
264 1
        out = dict(nodes=[], edges=graph_data['edges'])
265 1
        duplicate_ids = [item for item, count in collections.Counter(
266
            array_of_ids).items() if count > 1]
267
268 1
        for node in graph_data['nodes']:
269 1
            if node['id'] not in duplicate_ids:
270 1
                out['nodes'].append(node)
271
272 1
        for id in duplicate_ids:
273 1
            for node in graph_data['nodes']:
274 1
                if node['id'] == id:
275 1
                    out['nodes'].append(node)
276 1
                    break
277 1
        return out
278
279 1
    def _fix_graph(self, preprocessed_graph_data):
280 1
        for node in preprocessed_graph_data['nodes']:
281 1
            for node1 in preprocessed_graph_data['nodes']:
282 1
                if node['x'] == node1['x'] and node['y'] == node1['y']:
283 1
                    node['x'] = node['x'] - 1
284 1
        return preprocessed_graph_data
285
286 1
    def _help_to_sigma_dict(self, x, y, preprocessed_graph_data=None):
287 1
        if preprocessed_graph_data is None:
288 1
            preprocessed_graph_data = dict(nodes=[], edges=[])
289 1
            preprocessed_graph_data['nodes'].append(self._create_node(x, y))
290 1
        y_row = y + 1
291 1
        x_row = x
292 1
        for node in self.children:
293 1
            preprocessed_graph_data['nodes'].append(
294
                node._create_node(x_row, y_row))
295 1
            preprocessed_graph_data['edges'].append(
296
                node._create_edge(self.node_id, node.node_id))
297 1
            x_row = x_row + 1
298 1
            if node.children is not None:
299 1
                preprocessed_graph_data = node._help_to_sigma_dict(
300
                    x_row + 1, y_row + 1, preprocessed_graph_data)
301 1
        return self._fix_graph(preprocessed_graph_data)
302
303 1
    def countMaxY(self, out):
304 1
        maxY = 0
305
306 1
        for node in out['nodes']:
307 1
            if(maxY < node['y']):
308 1
                maxY = node['y']
309 1
        return maxY
310
311 1
    def createNodesInRows(self, rows):
312 1
        nodesInRows = dict()
313
314 1
        for i in range(rows + 1):
315 1
            nodesInRows[i] = []
316 1
        return nodesInRows
317
318 1
    def pushNodesToNodesInRow(self, out, nodesInRows):
319 1
        for node in out['nodes']:
320 1
            nodesInRows[node['y']].append(node)
321
322 1
    def removeEmptyRows(self, nodesInRows, maxY):
323 1
        for row in range(maxY + 1):
324 1
            if not nodesInRows[row]:
325 1
                del nodesInRows[row]
326
327 1
    def moveRows(self, nodesInRows):
328 1
        count = 0
329 1
        nodesInRows1 = dict()
330
331 1
        for row in nodesInRows:
332 1
            nodesInRows1[count] = nodesInRows[row]
333 1
            for node in nodesInRows1[count]:
334 1
                node['y'] = count
335 1
            count += 1
336 1
        return nodesInRows1
337
338 1
    def createPositions(self, nodesInRows):
339 1
        positions = []
340 1
        for row in nodesInRows:
341 1
            lenOfRow = len(nodesInRows[row])
342 1
            if lenOfRow > 1:
343 1
                if (lenOfRow % 2) == 1:
344 1
                    lenOfRow += 1
345
346 1
                for i in range((int(-(lenOfRow / 2))) * 2,
347
                               (int(+(lenOfRow / 2)) + 1) * 2, 2):
348 1
                    positions.append(i)
349
350 1
                if lenOfRow == 2:
351 1
                    positions.remove(0)
352
353 1
                if len(nodesInRows[row]) < len(positions):
354 1
                    positions.pop()
355 1
                    if len(nodesInRows[row]) < len(positions):
356 1
                        positions.pop(0)
357
358 1
                count = 0
359
360 1
                for pos in positions:
361 1
                    nodesInRows[row][count]['x'] = pos
362 1
                    count += 1
363 1
                positions = []
364
            else:
365 1
                nodesInRows[row][0]['x'] = 0
366
367 1
        return positions
368
369 1
    def convertNodesInRowsToNodes(self, nodesInRows):
370 1
        nodes = []
371 1
        for row in nodesInRows:
372 1
            for node in nodesInRows[row]:
373 1
                nodes.append(node)
374 1
        return nodes
375
376 1
    def changePosition(self, positions, nodesInRows):
377 1
        x = 0.6
378 1
        upAndDown = True
379 1
        down = False
380 1
        downRow = False
381 1
        saveX = 0
382
383 1
        for row in nodesInRows:
384 1
            for node in nodesInRows[row]:
385 1
                if len(node['label']) > 6 and len(node['label']) < 40:
386 1
                    if upAndDown:
387 1
                        node['y'] = node['y'] + (0.6 * x)
388 1
                        upAndDown = False
389
                    else:
390 1
                        upAndDown = True
391 1
                elif len(node['label']) > 30:
392 1
                    node['y'] = node['y'] + (0.6 * x)
393 1
                    x += 0.6
394 1
                    saveX = x
395 1
                    down = True
396
                else:
397 1
                    if down:
398 1
                        node['y'] = node['y'] + (0.6 * saveX)
399
400 1
                    if downRow:
401 1
                        node['y'] = node['y'] + (0.6 * saveX) - 0.7
402 1
            if down:
403 1
                down = False
404 1
                downRow = True
405 1
            x = 0.6
406
407 1
    def center_graph(self, out):
408 1
        maxY = self.countMaxY(out)
409 1
        nodesInRows = self.createNodesInRows(maxY)
410 1
        self.pushNodesToNodesInRow(out, nodesInRows)
411 1
        self.removeEmptyRows(nodesInRows, maxY)
412 1
        nodesInRows = self.moveRows(nodesInRows)
413 1
        positions = self.createPositions(nodesInRows)
414 1
        self.changePosition(positions, nodesInRows)
415 1
        out['nodes'] = self.convertNodesInRowsToNodes(nodesInRows)
416 1
        return out
417
418 1
    def to_sigma_dict(self, x, y):
419 1
        return self.center_graph(
420
            self._remove_Duplication(
421
                self._help_to_sigma_dict(
422
                    x, y)))
423
424
425 1
def build_nodes_form_xml(xml_src, rule_id):
426 1
    parser = graph.xml_parser.xml_parser(xml_src)
427 1
    return parser.get_oval_graph(rule_id)
428
429
430 1
def restore_dict_to_tree(dict_of_tree):
431 1
    if dict_of_tree["child"] is None:
432 1
        return OvalNode(
433
            dict_of_tree["node_id"],
434
            dict_of_tree["type"],
435
            dict_of_tree["value"])
436 1
    return OvalNode(
437
        dict_of_tree["node_id"],
438
        dict_of_tree["type"],
439
        dict_of_tree["value"],
440
        [restore_dict_to_tree(i) for i in dict_of_tree["child"]])
441