def send_to_stage(push): assert push.state in ('accepting', 'onstage') checkedin_requests = query.push_requests(push, state='checkedin') if checkedin_requests: if push.state != 'onstage': push.state = 'onstage' push.put() for request in checkedin_requests: request.state = 'onstage' if request.no_testing: set_request_tested(request, bust_caches=False) else: owner_email = request.owner.email() send_mail( to=[owner_email, config.mail_to], subject='Re: ' + request.subject, body='Please check your changes on stage.\n' + config.url(push.uri)) im_fields = dict( pushmaster_email=html_escape(push.owner.email()), pushmaster_name=html_escape(push.owner.nickname()), request_subject=html_escape(request.subject), uri=html_escape(config.url(push.uri)), ) send_im(owner_email, '<a href="mailto:%(pushmaster_email)s">%(pushmaster_name)s</a> requests that you check your changes on stage for <a href="%(uri)s">%(request_subject)s</a>.' % im_fields) request.put() push.bust_requests_cache() return push
def get(self, push_id): push = None if push_id == 'current': push = query.current_push() self.redirect(push.uri if push else '/pushes') return try: push = model.Push.get(push_id) except BadKeyError: raise HTTPStatusCode(httplib.NOT_FOUND) current_user = users.get_current_user() pending_requests = query.pending_requests(not_after=util.tznow().date()) if current_user == push.owner else [] if 'application/json' in self.get_request_header_list('Accept', default='*/*'): requests = query.push_requests(push) push_div = self.render_push_div(current_user, push, requests, pending_requests) response = {'push': dict(key=unicode(push.key()), state=push.state), 'html': unicode(push_div)} self.response.headers['Vary'] = 'Accept' self.response.headers['Content-Type'] = 'application/json' self.response.headers['Cache-Control'] = 'no-store' self.response.out.write(json.dumps(response)) else: doc = self.render_doc(current_user, push, pending_requests) self.response.out.write(unicode(doc))
def get(self, push_id): push = None if push_id == 'current': push = query.current_push() self.redirect(push.api_uri if push else '/pushes') return try: push = model.Push.get(push_id) except BadKeyError: raise HTTPStatusCode(httplib.NOT_FOUND) current_user = users.get_current_user() pending_requests = query.pending_requests(not_after=util.tznow().date()) if current_user == push.owner else [] requests = query.push_requests(push) push_info = self.render_push_info(push, requests) request_info = self.render_request_info(pending_requests) response = {'push': push_info, 'pending_requests': request_info} self.response.headers['Vary'] = 'Accept' self.response.headers['Content-Type'] = 'application/json' self.response.headers['Cache-Control'] = 'no-store' self.response.out.write(json.dumps(response))
def receive(self, mail_message): sender = mail_message.sender logging.debug('got mail from %s', sender) text_bodies = [body for content_type, body in mail_message.bodies('text/plain')] if not text_bodies: return text_body = text_bodies[0] # TODO: support multiple bodies to = mail_message.to match = self.push_key_address_re.match(to) if match is None: logging.warning('failed to match push address: %s', to) return try: push_key = match.group(1) push = model.Push.get(push_key) requester_emails = list(set([request.owner.email() for request in query.push_requests(push)])) kw = dict(sender=sender, to=requester_emails, subject=mail_message.subject, body=text_body, reply_to=sender) logging.info('sending push mail: %r', kw) util.send_mail(**kw) except BadKeyError: logging.warning('failed to find push %s', push_key)
def get(self, datestr): from_date, to_date = report_date_range(datestr) doc = common.Document(title='pushmaster: reports') doc.body(T.h1('Report for ', from_date.strftime('%e %b %Y'), ' - ', to_date.strftime('%e %b %Y'))) pushes = query.pushes_for_the_week_of(from_date) for push in pushes: pushdiv = T.div(class_='push') pushdiv(T.h2( T.a(href=push.uri)( push.ltime.replace(tzinfo=timezone.UTC()).astimezone(config.timezone).strftime('%a, %l:%M %p, %e %b %Y'), T.span(' '), push.name or '', ), T.span(' by '), common.display_user_email(push.owner), )) reqlist = T.ol(class_='requests') for request in query.push_requests(push): reqlist(common.request_item(request)) pushdiv(reqlist) doc.body(pushdiv) doc.body(common.jquery_js, common.jquery_ui_js, common.pushmaster_js) doc.serialize(self.response.out)
def render(self, push, current_user, pending_requests): requests = query.push_requests(push) push_div = self.render_push_div(current_user, push, requests, pending_requests) response = {'push': dict(key=unicode(push.key()), state=push.state), 'html': unicode(push_div)} self.response.headers['Vary'] = 'Accept' self.response.headers['Content-Type'] = 'application/json' self.response.headers['Cache-Control'] = 'no-store' json.dump(response, self.response.out)
def render_doc(self, current_user, push, pending_requests): doc = common.Document(title='pushmaster: push: ' + logic.format_datetime(push.ptime)) requests = query.push_requests(push) push_div = self.render_push_div(current_user, push, requests, pending_requests) doc.body(push_div) doc.body(common.jquery_js, common.jquery_ui_js, common.pushmaster_js, common.script('/js/push.js')) push_json = ScriptCData('this.push = %s;' % json.dumps(dict(key=str(push.key()), state=push.state))) doc.head(T.script(type='text/javascript')(push_json)) return doc
def push_item(push): requests = query.push_requests(push) return T.li(class_='push')( T.div( common.display_datetime(push.ptime), T.a(href=push.uri)(push.name or 'push'), common.user_home_link(push.owner, logic.user_info(push.owner)), T.span(class_='state')(common.display_push_state(push)), class_='headline', ), T.ol(map(common.request_item, requests)) if requests else T.div('No requests.'), )
def render_doc(self, push, current_user, pending_requests): doc = common.Document(title='pushmaster: push: %s %s' % (util.format_datetime(push.ptime), push.name)) doc.funcbar(T.span('|', class_='sep'), common.push_email(push, 'Send Mail to Requesters')) requests = query.push_requests(push) push_div = self.render_push_div(current_user, push, requests, pending_requests) doc.body(push_div) doc.scripts(common.script('/js/push.js')) push_json = ScriptCData('this.push = %s;' % json.dumps(dict(key=str(push.key()), state=push.state))) doc.head(T.script(type='text/javascript')(push_json)) return doc
def force_live(push): for request in query.push_requests(push): request.state = 'live' request.put() push.bust_requests_cache() push.state = 'live' push.ltime = push.mtime push.put() return push
def abandon_push(push): assert push.state in ('accepting', 'onstage') push.state = 'abandoned' for request in query.push_requests(push): request.state = 'requested' request.push = None request.put() push.put() query.bust_request_caches() push.bust_requests_cache() return push
def get(self, datestr=None): if datestr: from_date, to_date = report_date_range(datestr) else: for_date = last_monday_datetime() - datetime.timedelta(days=7) return self.redirect('/lastweek/' + for_date.strftime('%Y%m%d')) pushes = query.pushes_for_the_week_of(from_date) requests = [] for push in pushes: requests.extend(query.push_requests(push)) requests = sorted(requests, key=lambda r: r.mtime) doc = common.Document(title='pushmaster: weekly report: ' + datestr) teams_list = T.ul(class_='teams') doc(teams_list) nothing_messages_list = None for team in config.report_users: team_item = T.li(class_='team')(T.h3(team['name'])) teams_list(team_item) devs_list = T.ul(class_='devs') team_item(devs_list) for dev in sorted(team['dev']): dev_item = T.li(class_='dev')(T.h4(dev)) devs_list(dev_item) dev_requests = filter(lambda r: r.owner.nickname() == dev, requests) if dev_requests: requests_list = T.ol(class_='requests')(map(common.request_item, dev_requests)) dev_item(requests_list) else: # lazy (re)initialize random messages if not nothing_messages_list: nothing_messages_list = list(config.nothing_messages) import random random.shuffle(nothing_messages_list) dev_item(T.div(nothing_messages_list.pop(), class_='nothing')) if 'prod' in team: team_item(T.h4('PM: ' if len(team['prod']) == 1 else 'PMs: ', ', '.join(team['prod']), class_='pm')) doc.serialize(self.response.out)
def send_to_live(push): assert push.state == 'onstage' requests = query.push_requests(push) for request in requests: assert request.state in ('tested', 'live') for request in requests: request.state = 'live' request.put() push.state = 'live' push.ltime = datetime.datetime.utcnow() push.put() push.bust_requests_cache() return push
def set_request_tested(request, bust_caches=True): assert request.state == 'onstage' push = request.push assert push request.state = 'tested' request.put() if bust_caches: push.bust_requests_cache() push_owner_email = push.owner.email() send_mail( to=[push_owner_email, config.mail_to], subject='Re: ' + request.subject, body='Looks good to me.\n' + config.url(push.uri)) if all(request.state == 'tested' for request in query.push_requests(push)): send_im(push_owner_email, 'All changes for <a href="%s">the push</a> are tested on stage.' % config.url(push.uri)) return request