OLD | NEW |
1 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 # for details. All rights reserved. Use of this source code is governed by a | 2 # for details. All rights reserved. Use of this source code is governed by a |
3 # BSD-style license that can be found in the LICENSE file. | 3 # BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import cgi | 5 import cgi |
6 import json | 6 import json |
7 import logging | 7 import logging |
8 | 8 |
9 from google.appengine.api import memcache | 9 from google.appengine.api import memcache |
10 from google.appengine.api import users | 10 from google.appengine.api import users |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 cgi.escape(email), cgi.escape(author)) | 121 cgi.escape(email), cgi.escape(author)) |
122 | 122 |
123 return '<br/>'.join(map(author_html, self.latest_version.pubspec.authors
)) | 123 return '<br/>'.join(map(author_html, self.latest_version.pubspec.authors
)) |
124 | 124 |
125 @property | 125 @property |
126 def uploaders_title(self): | 126 def uploaders_title(self): |
127 """The title for the uploaders list of the package.""" | 127 """The title for the uploaders list of the package.""" |
128 return 'Uploader' if len(self.latest_version.pubspec.authors) == 1 \ | 128 return 'Uploader' if len(self.latest_version.pubspec.authors) == 1 \ |
129 else 'Uploaders' | 129 else 'Uploaders' |
130 | 130 |
131 # TODO(kustermann): When we have string emails, this needs to be changed | |
132 # to read uploaderEmails instead of uploaders. | |
133 @property | 131 @property |
134 def uploaders_html(self): | 132 def uploaders_html(self): |
135 """Inline HTML for the uploaders of this package.""" | 133 """Inline HTML for the uploaders of this package.""" |
136 return '<br/>'.join(cgi.escape(uploader.nickname()) | 134 return '<br/>'.join(cgi.escape(email) |
137 for uploader in self.uploaders) | 135 for email in self.uploaderEmails) |
138 | 136 |
139 @property | 137 @property |
140 def short_updated(self): | 138 def short_updated(self): |
141 """The short updated time of the package.""" | 139 """The short updated time of the package.""" |
142 return self.updated.strftime('%b %d, %Y') | 140 return self.updated.strftime('%b %d, %Y') |
143 | 141 |
144 @classmethod | 142 @classmethod |
145 def new(cls, **kwargs): | 143 def new(cls, **kwargs): |
146 """Construct a new package. | 144 """Construct a new package. |
147 | 145 |
(...skipping 20 matching lines...) Expand all Loading... |
168 """Determine whether a package with the given name exists.""" | 166 """Determine whether a package with the given name exists.""" |
169 return cls.get_by_key_name(name) is not None | 167 return cls.get_by_key_name(name) is not None |
170 | 168 |
171 def has_version(self, version): | 169 def has_version(self, version): |
172 """Determine whether this package has a given version uploaded.""" | 170 """Determine whether this package has a given version uploaded.""" |
173 from package_version import PackageVersion | 171 from package_version import PackageVersion |
174 version = PackageVersion.get_by_name_and_version( | 172 version = PackageVersion.get_by_name_and_version( |
175 self.name, str(version)) | 173 self.name, str(version)) |
176 return version is not None | 174 return version is not None |
177 | 175 |
178 # TODO(kustermann): When we have string emails, this needs to be changed | |
179 # to read uploaderEmails instead of uploaders. | |
180 def has_uploader(self, uploader): | 176 def has_uploader(self, uploader): |
181 """Determine whether the given user is an uploader for this package. | 177 """Determine whether the given user is an uploader for this package. |
182 | 178 |
183 This compares users via case-insensitive email comparison. | 179 This compares users via case-insensitive email comparison. |
184 | 180 |
185 Although admins have uploader privileges for all packages, this will not | 181 Although admins have uploader privileges for all packages, this will not |
186 return True for admins. | 182 return True for admins. |
187 """ | 183 """ |
188 return uploader.email().lower() in \ | 184 return uploader.email().lower() in \ |
189 [u.email().lower() for u in self.uploaders] | 185 [email.lower() for email in self.uploaderEmails] |
190 | 186 |
191 @property | 187 @property |
192 def url(self): | 188 def url(self): |
193 """The API URL for this package.""" | 189 """The API URL for this package.""" |
194 return models.url( | 190 return models.url( |
195 controller='api.packages', action='show', id=self.name) | 191 controller='api.packages', action='show', id=self.name) |
196 | 192 |
197 # TODO(kustermann): When we have string emails, this needs to be changed | |
198 # to read uploaderEmails instead of uploaders. | |
199 def as_dict(self, full=False): | 193 def as_dict(self, full=False): |
200 """Returns the dictionary representation of this package. | 194 """Returns the dictionary representation of this package. |
201 | 195 |
202 This is used to represent the package in API responses. Normally this | 196 This is used to represent the package in API responses. Normally this |
203 just includes URLs and some information about the latest version, but if | 197 just includes URLs and some information about the latest version, but if |
204 full is True, it will include all available information about the | 198 full is True, it will include all available information about the |
205 package. | 199 package. |
206 """ | 200 """ |
207 | 201 |
208 value = { | 202 value = { |
209 'name': self.name, | 203 'name': self.name, |
210 'url': self.url, | 204 'url': self.url, |
211 'uploaders_url': self.url + '/uploaders', | 205 'uploaders_url': self.url + '/uploaders', |
212 'version_url': self.url + '/versions/{version}', | 206 'version_url': self.url + '/versions/{version}', |
213 'new_version_url': self.url + '/versions/new', | 207 'new_version_url': self.url + '/versions/new', |
214 'latest': self.latest_version and self.latest_version.as_dict() | 208 'latest': self.latest_version and self.latest_version.as_dict() |
215 } | 209 } |
216 | 210 |
217 if full: | 211 if full: |
218 value.update({ | 212 value.update({ |
219 'created': self.created.isoformat(), | 213 'created': self.created.isoformat(), |
220 'downloads': self.downloads, | 214 'downloads': self.downloads, |
221 'uploaders': [uploader.email() for uploader in self.uploaders], | 215 'uploaders': [email for email in self.uploaderEmails], |
222 'versions': [version.as_dict() for version in self.version_set] | 216 'versions': [version.as_dict() for version in self.version_set] |
223 }) | 217 }) |
224 | 218 |
225 return value | 219 return value |
226 | 220 |
227 def as_json(self): | 221 def as_json(self): |
228 """Returns the JSON stringified representation of the full information | 222 """Returns the JSON stringified representation of the full information |
229 for this package. | 223 for this package. |
230 """ | 224 """ |
231 cached = memcache.get(self._package_json_cache_key) | 225 cached = memcache.get(self._package_json_cache_key) |
(...skipping 12 matching lines...) Expand all Loading... |
244 description of the package changes. This isn't often since most package | 238 description of the package changes. This isn't often since most package |
245 data is immutable, but when the uploader list changes or new versions | 239 data is immutable, but when the uploader list changes or new versions |
246 of the package are uploaded, the data will change. | 240 of the package are uploaded, the data will change. |
247 """ | 241 """ |
248 memcache.delete(self._package_json_cache_key) | 242 memcache.delete(self._package_json_cache_key) |
249 | 243 |
250 @property | 244 @property |
251 def _package_json_cache_key(self): | 245 def _package_json_cache_key(self): |
252 """The memcache key for the cached JSON for this package.""" | 246 """The memcache key for the cached JSON for this package.""" |
253 return 'package_json_' + self.name | 247 return 'package_json_' + self.name |
OLD | NEW |