| 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 |