← Back to team overview

launchpad-reviewers team mailing list archive

Re: [Merge] lp:~wgrant/launchpad/product-aps-set into lp:launchpad

 

Review: Approve



Diff comments:

> === modified file 'lib/lp/registry/model/product.py'
> --- lib/lp/registry/model/product.py	2015-06-24 21:14:20 +0000
> +++ lib/lp/registry/model/product.py	2015-06-26 06:42:59 +0000
> @@ -38,7 +38,9 @@
>  from storm.locals import (
>      And,
>      Desc,
> +    Int,
>      Join,
> +    List,
>      Not,
>      Or,
>      Select,
> @@ -439,6 +441,11 @@
>          name='remote_product', allow_none=True, default=None)
>      vcs = EnumCol(enum=VCSType, notNull=False)
>  
> +    # Cache of AccessPolicy.ids that convey launchpad.LimitedView.
> +    # Unlike artifacts' cached access_policies, an AccessArtifactGrant
> +    # to an artifact in the policy is sufficient for access.
> +    access_policies = List(type=Int())
> +
>      @property
>      def date_next_suggest_packaging(self):
>          """See `IProduct`
> @@ -582,6 +589,7 @@
>                  self.setSpecificationSharingPolicy(
>                      specification_policy_default[value])
>              self._ensurePolicies([value])
> +            self._cacheAccessPolicies()

In the creation case, you call _cacheAccessPolicies after calling _ensurePolicies.  In the revocation case, you call _cacheAccessPolicies from _pruneUnusedPolicies.  It would be more consistent and harder to get wrong in future if you moved this call as well as that in _prepare_to_set_sharing_policy to the end of _ensurePolicies.

>  
>      information_type = property(_get_information_type, _set_information_type)
>  
> @@ -753,6 +761,7 @@
>                  raise ProprietaryProduct(
>                      "The project is %s." % self.information_type.title)
>          self._ensurePolicies(allowed_types[var])
> +        self._cacheAccessPolicies()
>  
>      def setBranchSharingPolicy(self, branch_sharing_policy):
>          """See `IProductEditRestricted`."""
> @@ -815,6 +824,23 @@
>              grants.append((p, self.owner, self.owner))
>          getUtility(IAccessPolicyGrantSource).grant(grants)
>  
> +    def _cacheAccessPolicies(self):
> +        # Update the cache of AccessPolicy.ids for which an
> +        # AccessPolicyGrant or AccessArtifactGrant is sufficient to
> +        # convey launchpad.LimitedView on this Product.
> +        #
> +        # We only need a cache for proprietary types, and it only
> +        # includes proprietary policies in case a policy like Private
> +        # Security was somehow left around when a project was
> +        # transitioned to Proprietary.
> +        if self.information_type in PROPRIETARY_INFORMATION_TYPES:
> +            self.access_policies = [
> +                policy.id for policy in
> +                getUtility(IAccessPolicySource).findByPillar([self])
> +                if policy.type in PROPRIETARY_INFORMATION_TYPES]

Perhaps this could use AccessPolicySource.find instead of filtering by type afterwards.

> +        else:
> +            self.access_policies = None
> +
>      def _pruneUnusedPolicies(self):
>          allowed_bug_types = set(
>              BUG_POLICY_ALLOWED_TYPES.get(
> @@ -840,6 +866,7 @@
>              and apa_source.findByPolicy([ap]).is_empty()]
>          getUtility(IAccessPolicyGrantSource).revokeByPolicy(unused_aps)
>          ap_source.delete([(ap.pillar, ap.type) for ap in unused_aps])
> +        self._cacheAccessPolicies()
>  
>      @cachedproperty
>      def commercial_subscription(self):
> 
> === modified file 'lib/lp/registry/tests/test_product.py'
> --- lib/lp/registry/tests/test_product.py	2015-06-25 07:39:40 +0000
> +++ lib/lp/registry/tests/test_product.py	2015-06-26 06:42:59 +0000
> @@ -527,6 +527,40 @@
>              SpecificationSharingPolicy.PROPRIETARY,
>              product.specification_sharing_policy)
>  
> +    def test_cacheAccessPolicies(self):
> +        # Product.access_policies is a list caching AccessPolicy.ids for
> +        # which an AccessPolicyGrant or AccessArtifactGrant gives a
> +        # principal LimitedView on the Product.
> +        aps = getUtility(IAccessPolicySource)
> +
> +        # Public projects don't need a cache.
> +        product = self.factory.makeProduct()
> +        naked_product = removeSecurityProxy(product)
> +        self.assertContentEqual(
> +            [InformationType.USERDATA, InformationType.PRIVATESECURITY],
> +            [p.type for p in aps.findByPillar([product])])
> +        self.assertIs(None, naked_product.access_policies)
> +
> +        # A private project normally just allows the Proprietary policy,
> +        # even if there is still another policy like Private Security.
> +        naked_product.information_type = InformationType.PROPRIETARY
> +        [prop_policy] = aps.find([(product, InformationType.PROPRIETARY)])
> +        self.assertEqual([prop_policy.id], naked_product.access_policies)
> +
> +        # If we switch it back to public, the cache is no longer
> +        # required.
> +        naked_product.information_type = InformationType.PUBLIC
> +        self.assertIs(None, naked_product.access_policies)
> +
> +        # Projects can also be Embargoed because of reasons. Since they
> +        # can have both Proprietary and Embargoed artifacts, and someone
> +        # who can see either needs LimitedView on the pillar they're on,
> +        # both policies are permissible.
> +        naked_product.information_type = InformationType.EMBARGOED
> +        [emb_policy] = aps.find([(product, InformationType.EMBARGOED)])
> +        self.assertContentEqual(
> +            [prop_policy.id, emb_policy.id], naked_product.access_policies)
> +
>      def test_checkInformationType_bug_supervisor(self):
>          # Bug supervisors of proprietary products must not have inclusive
>          # membership policies.
> 


-- 
https://code.launchpad.net/~wgrant/launchpad/product-aps-set/+merge/263062
Your team Launchpad code reviewers is subscribed to branch lp:launchpad.


References