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