Merge lp:~stevenk/launchpad/branch-information_type-ui into lp:launchpad
- branch-information_type-ui
- Merge into devel
Proposed by
Steve Kowalik
on 2012-05-30
| Status: | Merged |
|---|---|
| Approved by: | Steve Kowalik on 2012-05-30 |
| Approved revision: | no longer in the source branch. |
| Merged at revision: | 15327 |
| Proposed branch: | lp:~stevenk/launchpad/branch-information_type-ui |
| Merge into: | lp:launchpad |
| Diff against target: |
505 lines (+224/-79) 7 files modified
lib/lp/app/browser/informationtype.py (+61/-0) lib/lp/bugs/browser/bug.py (+2/-42) lib/lp/code/browser/branch.py (+65/-32) lib/lp/code/browser/configure.zcml (+3/-5) lib/lp/code/browser/tests/test_branch.py (+81/-0) lib/lp/code/templates/branch-portlet-privacy.pt (+6/-0) lib/lp/services/features/flags.py (+6/-0) |
| To merge this branch: | bzr merge lp:~stevenk/launchpad/branch-information_type-ui |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| William Grant | code | 2012-05-30 | Approve on 2012-05-30 |
|
Review via email:
|
|||
Commit Message
Show the information_type in the branch UI if a feature flag is set.
Description of the Change
In moving towards the death march of having branch use information_type, show it in the branch UI.
Add a new feature flag, show_informatio
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | === added file 'lib/lp/app/browser/informationtype.py' |
| 2 | --- lib/lp/app/browser/informationtype.py 1970-01-01 00:00:00 +0000 |
| 3 | +++ lib/lp/app/browser/informationtype.py 2012-05-30 05:10:23 +0000 |
| 4 | @@ -0,0 +1,61 @@ |
| 5 | +# Copyright 2012 Canonical Ltd. This software is licensed under the |
| 6 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
| 7 | + |
| 8 | +__metaclass__ = type |
| 9 | +__all__ = [ |
| 10 | + 'InformationTypePortletMixin', |
| 11 | + ] |
| 12 | + |
| 13 | +from lazr.restful.interfaces import IJSONRequestCache |
| 14 | + |
| 15 | +from lp.registry.enums import ( |
| 16 | + InformationType, |
| 17 | + PRIVATE_INFORMATION_TYPES, |
| 18 | + ) |
| 19 | +from lp.registry.vocabularies import InformationTypeVocabulary |
| 20 | +from lp.services.features import getFeatureFlag |
| 21 | + |
| 22 | + |
| 23 | +class InformationTypePortletMixin: |
| 24 | + |
| 25 | + def initialize(self): |
| 26 | + cache = IJSONRequestCache(self.request) |
| 27 | + cache.objects['information_types'] = [ |
| 28 | + {'value': term.value, 'description': term.description, |
| 29 | + 'name': term.title, |
| 30 | + 'description_css_class': 'choice-description'} |
| 31 | + for term in InformationTypeVocabulary()] |
| 32 | + cache.objects['private_types'] = [ |
| 33 | + type.title for type in PRIVATE_INFORMATION_TYPES] |
| 34 | + cache.objects['show_information_type_in_ui'] = ( |
| 35 | + self.show_information_type_in_ui) |
| 36 | + |
| 37 | + @property |
| 38 | + def show_information_type_in_ui(self): |
| 39 | + raise NotImplementedError() |
| 40 | + |
| 41 | + @property |
| 42 | + def show_userdata_as_private(self): |
| 43 | + return bool(getFeatureFlag( |
| 44 | + 'disclosure.display_userdata_as_private.enabled')) |
| 45 | + |
| 46 | + @property |
| 47 | + def information_type(self): |
| 48 | + # This can be replaced with just a return when the feature flag is |
| 49 | + # dropped. |
| 50 | + title = self.context.information_type.title |
| 51 | + if (self.context.information_type == InformationType.USERDATA and |
| 52 | + self.show_userdata_as_private): |
| 53 | + return 'Private' |
| 54 | + return title |
| 55 | + |
| 56 | + @property |
| 57 | + def information_type_description(self): |
| 58 | + # This can be replaced with just a return when the feature flag is |
| 59 | + # dropped. |
| 60 | + description = self.context.information_type.description |
| 61 | + if (self.context.information_type == InformationType.USERDATA and |
| 62 | + self.show_userdata_as_private): |
| 63 | + description = ( |
| 64 | + description.replace('user data', 'private information')) |
| 65 | + return description |
| 66 | |
| 67 | === modified file 'lib/lp/bugs/browser/bug.py' |
| 68 | --- lib/lp/bugs/browser/bug.py 2012-05-17 09:45:29 +0000 |
| 69 | +++ lib/lp/bugs/browser/bug.py 2012-05-30 05:10:23 +0000 |
| 70 | @@ -55,6 +55,7 @@ |
| 71 | from zope.security.interfaces import Unauthorized |
| 72 | |
| 73 | from lp import _ |
| 74 | +from lp.app.browser.informationtype import InformationTypePortletMixin |
| 75 | from lp.app.browser.launchpadform import ( |
| 76 | action, |
| 77 | custom_widget, |
| 78 | @@ -518,7 +519,7 @@ |
| 79 | return getUtility(ILaunchBag).bugtask |
| 80 | |
| 81 | |
| 82 | -class BugView(LaunchpadView, BugViewMixin): |
| 83 | +class BugView(InformationTypePortletMixin, LaunchpadView, BugViewMixin): |
| 84 | """View class for presenting information about an `IBug`. |
| 85 | |
| 86 | Since all bug pages are registered on IBugTask, the context will be |
| 87 | @@ -535,19 +536,6 @@ |
| 88 | return bool(getFeatureFlag( |
| 89 | 'disclosure.show_information_type_in_ui.enabled')) |
| 90 | |
| 91 | - def initialize(self): |
| 92 | - super(BugView, self).initialize() |
| 93 | - cache = IJSONRequestCache(self.request) |
| 94 | - cache.objects['information_types'] = [ |
| 95 | - {'value': term.value, 'description': term.description, |
| 96 | - 'name': term.title, |
| 97 | - 'description_css_class': 'choice-description'} |
| 98 | - for term in InformationTypeVocabulary()] |
| 99 | - cache.objects['private_types'] = [ |
| 100 | - type.title for type in PRIVATE_INFORMATION_TYPES] |
| 101 | - cache.objects['show_information_type_in_ui'] = ( |
| 102 | - self.show_information_type_in_ui) |
| 103 | - |
| 104 | @cachedproperty |
| 105 | def page_description(self): |
| 106 | return IBug(self.context).description |
| 107 | @@ -596,34 +584,6 @@ |
| 108 | return ProxiedLibraryFileAlias( |
| 109 | attachment.libraryfile, attachment).http_url |
| 110 | |
| 111 | - @property |
| 112 | - def information_type(self): |
| 113 | - # This can be replaced with just a return when the feature flag is |
| 114 | - # dropped. |
| 115 | - title = self.context.information_type.title |
| 116 | - show_userdata_as_private = bool(getFeatureFlag( |
| 117 | - 'disclosure.display_userdata_as_private.enabled')) |
| 118 | - if ( |
| 119 | - self.context.information_type == InformationType.USERDATA and |
| 120 | - show_userdata_as_private): |
| 121 | - return 'Private' |
| 122 | - return title |
| 123 | - |
| 124 | - @property |
| 125 | - def information_type_description(self): |
| 126 | - # This can be replaced with just a return when the feature flag is |
| 127 | - # dropped. |
| 128 | - description = self.context.information_type.description |
| 129 | - show_userdata_as_private = bool(getFeatureFlag( |
| 130 | - 'disclosure.display_userdata_as_private.enabled')) |
| 131 | - if ( |
| 132 | - self.context.information_type == InformationType.USERDATA and |
| 133 | - show_userdata_as_private): |
| 134 | - description = ( |
| 135 | - description.replace('user data', 'private information')) |
| 136 | - |
| 137 | - return description |
| 138 | - |
| 139 | |
| 140 | class BugActivity(BugView): |
| 141 | |
| 142 | |
| 143 | === modified file 'lib/lp/code/browser/branch.py' |
| 144 | --- lib/lp/code/browser/branch.py 2012-03-27 04:36:24 +0000 |
| 145 | +++ lib/lp/code/browser/branch.py 2012-05-30 05:10:23 +0000 |
| 146 | @@ -75,6 +75,7 @@ |
| 147 | from zope.traversing.interfaces import IPathAdapter |
| 148 | |
| 149 | from lp import _ |
| 150 | +from lp.app.browser.informationtype import InformationTypePortletMixin |
| 151 | from lp.app.browser.launchpad import Hierarchy |
| 152 | from lp.app.browser.launchpadform import ( |
| 153 | action, |
| 154 | @@ -123,10 +124,14 @@ |
| 155 | from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference |
| 156 | from lp.registry.interfaces.person import IPersonSet |
| 157 | from lp.registry.interfaces.productseries import IProductSeries |
| 158 | -from lp.registry.vocabularies import UserTeamsParticipationPlusSelfVocabulary |
| 159 | +from lp.registry.vocabularies import ( |
| 160 | + InformationTypeVocabulary, |
| 161 | + UserTeamsParticipationPlusSelfVocabulary, |
| 162 | + ) |
| 163 | from lp.services import searchbuilder |
| 164 | from lp.services.config import config |
| 165 | from lp.services.database.constants import UTC_NOW |
| 166 | +from lp.services.features import getFeatureFlag |
| 167 | from lp.services.feeds.browser import ( |
| 168 | BranchFeedLink, |
| 169 | FeedsMixin, |
| 170 | @@ -425,7 +430,8 @@ |
| 171 | return branch.url |
| 172 | |
| 173 | |
| 174 | -class BranchView(LaunchpadView, FeedsMixin, BranchMirrorMixin): |
| 175 | +class BranchView(LaunchpadView, FeedsMixin, BranchMirrorMixin, |
| 176 | + InformationTypePortletMixin): |
| 177 | |
| 178 | feed_types = ( |
| 179 | BranchFeedLink, |
| 180 | @@ -437,7 +443,13 @@ |
| 181 | |
| 182 | label = page_title |
| 183 | |
| 184 | + @property |
| 185 | + def show_information_type_in_ui(self): |
| 186 | + return bool(getFeatureFlag( |
| 187 | + 'disclosure.show_information_type_in_branch_ui.enabled')) |
| 188 | + |
| 189 | def initialize(self): |
| 190 | + super(BranchView, self).initialize() |
| 191 | self.branch = self.context |
| 192 | self.notices = [] |
| 193 | # Cache permission so private team owner can be rendered. |
| 194 | @@ -706,33 +718,38 @@ |
| 195 | self.setFieldError(field_name, structured(message)) |
| 196 | |
| 197 | |
| 198 | -class BranchEditSchema(Interface): |
| 199 | - """Defines the fields for the edit form. |
| 200 | - |
| 201 | - This is necessary so as to make an editable field for the branch privacy. |
| 202 | - Normally the field is not editable through the interface in order to stop |
| 203 | - direct setting of the private attribute, but in this case we actually want |
| 204 | - the user to be able to edit it. |
| 205 | - """ |
| 206 | - use_template(IBranch, include=[ |
| 207 | - 'name', |
| 208 | - 'url', |
| 209 | - 'description', |
| 210 | - 'lifecycle_status', |
| 211 | - 'whiteboard', |
| 212 | - ]) |
| 213 | - explicitly_private = copy_field( |
| 214 | - IBranch['explicitly_private'], readonly=False) |
| 215 | - reviewer = copy_field(IBranch['reviewer'], required=True) |
| 216 | - owner = copy_field(IBranch['owner'], readonly=False) |
| 217 | - |
| 218 | - |
| 219 | class BranchEditFormView(LaunchpadEditFormView): |
| 220 | """Base class for forms that edit a branch.""" |
| 221 | |
| 222 | - schema = BranchEditSchema |
| 223 | field_names = None |
| 224 | |
| 225 | + @cachedproperty |
| 226 | + def schema(self): |
| 227 | + class BranchEditSchema(Interface): |
| 228 | + """Defines the fields for the edit form. |
| 229 | + |
| 230 | + This is necessary so as to make an editable field for the |
| 231 | + branch privacy. Normally the field is not editable through |
| 232 | + the interface in order to stop direct setting of the private |
| 233 | + attribute, but in this case we actually want the user to be |
| 234 | + able to edit it. |
| 235 | + """ |
| 236 | + use_template(IBranch, include=[ |
| 237 | + 'name', |
| 238 | + 'url', |
| 239 | + 'description', |
| 240 | + 'lifecycle_status', |
| 241 | + 'whiteboard', |
| 242 | + ]) |
| 243 | + information_type = copy_field( |
| 244 | + IBranch['information_type'], readonly=False, |
| 245 | + vocabulary=InformationTypeVocabulary()) |
| 246 | + explicitly_private = copy_field( |
| 247 | + IBranch['explicitly_private'], readonly=False) |
| 248 | + reviewer = copy_field(IBranch['reviewer'], required=True) |
| 249 | + owner = copy_field(IBranch['owner'], readonly=False) |
| 250 | + return BranchEditSchema |
| 251 | + |
| 252 | @property |
| 253 | def page_title(self): |
| 254 | return 'Edit %s' % self.context.displayname |
| 255 | @@ -744,7 +761,7 @@ |
| 256 | @property |
| 257 | def adapters(self): |
| 258 | """See `LaunchpadFormView`""" |
| 259 | - return {BranchEditSchema: self.context} |
| 260 | + return {self.schema: self.context} |
| 261 | |
| 262 | @action('Change Branch', name='change') |
| 263 | def change_action(self, action, data): |
| 264 | @@ -767,6 +784,10 @@ |
| 265 | if 'private' in data: |
| 266 | # Read only for display. |
| 267 | data.pop('private') |
| 268 | + if 'information_type' in data: |
| 269 | + information_type = data.pop('information_type') |
| 270 | + self.context.transitionToInformationType( |
| 271 | + information_type, self.user) |
| 272 | if 'explicitly_private' in data: |
| 273 | private = data.pop('explicitly_private') |
| 274 | if (private != self.context.private |
| 275 | @@ -1014,16 +1035,27 @@ |
| 276 | |
| 277 | |
| 278 | class BranchEditView(BranchEditFormView, BranchNameValidationMixin): |
| 279 | - """The main branch view for editing the branch attributes.""" |
| 280 | - |
| 281 | - field_names = [ |
| 282 | - 'owner', 'name', 'explicitly_private', 'url', 'description', |
| 283 | - 'lifecycle_status'] |
| 284 | + """The main branch for editing the branch attributes.""" |
| 285 | + |
| 286 | + @property |
| 287 | + def show_information_type_in_ui(self): |
| 288 | + return bool(getFeatureFlag( |
| 289 | + 'disclosure.show_information_type_in_branch_ui.enabled')) |
| 290 | + |
| 291 | + @property |
| 292 | + def field_names(self): |
| 293 | + fields = [ |
| 294 | + 'owner', 'name', 'explicitly_private', 'url', 'description', |
| 295 | + 'lifecycle_status'] |
| 296 | + if self.show_information_type_in_ui: |
| 297 | + fields[2] = 'information_type' |
| 298 | + return fields |
| 299 | |
| 300 | custom_widget('lifecycle_status', LaunchpadRadioWidgetWithDescription) |
| 301 | + custom_widget('information_type', LaunchpadRadioWidgetWithDescription) |
| 302 | |
| 303 | def setUpFields(self): |
| 304 | - LaunchpadFormView.setUpFields(self) |
| 305 | + super(BranchEditView, self).setUpFields() |
| 306 | # This is to prevent users from converting push/import |
| 307 | # branches to pull branches. |
| 308 | branch = self.context |
| 309 | @@ -1061,7 +1093,8 @@ |
| 310 | user_has_special_branch_access(self.user)) |
| 311 | |
| 312 | if not show_private_field: |
| 313 | - self.form_fields = self.form_fields.omit('explicitly_private') |
| 314 | + self.form_fields = self.form_fields.omit( |
| 315 | + 'explicitly_private', 'information_type') |
| 316 | |
| 317 | # If the user can administer branches, then they should be able to |
| 318 | # assign the ownership of the branch to any valid person or team. |
| 319 | |
| 320 | === modified file 'lib/lp/code/browser/configure.zcml' |
| 321 | --- lib/lp/code/browser/configure.zcml 2012-03-07 00:58:37 +0000 |
| 322 | +++ lib/lp/code/browser/configure.zcml 2012-05-30 05:10:23 +0000 |
| 323 | @@ -390,9 +390,11 @@ |
| 324 | name="+index" |
| 325 | template="../templates/branch-index.pt"/> |
| 326 | <browser:page |
| 327 | + name="+portlet-privacy" |
| 328 | + template="../templates/branch-portlet-privacy.pt"/> |
| 329 | + <browser:page |
| 330 | name="++bug-links" |
| 331 | template="../templates/branch-bug-links.pt"/> |
| 332 | - |
| 333 | <browser:page |
| 334 | name="++branch-information" |
| 335 | template="../templates/branch-information.pt" /> |
| 336 | @@ -417,16 +419,12 @@ |
| 337 | <browser:page |
| 338 | name="++branch-related-bugs-specs" |
| 339 | template="../templates/branch-related-bugs-specs.pt" /> |
| 340 | - |
| 341 | </browser:pages> |
| 342 | <browser:pages |
| 343 | for="lp.code.interfaces.branch.IBranch" |
| 344 | layer="lp.code.publisher.CodeLayer" |
| 345 | permission="zope.Public"> |
| 346 | <browser:page |
| 347 | - name="+portlet-privacy" |
| 348 | - template="../templates/branch-portlet-privacy.pt"/> |
| 349 | - <browser:page |
| 350 | name="+heading" |
| 351 | template="../templates/branch-heading.pt"/> |
| 352 | </browser:pages> |
| 353 | |
| 354 | === modified file 'lib/lp/code/browser/tests/test_branch.py' |
| 355 | --- lib/lp/code/browser/tests/test_branch.py 2012-05-24 02:16:59 +0000 |
| 356 | +++ lib/lp/code/browser/tests/test_branch.py 2012-05-30 05:10:23 +0000 |
| 357 | @@ -10,10 +10,12 @@ |
| 358 | |
| 359 | from BeautifulSoup import BeautifulSoup |
| 360 | import pytz |
| 361 | +from zope.component import getUtility |
| 362 | from zope.publisher.interfaces import NotFound |
| 363 | from zope.security.proxy import removeSecurityProxy |
| 364 | |
| 365 | from lp.app.interfaces.headings import IRootContext |
| 366 | +from lp.app.interfaces.launchpad import ILaunchpadCelebrities |
| 367 | from lp.bugs.interfaces.bugtask import ( |
| 368 | BugTaskStatus, |
| 369 | UNRESOLVED_BUGTASK_STATUSES, |
| 370 | @@ -37,6 +39,7 @@ |
| 371 | from lp.registry.interfaces.person import PersonVisibility |
| 372 | from lp.services.config import config |
| 373 | from lp.services.database.constants import UTC_NOW |
| 374 | +from lp.services.features.testing import FeatureFixture |
| 375 | from lp.services.helpers import truncate_text |
| 376 | from lp.services.webapp.publisher import canonical_url |
| 377 | from lp.services.webapp.servers import LaunchpadTestRequest |
| 378 | @@ -897,6 +900,39 @@ |
| 379 | with person_logged_in(person): |
| 380 | self.assertEquals(team, branch.owner) |
| 381 | |
| 382 | + def test_information_type_in_ui(self): |
| 383 | + # The information_type of a branch can be changed via the UI when |
| 384 | + # the feature flag is enabled. |
| 385 | + person = self.factory.makePerson() |
| 386 | + branch = self.factory.makeProductBranch(owner=person) |
| 387 | + feature_flag = { |
| 388 | + 'disclosure.show_information_type_in_branch_ui.enabled': 'on'} |
| 389 | + admins = getUtility(ILaunchpadCelebrities).admin |
| 390 | + admin = admins.teamowner |
| 391 | + with FeatureFixture(feature_flag): |
| 392 | + browser = self.getUserBrowser( |
| 393 | + canonical_url(branch) + '/+edit', user=admin) |
| 394 | + browser.getControl("Embargoed Security").click() |
| 395 | + browser.getControl("Change Branch").click() |
| 396 | + with person_logged_in(person): |
| 397 | + self.assertEqual( |
| 398 | + InformationType.EMBARGOEDSECURITY, branch.information_type) |
| 399 | + |
| 400 | + def test_information_type_in_ui_vocabulary(self): |
| 401 | + # The vocabulary that Branch:+edit uses for the information_type |
| 402 | + # has been correctly created. |
| 403 | + person = self.factory.makePerson() |
| 404 | + branch = self.factory.makeProductBranch(owner=person) |
| 405 | + feature_flags = { |
| 406 | + 'disclosure.show_information_type_in_branch_ui.enabled': 'on', |
| 407 | + 'disclosure.proprietary_information_type.disabled': 'on'} |
| 408 | + admins = getUtility(ILaunchpadCelebrities).admin |
| 409 | + admin = admins.teamowner |
| 410 | + with FeatureFixture(feature_flags): |
| 411 | + browser = self.getUserBrowser( |
| 412 | + canonical_url(branch) + '/+edit', user=admin) |
| 413 | + self.assertRaises(LookupError, browser.getControl, "Proprietary") |
| 414 | + |
| 415 | |
| 416 | class TestBranchUpgradeView(TestCaseWithFactory): |
| 417 | |
| 418 | @@ -916,3 +952,48 @@ |
| 419 | self.assertEqual( |
| 420 | 'An upgrade is already in progress for branch %s.' % |
| 421 | branch.bzr_identity, view.request.notifications[0].message) |
| 422 | + |
| 423 | + |
| 424 | +class TestBranchPrivacyPortlet(TestCaseWithFactory): |
| 425 | + |
| 426 | + layer = LaunchpadFunctionalLayer |
| 427 | + |
| 428 | + def test_information_type_in_ui(self): |
| 429 | + # With the show_information_type_in_branch_ui feature flag on, the |
| 430 | + # privacy portlet shows the information_type. |
| 431 | + owner = self.factory.makePerson() |
| 432 | + branch = self.factory.makeBranch(private=True, owner=owner) |
| 433 | + feature_flag = { |
| 434 | + 'disclosure.show_information_type_in_branch_ui.enabled': 'on'} |
| 435 | + with FeatureFixture(feature_flag): |
| 436 | + with person_logged_in(owner): |
| 437 | + view = create_initialized_view(branch, '+portlet-privacy') |
| 438 | + soup = BeautifulSoup(view.render()) |
| 439 | + information_type = soup.find('strong') |
| 440 | + description = soup.find('div', id='information-type-description') |
| 441 | + self.assertEqual('User Data', information_type.renderContents()) |
| 442 | + self.assertEqual( |
| 443 | + 'Visible only to users with whom the project has shared ' |
| 444 | + 'information\ncontaining user data.\n', |
| 445 | + description.renderContents()) |
| 446 | + |
| 447 | + def test_information_type_in_ui_with_display_as_private(self): |
| 448 | + # With both show_information_type_in_branch_ui and |
| 449 | + # display_userdata_as_private, the information_type is shown with |
| 450 | + # User Data masked as Private. |
| 451 | + owner = self.factory.makePerson() |
| 452 | + branch = self.factory.makeBranch(private=True, owner=owner) |
| 453 | + feature_flags = { |
| 454 | + 'disclosure.show_information_type_in_branch_ui.enabled': 'on', |
| 455 | + 'disclosure.display_userdata_as_private.enabled': 'on'} |
| 456 | + with FeatureFixture(feature_flags): |
| 457 | + with person_logged_in(owner): |
| 458 | + view = create_initialized_view(branch, '+portlet-privacy') |
| 459 | + soup = BeautifulSoup(view.render()) |
| 460 | + information_type = soup.find('strong') |
| 461 | + description = soup.find('div', id='information-type-description') |
| 462 | + self.assertEqual('Private', information_type.renderContents()) |
| 463 | + self.assertEqual( |
| 464 | + 'Visible only to users with whom the project has shared ' |
| 465 | + 'information\ncontaining private information.\n', |
| 466 | + description.renderContents()) |
| 467 | |
| 468 | === modified file 'lib/lp/code/templates/branch-portlet-privacy.pt' |
| 469 | --- lib/lp/code/templates/branch-portlet-privacy.pt 2011-08-24 08:57:25 +0000 |
| 470 | +++ lib/lp/code/templates/branch-portlet-privacy.pt 2012-05-30 05:10:23 +0000 |
| 471 | @@ -7,6 +7,11 @@ |
| 472 | class python: path('context/private') and 'portlet private' or 'portlet public' |
| 473 | " |
| 474 | > |
| 475 | + <tal:information_type tal:condition="view/show_information_type_in_ui"> |
| 476 | + This branch contains <strong id="information-type" tal:content="view/information_type"></strong> information |
| 477 | + <div id='information-type-description' style='padding-top: 5px' tal:content="view/information_type_description"></div> |
| 478 | + </tal:information_type> |
| 479 | + <tal:privacy tal:condition="not:view/show_information_type_in_ui"> |
| 480 | <div tal:condition="not:context/private" |
| 481 | >This branch is public</div> |
| 482 | <div tal:condition="context/private"> |
| 483 | @@ -15,4 +20,5 @@ |
| 484 | because it is stacked on a private branch. |
| 485 | </tal:msg> |
| 486 | </div> |
| 487 | + </tal:privacy> |
| 488 | </div> |
| 489 | |
| 490 | === modified file 'lib/lp/services/features/flags.py' |
| 491 | --- lib/lp/services/features/flags.py 2012-05-18 05:31:54 +0000 |
| 492 | +++ lib/lp/services/features/flags.py 2012-05-30 05:10:23 +0000 |
| 493 | @@ -320,6 +320,12 @@ |
| 494 | '', |
| 495 | '', |
| 496 | ''), |
| 497 | + ('disclosure.show_information_type_in_branch_ui.enabled', |
| 498 | + 'boolean', |
| 499 | + 'If true, displays the information_type directly on branch pages.', |
| 500 | + '', |
| 501 | + '', |
| 502 | + ''), |
| 503 | ]) |
| 504 | |
| 505 | # The set of all flag names that are documented. |

39 + @property n_type_ in_ui(self) : show_informatio n_type_ in_ui.enabled' (self.context) : providedBy( self.context) : flag_base. replace( 'ui', 'branch_ui') Flag(feature_ flag_base) )
40 + def show_informatio
41 + feature_flag_base = 'disclosure.
42 + if IBug.providedBy
43 + pass
44 + elif IBranch.
45 + feature_flag_base = feature_
46 + else:
47 + raise NotImplemented()
48 + return bool(getFeature
Since InformationType Portlet isn't used as its own view (always as a mixin for an edit form class), this horror can probably die or be replaced with "raise NotImplementedE rror()" . It should also possibly be renamed to InformationType PortletMixin, and the module name should be informationtype, not information_type.
60 + if ( information_ type == InformationType .USERDATA and userdata_ as_private) :
61 + self.context.
62 + self.show_
Why is that extra newline there?
if (self.context. information_ type == InformationType .USERDATA userdata_ as_private) :
and self.show_
71 + if ( information_ type == InformationType .USERDATA and userdata_ as_private) :
72 + self.context.
73 + self.show_
Likewise.
107 def initialize(self):
108 super(BugView, self).initialize()
These can be deleted, as the method looks empty apart from that super() call.
433 +class TestBranchPriva cyPortlet( TestCaseWithFac tory):
That's a bit odd. Is there really nowhere else that tests the portlet?
485 + This branch contains <strong id="information -type" tal:content= "view/informati on_type" ></strong> information -type-descripti on' style='padding-top: 5px' tal:content= "view/informati on_type_ description" ></div>
486 + <div id='information
The nbsp before a new div doesn't strike me as particularly useful. Do you know why it's there?