Passed
Push — master ( 786833...afd6fa )
by Alexander
02:28
created

tcms.core.views.IterOpen.timestamp()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
# -*- coding: utf-8 -*-
2
import os
3
import subprocess  # nosec:B404:import_subprocess
4
import time
5
6
from django import http
7
from django.conf import settings
8
from django.contrib.auth.decorators import login_required
9
from django.db.models import Count, Q
10
from django.http import HttpResponseRedirect, StreamingHttpResponse
11
from django.template import loader
12
from django.urls import reverse
13
from django.utils import timezone, translation
14
from django.utils.decorators import method_decorator
15
from django.utils.translation import trans_real
16
from django.views import i18n
17
from django.views.decorators.csrf import requires_csrf_token
18
from django.views.generic.base import TemplateView, View
19
20
from tcms.testplans.models import TestPlan
21
from tcms.testruns.models import TestRun
22
23
24
@method_decorator(
25
    login_required, name="dispatch"
26
)  # pylint: disable=missing-permission-required
27
class DashboardView(TemplateView):
28
29
    template_name = "dashboard.html"
30
31
    def get_context_data(self, **kwargs):
32
        """List all recent TestPlans and TestRuns"""
33
        test_plans = (
34
            TestPlan.objects.filter(author=self.request.user)
35
            .order_by("-pk")
36
            .select_related("product", "type")
37
            .annotate(num_runs=Count("run", distinct=True))
38
        )
39
        test_plans_disable_count = test_plans.filter(is_active=False).count()
40
41
        test_runs = (
42
            TestRun.objects.filter(
43
                Q(manager=self.request.user)
44
                | Q(default_tester=self.request.user)
45
                | Q(executions__assignee=self.request.user),
46
                stop_date__isnull=True,
47
            )
48
            .order_by("-pk")
49
            .distinct()
50
        )
51
52
        return {
53
            "test_plans_count": test_plans.count(),
54
            "test_plans_disable_count": test_plans_disable_count,
55
            "last_15_test_plans": test_plans.filter(is_active=True)[:15],
56
            "last_15_test_runs": test_runs[:15],
57
            "test_runs_count": test_runs.count(),
58
        }
59
60
61
@requires_csrf_token
62
def server_error(request):  # pylint: disable=missing-permission-required
63
    """
64
    Render the error page with request object which supports
65
    static URLs so we can load a nice picture.
66
    """
67
    template = loader.get_template("500.html")
68
    return http.HttpResponseServerError(template.render({}, request))
69
70
71
class IterOpen(subprocess.Popen):  # pylint: disable=missing-permission-required
72
    """
73
    Popen which allows us to iterate over the output so we can
74
    stream it back to the browser with some extra eye candy!
75
    """
76
77
    still_waiting = True
78
    has_completed = False
79
80
    @property
81
    def timestamp(self):
82
        return timezone.now().isoformat().replace("T", " ") + " init-db: "
83
84
    def __iter__(self):
85
        os.set_blocking(self.stdout.fileno(), False)
86
        return self
87
88
    def __next__(self):
89
        line = self.stdout.readline()
90
91
        if not line:
92
            if self.still_waiting:
93
                time.sleep(3)
94
                return self.timestamp + "waiting for migrations to start\n"
95
96
            if not self.has_completed:
97
                self.has_completed = True
98
                return self.timestamp + "Complete!\n"
99
100
            # instruct the streaming response to stop streaming
101
            raise StopIteration
102
103
        self.still_waiting = False
104
        return self.timestamp + line.lstrip()
105
106
107
class InitDBView(TemplateView):  # pylint: disable=missing-permission-required
108
109
    template_name = "initdb.html"
110
111
    def post(self, request):
112
        # Default production installation
113
        manage_path = "/Kiwi/manage.py"
114
        if not os.path.exists(manage_path):
115
            # Development installation
116
            manage_path = os.path.join(settings.TCMS_ROOT_PATH, "..", "manage.py")
117
118
        if "init_db" in request.POST:
119
            # Perform migrations
120
            proc = IterOpen(
121
                [manage_path, "migrate"],
122
                stdout=subprocess.PIPE,
123
                stderr=subprocess.STDOUT,
124
                bufsize=1,  # line buffered
125
                universal_newlines=True,
126
            )
127
            response = StreamingHttpResponse(
128
                proc, content_type="text/plain; charset=utf-8"
129
            )
130
            response["Cache-Control"] = "no-cache"
131
            return response
132
133
        return HttpResponseRedirect(reverse("init-db"))
134
135
136
class TranslationMode(View):  # pylint: disable=missing-permission-required
137
    """
138
    Turns on and off translation mode by switching language to
139
    Esperanto!
140
    """
141
142
    @staticmethod
143
    def get_browser_language(request):
144
        """
145
        Returns *ONLY* the language that is sent by the browser via the
146
        Accept-Language headers. Defaults to ``settings.LANGUAGE_CODE`` if
147
        that doesn't work!
148
149
        This is the language we switch back to when translation mode is turned off.
150
151
        Copied from the bottom half of
152
        ``django.utils.translation.trans_real.get_language_from_request()``
153
154
        .. note::
155
156
            Using ``get_language_from_request()`` doesn't work for us because
157
            it first inspects session and cookies and we've already set Esperanto
158
            in both the session and the cookie!
159
        """
160
        accept = request.META.get("HTTP_ACCEPT_LANGUAGE", "")
161
        for accept_lang, _unused in trans_real.parse_accept_lang_header(accept):
162
            if accept_lang == "*":
163
                break
164
165
            if not trans_real.language_code_re.search(accept_lang):
166
                continue
167
168
            try:
169
                return translation.get_supported_language_variant(accept_lang)
170
            except LookupError:
171
                continue
172
173
        try:
174
            return translation.get_supported_language_variant(settings.LANGUAGE_CODE)
175
        except LookupError:
176
            return settings.LANGUAGE_CODE
177
178
    def get(self, request):
179
        """
180
        In the HTML template we'd like to work with simple links
181
        however the view which actually switches the language needs
182
        to be called via POST so we simulate that here!
183
184
        If the URL doesn't explicitly specify language then we turn-off
185
        translation mode by switching back to browser preferred language.
186
        """
187
        browser_lang = self.get_browser_language(request)
188
        post_body = "%s=%s" % (
189
            i18n.LANGUAGE_QUERY_PARAMETER,
190
            request.GET.get(i18n.LANGUAGE_QUERY_PARAMETER, browser_lang),
191
        )
192
        request.META["REQUEST_METHOD"] = "POST"
193
        request.META["CONTENT_LENGTH"] = len(post_body)
194
        request.META["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
195
196
        post_request = request.__class__(request.META)
197
        # pylint: disable=protected-access
198
        post_request._post = http.QueryDict(post_body, encoding=post_request._encoding)
199
200
        return i18n.set_language(post_request)
201