There are some objects in Launchpad that are very well known, and required for the correct operation of the system. Code often wants to refer to these specific objects directly. For example:
- The "super" team has all permissions up to and including launchpad.Super. See SuperSpecialPermissions.
- The "vcs-imports" team has the launchpad.Admin permission on SourceSources. - The "buildd" team will have the launchpad.Admin permission on the system-wide build queue and builders.
- The "codeofconduct" team will be responsible for Signed CodeOfConduct management. - The "doapadmin" team will own all products we import without valid ownership information. - The "malonexpert" team consists of all Malone experts, who have broad system privileges in Malone. - The "ubuntu" and "debian" distributions are often used in code. So are the projects associated with these distributions. - The "launchpad", "rosetta", and "malone" Products also are useful to be able to refer to directly.
At present, these objects are refered to by name, hardcoded as string literals, for example in the IAuthorization adapter code in canonical/launchpad/security.py.
In the future we may decide to have a LaunchpadCelebrities table that has a single column linking to the Person table to represent these teams, as well as specific columns that link to ubuntu, debian, launchpad etc.
For now we will improve the code by having a single idiom for getting hold of one of these core objects.
We also need to have some "abstract crowds", such as "all people", "nobody", "anonymous users", that are used by the security code. We can make these crowds celebrities, and have a single idiom for getting hold of them.
Here's an example of using ILaunchpadCelebrities.
from canonical.launchpad.interfaces import ILaunchpadCelebrities celebs = getUtility(ILaunchpadCelebrities) print ITeam(celebs.admin).members print ITeam(celebs.vcs_imports).members # ...and so on.
Here is an example of how using the ILaunchpadCelebrities utility for an IAuthorization adapter changes it from the current state of affairs.
AFTER, including CrowdControl
The interface looks like this.
from zope.interface import Interface, Attribute class ILaunchpadCelebrities(Interface): """The global teams in Launchpad that are responsible for global things.""" super = Attribute("The super team.") buildmaster = Attribute("Build Daemon Admins") codeofconduct = Attribute("CoC Admin team") maloneexpert = Attribute("Malone experts") debian = Attribute("The debian distribution.") ubuntu = Attribute("The ubuntu distribution.") vcs_imports = Attribute("The 'vcs-imports' team.") # Special celebrities for use in authorization code. nobody = Attribute("The empty crowd.") people = Attribute("The Crowd of all People.") anonymous = Attribute("The Crowd that represents anonymous Users of the system.") absolutelyeverybody = Attribute("All people. celebs.people + celebs.anonymous.")
Note that coding style to use the celebrities should always explicitly cast them to what you need. So, like this:
celebs = getUtility(ICelebrities) print ICrowd(celebs.people) print celebs.ubuntu print celebs.ubuntu.project
The production implementation of ILaunchpadCelebrities will be similar to the ILaunchBag implementation in that it will be a utility that implements its attributes as read-only properties. Each property will look up the relevant object by its name from its database class. The implementation is tied to the database, and so will live in canonical/launchpad/database/.
An implementation with more indirection would use the IPersonSet utility to look up the teams.
It is up to the implementor to choose which approach to take, remembering that premature optimization is the root of all evil.
To actually determine team membership, the team should be adapted to an ICrowd as documented in TeamParticipationUsage
All of the celebrity objects must be set up as part of the initial data in the database, for development, production, dogfood and testing.
Ideally the Launchpad application should confirm that it is able to acquire all of the celebrities during startup and refuse to run without them. Otherwise we run the risk of a celebrity not being present right from the start.
The DBA is also responsible for populating the database with more core teams information.
A stubbed-out utility can be used for unit tests, where this is appropriate.
We should consider creating the stub ILaunchpadCelebrities as part of the implementation.
Getting the most out of this system depends on making initZopeless have an option to read in ZCML files, and make utilities available.
Possible confusion about the type of a celebrity
It may be that using getUtility(ILaunchpadCelebrities).something will read ambiguously in code, and lead to errors. If this turns out to happen, we will encourage users of ICelebrities to explicitly cast the celeb to the desired interface. We may need to implement an IDistribution to IProject adapter for this, so that it is clear whether the the debian and ubuntu celebrities are used as projects or distributions. We can enforce this casting by making the actual celebrities into proxy objects that insist on being cast, using a __conform__ method.
We will not do this in the initial implementation, and see how it goes in practice before starting this kind of bondage and discipline.