Passed
Pull Request — master (#457)
by Jaspar
02:22
created

NotesMixin.create_note()   C

Complexity

Conditions 11

Size

Total Lines 74
Code Lines 41

Duplication

Lines 74
Ratio 100 %

Importance

Changes 0
Metric Value
cc 11
eloc 41
nop 11
dl 74
loc 74
rs 5.4
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like gvm.protocols.gmpv208.entities.notes.NotesMixin.create_note() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2021 Greenbone Networks GmbH
3
#
4
# SPDX-License-Identifier: GPL-3.0-or-later
5
#
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19
# pylint:  disable=redefined-builtin
20
# MAYBE we should change filter to filter_string (everywhere)
21
22
from typing import Any, List, Optional
23
24
from gvm.errors import RequiredArgument, InvalidArgumentType
25
from gvm.protocols.gmpv208.entities.severity import Severity, SeverityLevel
26
from gvm.utils import add_filter, to_comma_list, to_bool
27
from gvm.xml import XmlCommand
28
29
30
class NotesMixin:
31 View Code Duplication
    def create_note(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
32
        self,
33
        text: str,
34
        nvt_oid: str,
35
        *,
36
        days_active: Optional[int] = None,
37
        hosts: Optional[List[str]] = None,
38
        port: Optional[int] = None,
39
        result_id: Optional[str] = None,
40
        severity: Optional[Severity] = None,
41
        task_id: Optional[str] = None,
42
        threat: Optional[SeverityLevel] = None,
43
    ) -> Any:
44
        """Create a new note
45
46
        Arguments:
47
            text: Text of the new note
48
            nvt_id: OID of the nvt to which note applies
49
            days_active: Days note will be active. -1 on
50
                always, 0 off
51
            hosts: A list of hosts addresses
52
            port: Port to which the note applies
53
            result_id: UUID of a result to which note applies
54
            severity: Severity to which note applies
55
            task_id: UUID of task to which note applies
56
            threat: Severity level to which note applies. Will be converted to
57
                severity.
58
59
        Returns:
60
            The response. See :py:meth:`send_command` for details.
61
        """
62
        if not text:
63
            raise RequiredArgument(
64
                function=self.create_note.__name__, argument='text'
65
            )
66
67
        if not nvt_oid:
68
            raise RequiredArgument(
69
                function=self.create_note.__name__, argument='nvt_oid'
70
            )
71
72
        cmd = XmlCommand("create_note")
73
        cmd.add_element("text", text)
74
        cmd.add_element("nvt", attrs={"oid": nvt_oid})
75
76
        if days_active is not None:
77
            cmd.add_element("active", str(days_active))
78
79
        if hosts:
80
            cmd.add_element("hosts", to_comma_list(hosts))
81
82
        if port:
83
            cmd.add_element("port", str(port))
84
85
        if result_id:
86
            cmd.add_element("result", attrs={"id": result_id})
87
88
        if severity:
89
            cmd.add_element("severity", str(severity))
90
91
        if task_id:
92
            cmd.add_element("task", attrs={"id": task_id})
93
94
        if threat is not None:
95
            if not isinstance(threat, SeverityLevel):
96
                raise InvalidArgumentType(
97
                    function="create_note",
98
                    argument="threat",
99
                    arg_type=SeverityLevel.__name__,
100
                )
101
102
            cmd.add_element("threat", threat.value)
103
104
        return self._send_xml_command(cmd)
105
106
    def clone_note(self, note_id: str) -> Any:
107
        """Clone an existing note
108
109
        Arguments:
110
            note_id: UUID of an existing note to clone from
111
112
        Returns:
113
            The response. See :py:meth:`send_command` for details.
114
        """
115
        if not note_id:
116
            raise RequiredArgument(
117
                function=self.clone_note.__name__, argument='note_id'
118
            )
119
120
        cmd = XmlCommand("create_note")
121
        cmd.add_element("copy", note_id)
122
        return self._send_xml_command(cmd)
123
124
    def delete_note(
125
        self, note_id: str, *, ultimate: Optional[bool] = False
126
    ) -> Any:
127
        """Deletes an existing note
128
129
        Arguments:
130
            note_id: UUID of the note to be deleted.
131
            ultimate: Whether to remove entirely,or to the trashcan.
132
        """
133
        if not note_id:
134
            raise RequiredArgument(
135
                function=self.delete_note.__name__, argument='note_id'
136
            )
137
138
        cmd = XmlCommand("delete_note")
139
        cmd.set_attribute("note_id", note_id)
140
        cmd.set_attribute("ultimate", to_bool(ultimate))
141
142
        return self._send_xml_command(cmd)
143
144 View Code Duplication
    def get_notes(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
145
        self,
146
        *,
147
        filter: Optional[str] = None,
148
        filter_id: Optional[str] = None,
149
        details: Optional[bool] = None,
150
        result: Optional[bool] = None,
151
    ) -> Any:
152
        """Request a list of notes
153
154
        Arguments:
155
            filter: Filter term to use for the query
156
            filter_id: UUID of an existing filter to use for the query
157
            details: Add info about connected results and tasks
158
            result: Return the details of possible connected results.
159
160
        Returns:
161
            The response. See :py:meth:`send_command` for details.
162
        """
163
        cmd = XmlCommand("get_notes")
164
165
        add_filter(cmd, filter, filter_id)
166
167
        if details is not None:
168
            cmd.set_attribute("details", to_bool(details))
169
170
        if result is not None:
171
            cmd.set_attribute("result", to_bool(result))
172
173
        return self._send_xml_command(cmd)
174
175
    def get_note(self, note_id: str) -> Any:
176
        """Request a single note
177
178
        Arguments:
179
            note_id: UUID of an existing note
180
181
        Returns:
182
            The response. See :py:meth:`send_command` for details.
183
        """
184
        if not note_id:
185
            raise RequiredArgument(
186
                function=self.get_note.__name__, argument='note_id'
187
            )
188
189
        cmd = XmlCommand("get_notes")
190
        cmd.set_attribute("note_id", note_id)
191
192
        # for single entity always request all details
193
        cmd.set_attribute("details", "1")
194
        return self._send_xml_command(cmd)
195
196 View Code Duplication
    def modify_note(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
197
        self,
198
        note_id: str,
199
        text: str,
200
        *,
201
        days_active: Optional[int] = None,
202
        hosts: Optional[List[str]] = None,
203
        port: Optional[int] = None,
204
        result_id: Optional[str] = None,
205
        severity: Optional[Severity] = None,
206
        task_id: Optional[str] = None,
207
        threat: Optional[SeverityLevel] = None,
208
    ) -> Any:
209
        """Modifies an existing note.
210
211
        Arguments:
212
            note_id: UUID of note to modify.
213
            text: The text of the note.
214
            days_active: Days note will be active. -1 on always, 0 off.
215
            hosts: A list of hosts addresses
216
            port: Port to which note applies.
217
            result_id: Result to which note applies.
218
            severity: Severity to which note applies.
219
            task_id: Task to which note applies.
220
            threat: Threat level to which note applies. Will be converted to
221
                severity.
222
223
        Returns:
224
            The response. See :py:meth:`send_command` for details.
225
        """
226
        if not note_id:
227
            raise RequiredArgument(
228
                function=self.modify_note.__name__, argument='note_id'
229
            )
230
231
        if not text:
232
            raise RequiredArgument(
233
                function=self.modify_note.__name__, argument='text'
234
            )
235
236
        cmd = XmlCommand("modify_note")
237
        cmd.set_attribute("note_id", note_id)
238
        cmd.add_element("text", text)
239
240
        if days_active is not None:
241
            cmd.add_element("active", str(days_active))
242
243
        if hosts:
244
            cmd.add_element("hosts", to_comma_list(hosts))
245
246
        if port:
247
            cmd.add_element("port", str(port))
248
249
        if result_id:
250
            cmd.add_element("result", attrs={"id": result_id})
251
252
        if severity:
253
            cmd.add_element("severity", str(severity))
254
255
        if task_id:
256
            cmd.add_element("task", attrs={"id": task_id})
257
258
        if threat is not None:
259
260
            if not isinstance(threat, SeverityLevel):
261
                raise InvalidArgumentType(
262
                    function=self.modify_note.__name__,
263
                    argument='threat',
264
                    arg_type=SeverityLevel.__name__,
265
                )
266
267
            cmd.add_element("threat", threat.value)
268
269
        return self._send_xml_command(cmd)
270