Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(83)

Delta Between Two Patch Sets: codereview/models.py

Issue 955: Allow upload with no base (Closed) SVN Base: http://rietveld.googlecode.com/svn/trunk/
Left Patch Set: Created 3 months, 3 weeks ago
Right Patch Set: I incorporated the changes as per your comments in previous patch. Created 3 months, 3 weeks ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 # Copyright 2008 Google Inc. 1 # Copyright 2008 Google Inc.
2 # 2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); 3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License. 4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at 5 # You may obtain a copy of the License at
6 # 6 #
7 # http://www.apache.org/licenses/LICENSE-2.0 7 # http://www.apache.org/licenses/LICENSE-2.0
8 # 8 #
9 # Unless required by applicable law or agreed to in writing, software 9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, 10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and 12 # See the License for the specific language governing permissions and
13 # limitations under the License. 13 # limitations under the License.
14 14
15 """App Engine data model (schema) definition for Rietveld.""" 15 """App Engine data model (schema) definition for Rietveld."""
16 16
17 # Python imports 17 # Python imports
18 import logging 18 import logging
19 19
20 # AppEngine imports 20 # AppEngine imports
21 from google.appengine.api import users 21 from google.appengine.api import users
22 from google.appengine.ext import db 22 from google.appengine.ext import db
23 23
24 # Local imports 24 # Local imports
25 import engine 25 import engine
26 import patching 26 import patching
27 27
28 28
29 ### GQL query cache ### 29 ### GQL query cache ###
30 30
31 31
32 _query_cache = {} 32 _query_cache = {}
33 33
34 def gql(cls, clause, *args, **kwds): 34 def gql(cls, clause, *args, **kwds):
35 """Return a query object, from the cache if possible. 35 """Return a query object, from the cache if possible.
36 36
37 Args: 37 Args:
38 cls: a db.Model subclass. 38 cls: a db.Model subclass.
39 clause: a query clause, e.g. 'WHERE draft = TRUE'. 39 clause: a query clause, e.g. 'WHERE draft = TRUE'.
40 *args, **kwds: positional and keyword arguments to be bound to the query. 40 *args, **kwds: positional and keyword arguments to be bound to the query.
41 41
42 Returns: 42 Returns:
43 A db.GqlQuery instance corresponding to the query with *args and 43 A db.GqlQuery instance corresponding to the query with *args and
44 **kwds bound to the query. 44 **kwds bound to the query.
45 """ 45 """
46 query_string = 'SELECT * FROM %s %s' % (cls.kind(), clause) 46 query_string = 'SELECT * FROM %s %s' % (cls.kind(), clause)
47 query = _query_cache.get(query_string) 47 query = _query_cache.get(query_string)
48 if query is None: 48 if query is None:
49 _query_cache[query_string] = query = db.GqlQuery(query_string) 49 _query_cache[query_string] = query = db.GqlQuery(query_string)
50 query.bind(*args, **kwds) 50 query.bind(*args, **kwds)
51 return query 51 return query
52 52
53 53
54 ### Issues, PatchSets, Patches, Contents, Comments, Messages ### 54 ### Issues, PatchSets, Patches, Contents, Comments, Messages ###
55 55
56 56
57 class Issue(db.Model): 57 class Issue(db.Model):
58 """The major top-level entity. 58 """The major top-level entity.
59 59
60 It has one or more PatchSets as its descendants. 60 It has one or more PatchSets as its descendants.
61 """ 61 """
62 62
63 subject = db.StringProperty(required=True) 63 subject = db.StringProperty(required=True)
64 description = db.TextProperty() 64 description = db.TextProperty()
65 base = db.StringProperty() 65 base = None
GvR 2008/05/17 03:29:02 Why do you need that? You could just set it to th
GvR 2008/05/19 02:10:58 Have you actually tested this code? I meant leavi
66 owner = db.UserProperty(required=True) 66 owner = db.UserProperty(required=True)
67 created = db.DateTimeProperty(auto_now_add=True) 67 created = db.DateTimeProperty(auto_now_add=True)
68 modified = db.DateTimeProperty(auto_now=True) 68 modified = db.DateTimeProperty(auto_now=True)
69 reviewers = db.ListProperty(db.Email) 69 reviewers = db.ListProperty(db.Email)
70 closed = db.BooleanProperty(default=False) 70 closed = db.BooleanProperty(default=False)
71 71
72 _num_comments = None 72 _num_comments = None
73 73
74 @property 74 @property
75 def num_comments(self): 75 def num_comments(self):
76 """The number of (non-draft) comments for this issue. 76 """The number of (non-draft) comments for this issue.
77 77
78 The value is expensive to compute, so it is cached. 78 The value is expensive to compute, so it is cached.
79 """ 79 """
80 if self._num_comments is None: 80 if self._num_comments is None:
81 ## self._num_comments = gql(Comment, 81 ## self._num_comments = gql(Comment,
82 ## 'WHERE ANCESTOR IS :1 AND draft = FALSE', 82 ## 'WHERE ANCESTOR IS :1 AND draft = FALSE',
83 ## self).count() 83 ## self).count()
84 # XXX Somehow the index broke, do without it 84 # XXX Somehow the index broke, do without it
85 query = gql(Comment, 'WHERE ANCESTOR IS :1', self) 85 query = gql(Comment, 'WHERE ANCESTOR IS :1', self)
86 self._num_comments = len([x for x in query if not x.draft]) 86 self._num_comments = len([x for x in query if not x.draft])
87 # XXX End 87 # XXX End
88 return self._num_comments 88 return self._num_comments
89 89
90 _num_drafts = None 90 _num_drafts = None
91 91
92 @property 92 @property
93 def num_drafts(self): 93 def num_drafts(self):
94 """The number of draft comments on this issue for the current user. 94 """The number of draft comments on this issue for the current user.
95 95
96 The value is expensive to compute, so it is cached. 96 The value is expensive to compute, so it is cached.
97 """ 97 """
98 if self._num_drafts is None: 98 if self._num_drafts is None:
99 user = users.get_current_user() 99 user = users.get_current_user()
100 if user is None: 100 if user is None:
101 self._num_drafts = 0 101 self._num_drafts = 0
102 else: 102 else:
103 ## query = gql(Comment, 103 ## query = gql(Comment,
104 ## 'WHERE ANCESTOR IS :1 AND author = :2 AND draft = TRUE', 104 ## 'WHERE ANCESTOR IS :1 AND author = :2 AND draft = TRUE',
105 ## self, user) 105 ## self, user)
106 ## self._num_drafts = query.count() 106 ## self._num_drafts = query.count()
107 # XXX Somehow the index broke, do without it 107 # XXX Somehow the index broke, do without it
108 query = gql(Comment, 'WHERE ANCESTOR IS :1', self) 108 query = gql(Comment, 'WHERE ANCESTOR IS :1', self)
109 self._num_drafts = len([x for x in query 109 self._num_drafts = len([x for x in query
110 if x.author == user and x.draft]) 110 if x.author == user and x.draft])
111 # XXX End 111 # XXX End
112 return self._num_drafts 112 return self._num_drafts
113 113
114 114
115 class PatchSet(db.Model): 115 class PatchSet(db.Model):
(...skipping 270 matching lines...) Show 10 above Show 10 below
386 email = user.email() 386 email = user.email()
387 assert email 387 assert email
388 key = '<%s>' % email 388 key = '<%s>' % email
389 nickname = user.nickname() 389 nickname = user.nickname()
390 if '@' in nickname: 390 if '@' in nickname:
391 nickname = nickname.split('@', 1)[0] 391 nickname = nickname.split('@', 1)[0]
392 assert nickname 392 assert nickname
393 return cls.get_or_insert(key, user=user, email=email, nickname=nickname) 393 return cls.get_or_insert(key, user=user, email=email, nickname=nickname)
394 394
395 @classmethod 395 @classmethod
396 def get_nickname_for_user(cls, user): 396 def get_nickname_for_user(cls, user):
397 """Get the nickname for a user.""" 397 """Get the nickname for a user."""
398 return cls.get_account_for_user(user).nickname 398 return cls.get_account_for_user(user).nickname
399 399
400 @classmethod 400 @classmethod
401 def get_account_for_email(cls, email): 401 def get_account_for_email(cls, email):
402 """Get the Account for an email address, or return None.""" 402 """Get the Account for an email address, or return None."""
403 assert email 403 assert email
404 key = '<%s>' % email 404 key = '<%s>' % email
405 return cls.get_by_key_name(key) 405 return cls.get_by_key_name(key)
406 406
407 @classmethod 407 @classmethod
408 def get_nickname_for_email(cls, email): 408 def get_nickname_for_email(cls, email):
409 """Get the nickname for an email address, possibly a default.""" 409 """Get the nickname for an email address, possibly a default."""
410 account = cls.get_account_for_email(email) 410 account = cls.get_account_for_email(email)
411 if account is not None and account.nickname: 411 if account is not None and account.nickname:
412 return account.nickname 412 return account.nickname
413 nickname = email 413 nickname = email
414 if '@' in nickname: 414 if '@' in nickname:
415 nickname = nickname.split('@', 1)[0] 415 nickname = nickname.split('@', 1)[0]
416 assert nickname 416 assert nickname
417 return nickname 417 return nickname
418 418
419 @classmethod 419 @classmethod
420 def get_accounts_for_nickname(cls, nickname): 420 def get_accounts_for_nickname(cls, nickname):
421 """Get the list of Accounts that have this nickname.""" 421 """Get the list of Accounts that have this nickname."""
422 assert nickname 422 assert nickname
423 assert '@' not in nickname 423 assert '@' not in nickname
424 return list(gql(cls, 'WHERE nickname = :1', nickname)) 424 return list(gql(cls, 'WHERE nickname = :1', nickname))
425 425
426 @classmethod 426 @classmethod
427 def get_email_for_nickname(cls, nickname): 427 def get_email_for_nickname(cls, nickname):
428 """Turn a nickname into an email address. 428 """Turn a nickname into an email address.
429 429
430 If the nickname is not unique or does not exist, this returns None. 430 If the nickname is not unique or does not exist, this returns None.
431 """ 431 """
432 accounts = cls.get_accounts_for_nickname(nickname) 432 accounts = cls.get_accounts_for_nickname(nickname)
433 if len(accounts) != 1: 433 if len(accounts) != 1:
434 return None 434 return None
435 return accounts[0].email 435 return accounts[0].email
LEFTRIGHT

Powered by Google App Engine
This is Rietveld r305