Passed
Push — master ( ae226f...980100 )
by Alexander
03:01
created

tcms.rpc.api.testplan   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 293
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 29
eloc 115
dl 0
loc 293
rs 10
c 0
b 0
f 0

10 Functions

Rating   Name   Duplication   Size   Complexity  
A add_attachment() 0 22 1
B _get_updated_test_plan() 0 25 8
A remove_tag() 0 18 1
A remove_case() 0 16 1
A add_case() 0 20 1
A list_attachments() 0 17 1
A filter() 0 17 2
A create() 0 51 4
C update() 0 38 9
A add_tag() 0 21 1
1
# -*- coding: utf-8 -*-
2
3
from modernrpc.core import rpc_method, REQUEST_KEY
4
5
from tcms.core.utils import form_errors_to_list
6
from tcms.management.models import Tag
7
from tcms.testplans.models import TestPlan
8
from tcms.testcases.models import TestCase, TestCasePlan
9
10
from tcms.rpc import utils
11
from tcms.rpc.api.forms.testplan import EditPlanForm, NewPlanForm
12
from tcms.rpc.decorators import permissions_required
13
14
__all__ = (
15
    'create',
16
    'update',
17
    'filter',
18
19
    'add_case',
20
    'remove_case',
21
22
    'add_tag',
23
    'remove_tag',
24
25
    'add_attachment',
26
    'list_attachments',
27
)
28
29
30
@permissions_required('testplans.add_testplan')
31
@rpc_method(name='TestPlan.create')
32
def create(values, **kwargs):
33
    """
34
    .. function:: XML-RPC TestPlan.create(values)
35
36
        Create new Test Plan object and store it in the database.
37
38
        :param values: Field values for :class:`tcms.testplans.models.TestPlan`
39
        :type values: dict
40
        :return: Serialized :class:`tcms.testplans.models.TestPlan` object
41
        :rtype: dict
42
        :raises: PermissionDenied if missing *testplans.add_testplan* permission
43
        :raises: ValueError if data validation fails
44
45
        Minimal parameters::
46
47
            >>> values = {
48
                'product': 61,
49
                'name': 'Testplan foobar',
50
                'type': 1,
51
                'parent_id': 150,
52
                'default_product_version': 93,
53
                'text':'Testing TCMS',
54
            }
55
            >>> TestPlan.create(values)
56
    """
57
    if values.get('default_product_version'):
58
        values['product_version'] = values.pop('default_product_version')
59
60
    if not values.get('product'):
61
        raise ValueError('Value of product is required')
62
63
    form = NewPlanForm(values)
64
    form.populate(product_id=values['product'])
65
66
    if form.is_valid():
67
        request = kwargs.get(REQUEST_KEY)
68
        test_plan = TestPlan.objects.create(
69
            product=form.cleaned_data['product'],
70
            name=form.cleaned_data['name'],
71
            type=form.cleaned_data['type'],
72
            author=request.user,
73
            product_version=form.cleaned_data['product_version'],
74
            parent=form.cleaned_data['parent'],
75
            is_active=form.cleaned_data['is_active'],
76
            text=form.cleaned_data['text'],
77
        )
78
79
        return test_plan.serialize()
80
    raise ValueError(form_errors_to_list(form))
81
82
83
@rpc_method(name='TestPlan.filter')
84
def filter(query=None):  # pylint: disable=redefined-builtin
85
    """
86
    .. function:: XML-RPC TestPlan.filter(query)
87
88
        Perform a search and return the resulting list of test plans.
89
90
        :param query: Field lookups for :class:`tcms.testplans.models.TestPlan`
91
        :type query: dict
92
        :return: List of serialized :class:`tcms.testplans.models.TestPlan` objects
93
        :rtype: list(dict)
94
    """
95
96
    if query is None:
97
        query = {}
98
99
    return TestPlan.to_xmlrpc(query)
100
101
102
@permissions_required('testplans.add_testplantag')
103
@rpc_method(name='TestPlan.add_tag')
104
def add_tag(plan_id, tag_name, **kwargs):
105
    """
106
    .. function:: XML-RPC TestPlan.add_tag(plan_id, tag_name)
107
108
        Add a tag to the specified test plan.
109
110
        :param plan_id: PK of TestPlan to modify
111
        :type plan_id: int
112
        :param tag_name: Tag name to add
113
        :type tag_name: str
114
        :return: None
115
        :raises: PermissionDenied if missing *testplans.add_testplantag* permission
116
        :raises: TestPlan.DoesNotExist if object specified by PK doesn't exist
117
        :raises: Tag.DoesNotExist if missing *management.add_tag* permission and *tag_name*
118
                 doesn't exist in the database!
119
    """
120
    request = kwargs.get(REQUEST_KEY)
121
    tag, _ = Tag.get_or_create(request.user, tag_name)
122
    TestPlan.objects.get(pk=plan_id).add_tag(tag)
123
124
125
@permissions_required('testplans.delete_testplantag')
126
@rpc_method(name='TestPlan.remove_tag')
127
def remove_tag(plan_id, tag_name):
128
    """
129
    .. function:: XML-RPC TestPlan.remove_tag(plan_id, tag_name)
130
131
        Remove tag from the specified test plan.
132
133
        :param plan_id: PK of TestPlan to modify
134
        :type plan_id: int
135
        :param tag_name: Tag name to remove
136
        :type tag_name: str
137
        :return: None
138
        :raises: PermissionDenied if missing *testplans.delete_testplantag* permission
139
        :raises: DoesNotExist if objects specified don't exist
140
    """
141
    tag = Tag.objects.get(name=tag_name)
142
    TestPlan.objects.get(pk=plan_id).remove_tag(tag)
143
144
145
@permissions_required('testplans.change_testplan')
146
@rpc_method(name='TestPlan.update')
147
def update(plan_id, values):
148
    """
149
    .. function:: XML-RPC TestPlan.update(plan_id, values)
150
151
        Update the fields of the selected test plan.
152
153
        :param plan_id: PK of TestPlan to modify
154
        :type plan_id: int
155
        :param values: Field values for :class:`tcms.testplans.models.TestPlan`
156
        :type values: dict
157
        :return: Serialized :class:`tcms.testplans.models.TestPlan` object
158
        :rtype: dict
159
        :raises: TestPlan.DoesNotExist if object specified by PK doesn't exist
160
        :raises: PermissionDenied if missing *testplans.change_testplan* permission
161
        :raises: ValueError if validations fail
162
    """
163
164
    if values.get('default_product_version'):
165
        values['product_version'] = values.pop('default_product_version')
166
167
    if values.get('product_version') and not values.get('product'):
168
        raise ValueError('Field "product" is required by product_version')
169
170
    if values.get('product') and not values.get('product_version'):
171
        raise ValueError('Field "product_version" is required by product')
172
173
    form = EditPlanForm(values)
174
    if values.get('product_version') and values.get('product'):
175
        form.populate(product_id=values['product'])
176
177
    test_plan = TestPlan.objects.get(pk=plan_id)
178
179
    if form.is_valid():
180
        return _get_updated_test_plan(values, form, test_plan).serialize()
181
182
    raise ValueError(form_errors_to_list(form))
183
184
185
def _get_updated_test_plan(values, form, test_plan):
186
    if form.cleaned_data['name']:
187
        test_plan.name = form.cleaned_data['name']
188
189
    if form.cleaned_data['type']:
190
        test_plan.type = form.cleaned_data['type']
191
192
    if form.cleaned_data['product']:
193
        test_plan.product = form.cleaned_data['product']
194
195
    if form.cleaned_data['product_version']:
196
        test_plan.product_version = form.cleaned_data['product_version']
197
198
    if form.cleaned_data['parent']:
199
        test_plan.parent = form.cleaned_data['parent']
200
201
    if values.get('is_active') is not None:
202
        test_plan.is_active = form.cleaned_data['is_active']
203
204
    if form.cleaned_data['text']:
205
        test_plan.text = form.cleaned_data['text']
206
207
    test_plan.save()
208
209
    return test_plan
210
211
212
@permissions_required('testcases.add_testcaseplan')
213
@rpc_method(name='TestPlan.add_case')
214
def add_case(plan_id, case_id):
215
    """
216
    .. function:: XML-RPC TestPlan.add_case(plan_id, case_id)
217
218
        Link test case to the given plan.
219
220
        :param plan_id: PK of TestPlan to modify
221
        :type plan_id: int
222
        :param case_id: PK of TestCase to be added to plan
223
        :type case_id: int
224
        :return: None
225
        :raises: TestPlan.DoesNotExit or TestCase.DoesNotExist if objects specified
226
                 by PKs are missing
227
        :raises: PermissionDenied if missing *testcases.add_testcaseplan* permission
228
    """
229
    plan = TestPlan.objects.get(pk=plan_id)
230
    case = TestCase.objects.get(pk=case_id)
231
    plan.add_case(case)
232
233
234
@permissions_required('testcases.delete_testcaseplan')
235
@rpc_method(name='TestPlan.remove_case')
236
def remove_case(plan_id, case_id):
237
    """
238
    .. function:: XML-RPC TestPlan.remove_case(plan_id, case_id)
239
240
        Unlink a test case from the given plan.
241
242
        :param plan_id: PK of TestPlan to modify
243
        :type plan_id: int
244
        :param case_id: PK of TestCase to be removed from plan
245
        :type case_id: int
246
        :return: None
247
        :raises: PermissionDenied if missing *testcases.delete_testcaseplan* permission
248
    """
249
    TestCasePlan.objects.filter(case=case_id, plan=plan_id).delete()
250
251
252
@permissions_required('attachments.view_attachment')
253
@rpc_method(name='TestPlan.list_attachments')
254
def list_attachments(plan_id, **kwargs):
255
    """
256
    .. function:: XML-RPC TestPlan.list_attachments(plan_id)
257
258
        List attachments for the given TestPlan.
259
260
        :param plan_id: PK of TestPlan to inspect
261
        :type plan_id: int
262
        :return: A list containing information and download URLs for attachements
263
        :rtype: list
264
        :raises: TestPlan.DoesNotExit if object specified by PK is missing
265
    """
266
    plan = TestPlan.objects.get(pk=plan_id)
267
    request = kwargs.get(REQUEST_KEY)
268
    return utils.get_attachments_for(request, plan)
269
270
271
@permissions_required('attachments.add_attachment')
272
@rpc_method(name='TestPlan.add_attachment')
273
def add_attachment(plan_id, filename, b64content, **kwargs):
274
    """
275
    .. function:: XML-RPC TestPlan.add_attachment(plan_id, filename, b64content)
276
277
        Add attachment to the given TestPlan.
278
279
        :param plan_id: PK of TestPlan
280
        :type plan_id: int
281
        :param filename: File name of attachment, e.g. 'logs.txt'
282
        :type filename: str
283
        :param b64content: Base64 encoded content
284
        :type b64content: str
285
        :return: None
286
    """
287
    utils.add_attachment(
288
        plan_id,
289
        'testplans.TestPlan',
290
        kwargs.get(REQUEST_KEY).user,
291
        filename,
292
        b64content)
293