Chromium Code Reviews| Index: status.py |
| diff --git a/status.py b/status.py |
| index fc37e40ea896dcbff03fe3c5f8f14ea01ca3670c..2f8a00aa6ad9bdf4b36c40304fd7da1c2c8988ff 100644 |
| --- a/status.py |
| +++ b/status.py |
| @@ -22,6 +22,101 @@ ALLOWED_ORIGINS = [ |
| ] |
| +class Link(object): |
| + """Simple object to hold text that might be linked""" |
|
M-A Ruel
2013/11/25 16:18:14
"""Holds text ..
No need to state a relative qual
vapier
2013/11/25 17:51:26
i agree it's simple, but i find scanning a one lin
|
| + |
| + def __init__(self, text, target=None, is_email=False): |
|
M-A Ruel
2013/11/25 16:18:14
I'd prefer to not use default arguments.
vapier
2013/11/25 17:51:26
any reason why ? the intention is for email to be
|
| + self.text = text |
| + self.target = target |
| + self.is_email = is_email |
| + |
| + def __repr__(self): |
| + return 'Link({%s->%s})' % (self.text, self.target) |
| + |
| + |
| +class LinkableText(object): |
| + """Turn arbitrary text into a set of links""" |
|
M-A Ruel
2013/11/25 16:18:14
Turns
(imperative everywhere)
vapier
2013/11/25 17:51:26
i dont see the point, but i also dont really care
|
| + |
| + GERRIT_URLS = { |
| + 'chrome': 'https://chrome-internal-review.googlesource.com', |
|
M-A Ruel
2013/11/25 16:18:14
Very hardcoded. :/ Could these be entities?
vapier
2013/11/25 17:51:26
i have no idea what "entities" are. plus this fil
|
| + 'chromium': 'https://chromium-review.googlesource.com', |
| + } |
| + |
| + WATERFALL_URLS = { |
| + 'chromeos': 'http://chromegw/i/chromeos', |
| + 'chromiumos': 'http://build.chromium.org/p/chromiumos', |
| + } |
| + |
| + # Automatically linkify convert known strings for the user. |
| + _CONVERTS = [ |
| + # Convert CrOS bug links. Support the forms: |
| + # http://crbug.com/1234 |
| + # http://crosbug.com/1234 |
| + # crbug/1234 |
| + # crosbug/p/1234 |
| + (re.compile( |
| + # 1 2 3 4 5 6 7 |
| + r'\b((http://)?((crbug|crosbug)(\.com)?(/(p/)?[0-9]+)))\b', |
| + flags=re.I), |
| + r'http://\4.com\6', r'\1', False), |
| + |
| + # Convert e-mail addresses. |
| + (re.compile(r'(([-+.a-z0-9_!#$%&*/=?^_`{|}~]+)@[-a-z0-9.]+\.[a-z0-9]+)\b', |
| + flags=re.I), |
| + r'\1', r'\2', True), |
| + |
| + # Convert SHA1's to gerrit links. Assume all external since |
| + # there is no sane way to detect it's an internal CL. |
| + (re.compile(r'\b([0-9a-f]{40})\b', flags=re.I), |
| + r'%s/#q,\1,n,z' % GERRIT_URLS['chromium'], r'\1', False), |
| + |
| + # Convert public gerrit CL numbers. |
| + (re.compile(r'\b(CL:([0-9]+))\b', flags=re.I), |
| + r'%s/\2' % GERRIT_URLS['chromium'], r'\1', False), |
| + # Convert internal gerrit CL numbers. |
| + (re.compile(r'\b(CL:\*([0-9]+))\b', flags=re.I), |
| + r'%s/\2' % GERRIT_URLS['chrome'], r'\1', False), |
| + ] |
| + |
| + @classmethod |
| + def bootstrap(cls, _app_name): |
| + """Add conversions specific to |app_name| instance""" |
| + cls._CONVERTS += [ |
| + # Do this for everyone since "cbuildbot" is unique to CrOS. |
| + # Match the string: |
| + # Automatic: "cbuildbot" on "x86-generic ASAN" from. |
| + (re.compile(r'("cbuildbot" on "([^"]+ canary)")', |
|
M-A Ruel
2013/11/25 16:18:14
These should be stated as static lists. There isn'
vapier
2013/11/25 17:51:26
this was needed in a previous CL where i used a fu
|
| + flags=re.I), |
| + r'%s/builders/\2' % cls.WATERFALL_URLS['chromeos'], r'\1', False), |
| + (re.compile(r'("cbuildbot" on "([^"]+)")', |
| + flags=re.I), |
| + r'%s/builders/\2' % cls.WATERFALL_URLS['chromiumos'], r'\1', False), |
| + ] |
| + |
| + @classmethod |
| + def parse(cls, text): |
| + """Create a list of Link objects based on |text|""" |
| + if not text: |
| + return [] |
| + for prog, target, pretty_text, is_email in cls._CONVERTS: |
| + m = prog.search(text) |
| + if m: |
| + link = Link(m.expand(pretty_text), |
| + target=m.expand(target), |
| + is_email=is_email) |
| + left_links = cls.parse(text[:m.start()].rstrip()) |
| + right_links = cls.parse(text[m.end():].lstrip()) |
| + return left_links + [link] + right_links |
| + return [Link(text)] |
| + |
| + def __init__(self, text): |
| + self.raw_text = text |
| + self.links = self.parse(text.strip()) |
| + |
| + def __str__(self): |
| + return self.raw_text |
| + |
| + |
| class Status(db.Model): |
| """Description for the status table.""" |
| # The username who added this status. |
| @@ -31,6 +126,14 @@ class Status(db.Model): |
| # The message. It can contain html code. |
| message = db.StringProperty(required=True) |
| + def __init__(self, *args, **kwargs): |
| + # Normalize newlines otherwise the DB store barfs. |
|
M-A Ruel
2013/11/25 16:18:14
I'm fine with adding multiline=True instead. Actua
vapier
2013/11/25 17:51:26
i don't think we want people to insert newlines in
|
| + kwargs['message'] = kwargs.get('message', '').replace('\n', '') |
| + |
| + super(Status, self).__init__(*args, **kwargs) |
| + self.username_links = LinkableText(self.username) |
| + self.message_links = LinkableText(self.message) |
| + |
| @property |
| def general_state(self): |
| """Returns a string representing the state that the status message |
| @@ -246,6 +349,8 @@ class MainPage(BasePage): |
| def _handle(self, error_message='', last_message=''): |
| """Sets the information to be displayed on the main page.""" |
| + LinkableText.bootstrap(self.APP_NAME) |
|
M-A Ruel
2013/11/25 16:18:14
This is a bad idea to do this there. It creates a
vapier
2013/11/25 17:51:26
i'm not terribly familiar with the app engine mode
|
| + |
| try: |
| limit = min(max(int(self.request.get('limit')), 1), 1000) |
| except ValueError: |