blob: 54a91c02edf8acfc398fedd257e3dd207a58b0ff [file] [log] [blame]
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Builder Status management pages."""
import json
import time
from google.appengine.api import memcache
from google.appengine.ext import db
from base_page import BasePage
import utils
# The default number of builder status messages that are displayed.
DEFAULT_BUILDER_STATUS_CHUNK = 500
class BuilderStatus(db.Model):
"""Description for each builder."""
# The username who added this status.
username = db.StringProperty(required=True)
# The builder the status message applies to.
builder_name = db.StringProperty(required=True)
# The date when the status got added.
date = db.DateTimeProperty(auto_now_add=True)
# The message. It can contain html code.
message = db.StringProperty(required=True)
@classmethod
def delete_builder(cls, builder_name):
builders = cls.all().filter('builder_name =', builder_name).fetch(limit=1)
if builders:
builders[0].delete()
@classmethod
def get_status_for_builder(cls, builder_name):
builders = (BuilderStatus.all()
.filter('builder_name =', builder_name)
.fetch(limit=1))
return builders[0].message if builders else ''
def get_builder_statuses():
"""Returns all builder statuses."""
builder_statuses = memcache.get('builder_statuses')
if not builder_statuses:
builder_statuses = BuilderStatus.all().order('-date').fetch(
DEFAULT_BUILDER_STATUS_CHUNK)
memcache.add('builder_statuses', builder_statuses)
return builder_statuses
class GetBuilderStatusesPage(BasePage):
"""Returns a JSON of all builder statuses."""
def get(self):
builder_statuses = get_builder_statuses()
builder_dict = {}
for status in builder_statuses:
tmp_dict = {}
tmp_dict['message'] = status.message
tmp_dict['date'] = str(status.date)
tmp_dict['username'] = status.username
builder_dict[status.builder_name] = tmp_dict
html_output = json.dumps(builder_dict, sort_keys=True)
callback = self.request.get('callback')
if callback:
html_output = callback + '(' + html_output + ')'
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(html_output)
class BuilderStatusPage(BasePage):
"""Displays the builder status page containing msgs for some builders."""
@utils.require_user
def get(self):
return self._handle()
@utils.require_user
@utils.admin_only
def post(self):
"""Adds a new builder status message."""
# Check if this is a delete builder request.
delete_builder = self.request.get('delete')
if delete_builder:
BuilderStatus.delete_builder(delete_builder)
else:
message = self.request.get('message')
builder_name = self.request.get('builder_name')
# If an entry with the builder_name already exists then delete it first.
BuilderStatus.delete_builder(builder_name)
# Add a new BuilderStatus entry.
BuilderStatus(username=self.user.email(),
builder_name=builder_name,
message=message).put()
# Flush the cache.
memcache.flush_all()
memcache.delete('builder_statuses')
# Wait for a second before accessing the memcache again (in case there is a
# propagation delay).
time.sleep(1)
# Set template values and load the template.
self._handle()
def _handle(self):
"""Sets the information to be displayed on the builder status page."""
builder_statuses = get_builder_statuses()
template_values = self.InitializeTemplate('Builder Statuses')
template_values['builder_statuses'] = builder_statuses
selected_builder_name = self.request.get('selected_builder_name')
template_values['selected_builder_name'] = selected_builder_name
if selected_builder_name:
template_values['selected_builder_status'] = (
BuilderStatus.get_status_for_builder(selected_builder_name))
self.DisplayTemplate('builder_status.html', template_values)
def bootstrap():
# Guarantee that at least one instance exists.
if db.GqlQuery('SELECT __key__ FROM BuilderStatus').get() is None:
BuilderStatus(username='none', builder_name='TestBuilder',
message='welcome to status').put()