1dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# Copyright (C) 2010 Google Inc. All rights reserved.
2dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#
3dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# Redistribution and use in source and binary forms, with or without
4dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# modification, are permitted provided that the following conditions are
5dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# met:
6dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#
7dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#     * Redistributions of source code must retain the above copyright
8dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# notice, this list of conditions and the following disclaimer.
9dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#     * Redistributions in binary form must reproduce the above
10dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# copyright notice, this list of conditions and the following disclaimer
11dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# in the documentation and/or other materials provided with the
12dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# distribution.
13dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#     * Neither the name of Google Inc. nor the names of its
14dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# contributors may be used to endorse or promote products derived from
15dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# this software without specific prior written permission.
16dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch#
17dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochimport datetime
3028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuimport itertools
3128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
32dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdochfrom google.appengine.ext import webapp
33dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdochfrom google.appengine.ext.webapp import template
34dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
35a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochfrom model.queues import Queue
36dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdochfrom model import queuestatus
37dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
38dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
39dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdochclass QueueStatus(webapp.RequestHandler):
40a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    def _rows_for_work_items(self, queue):
41a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        queued_items = queue.work_items()
42a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        active_items = queue.active_work_items()
43bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        if not queued_items:
44dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch            return []
45dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        rows = []
46bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        for item_id in queued_items.item_ids:
47dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch            rows.append({
48dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch                "attachment_id": item_id,
49dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch                "bug_id": 1,
50bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen                "lock_time": active_items and active_items.time_for_item(item_id),
51dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch            })
52dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        return rows
53dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
5428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    def _grouping_key_for_status(self, status):
5528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return "%s-%s" % (status.active_patch_id, status.bot_id)
5628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
5728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    def _build_status_groups(self, statuses):
5828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return [list(group) for key, group in itertools.groupby(statuses, self._grouping_key_for_status)]
5928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
60cad810f21b803229eb11403f9209855525a25d57Steve Block    def _fetch_statuses(self, queue, bot_id):
61cad810f21b803229eb11403f9209855525a25d57Steve Block        statuses = queuestatus.QueueStatus.all()
622daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        statuses.filter("queue_name =", queue.name())
63cad810f21b803229eb11403f9209855525a25d57Steve Block        if bot_id:
64cad810f21b803229eb11403f9209855525a25d57Steve Block            statuses.filter("bot_id =", bot_id)
65cad810f21b803229eb11403f9209855525a25d57Steve Block        return statuses.order("-date").fetch(15)
66cad810f21b803229eb11403f9209855525a25d57Steve Block
672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def _fetch_last_message_matching(self, queue, bot_id, message):
682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        statuses = queuestatus.QueueStatus.all()
692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        statuses.filter("queue_name =", queue.name())
702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if bot_id:
712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            statuses.filter("bot_id =", bot_id)
722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        statuses.filter("message =", message)
732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return statuses.order("-date").get()
742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    def _fetch_trailing_days_pass_count(self, queue, bot_id, days):
762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        statuses = queuestatus.QueueStatus.all()
772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        statuses.filter("queue_name =", queue.name())
782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        days_ago = datetime.datetime.now() - datetime.timedelta(days=days)
792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        statuses.filter("date >", days_ago)
802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if bot_id:
812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            statuses.filter("bot_id =", bot_id)
822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        statuses.filter("message =", "Pass")
832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return statuses.count()
842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
85cad810f21b803229eb11403f9209855525a25d57Steve Block    def _page_title(self, queue, bot_id):
86cad810f21b803229eb11403f9209855525a25d57Steve Block        title = "%s Messages" % queue.display_name()
87cad810f21b803229eb11403f9209855525a25d57Steve Block        if bot_id:
88cad810f21b803229eb11403f9209855525a25d57Steve Block            title += " from \"%s\"" % (bot_id)
89cad810f21b803229eb11403f9209855525a25d57Steve Block        return title
90cad810f21b803229eb11403f9209855525a25d57Steve Block
91cad810f21b803229eb11403f9209855525a25d57Steve Block    def get(self, queue_name, bot_id=None):
92a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        queue_name = queue_name.lower()
93a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        queue = Queue.queue_with_name(queue_name)
94a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if not queue:
95a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            self.error(404)
96a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            return
9768513a70bcd92384395513322f1b801e7bf9c729Steve Block
98cad810f21b803229eb11403f9209855525a25d57Steve Block        statuses = self._fetch_statuses(queue, bot_id)
99dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        template_values = {
100cad810f21b803229eb11403f9209855525a25d57Steve Block            "page_title": self._page_title(queue, bot_id),
101a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            "work_item_rows": self._rows_for_work_items(queue),
10228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            "status_groups": self._build_status_groups(statuses),
103cad810f21b803229eb11403f9209855525a25d57Steve Block            "bot_id": bot_id,
1042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            "last_pass": self._fetch_last_message_matching(queue, bot_id, "Pass"),
1052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            "last_boot": self._fetch_last_message_matching(queue, bot_id, "Starting Queue"),
1062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            "trailing_month_pass_count": self._fetch_trailing_days_pass_count(queue, bot_id, 30),
1072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            "trailing_week_pass_count": self._fetch_trailing_days_pass_count(queue, bot_id, 7),
108dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        }
109dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        self.response.out.write(template.render("templates/queuestatus.html", template_values))
110