Example #1
0
class ISpecificationBranch(Interface):
    """A branch linked to a specification."""

    export_as_webservice_entry(as_of="beta")

    id = Int(title=_("Specification Branch #"))
    specification = exported(ReferenceChoice(title=_("Blueprint"),
                                             vocabulary="Specification",
                                             required=True,
                                             readonly=True,
                                             schema=ISpecification),
                             as_of="beta")
    branch = exported(ReferenceChoice(title=_("Branch"),
                                      vocabulary="Branch",
                                      required=True,
                                      schema=IBranch),
                      as_of="beta")

    datecreated = Attribute("The date on which I was created.")
    registrant = exported(Reference(
        schema=IPerson,
        readonly=True,
        required=True,
        title=_("The person who linked the bug to the branch")),
                          as_of="beta")

    @export_operation_as('delete')
    @export_write_operation()
    @operation_for_version('beta')
    def destroySelf():
        """Destroy this specification branch link"""
class IBranchMergeProposalPublic(IPrivacy):

    id = Int(title=_('DB ID'),
             required=True,
             readonly=True,
             description=_("The tracking number for this merge proposal."))
    source_branchID = Int(title=_('Source branch ID'),
                          required=True,
                          readonly=True)
    prerequisite_branchID = Int(title=_('Prerequisite branch ID'),
                                required=True,
                                readonly=True)

    # This is redefined from IPrivacy.private because the attribute is
    # read-only. The value is determined by the involved branches.
    private = exported(
        Bool(title=_("Proposal is confidential"),
             required=False,
             readonly=True,
             default=False,
             description=_(
                 "If True, this proposal is visible only to subscribers.")))

    source_branch = exported(
        ReferenceChoice(title=_('Source Branch'),
                        schema=IBranch,
                        vocabulary='Branch',
                        required=True,
                        readonly=True,
                        description=_("The branch that has code to land.")))

    target_branch = exported(
        ReferenceChoice(
            title=_('Target Branch'),
            schema=IBranch,
            vocabulary='Branch',
            required=True,
            readonly=True,
            description=_(
                "The branch that the source branch will be merged into.")))

    prerequisite_branch = exported(
        ReferenceChoice(
            title=_('Prerequisite Branch'),
            schema=IBranch,
            vocabulary='Branch',
            required=False,
            readonly=True,
            description=_(
                "The branch that the source branch branched from. "
                "If this branch is the same as the target branch, then "
                "leave this field blank.")))
Example #3
0
class ISearchableByQuestionOwner(IQuestionCollection):
    """Collection that support searching by question owner."""
    @operation_parameters(
        search_text=TextLine(title=_('Search text'), required=False),
        status=List(title=_('Status'),
                    required=False,
                    value_type=Choice(vocabulary=QuestionStatus)),
        language=List(title=_('Language'),
                      required=False,
                      value_type=ReferenceChoice(vocabulary='Language')),
        owner=PublicPersonChoice(title=_('Owner'),
                                 required=False,
                                 vocabulary='ValidPerson'),
        needs_attention_from=PublicPersonChoice(
            title=_('Needs attentions from'),
            required=False,
            vocabulary='ValidPerson'),
        sort=Choice(title=_('Sort'), required=False, vocabulary=QuestionSort))
    @operation_returns_collection_of(Interface)  # IQuestion.
    @export_read_operation()
    @operation_for_version('devel')
    def searchQuestions(
            search_text=None,
            # Lp wants a sequence, but lazr.restful only supports
            # lists; cast the tuple as a list.
            status=list(QUESTION_STATUS_DEFAULT_SEARCH),
            language=None,
            sort=None,
            owner=None,
            needs_attention_from=None):
        """Return the questions from the collection matching search criteria.
Example #4
0
class IBugBranch(IHasDateCreated, IHasBug, IHasBranchTarget):
    """A branch linked to a bug."""

    export_as_webservice_entry()

    id = Int(title=_("Bug Branch #"))
    bug = exported(
        BugField(
            title=_("Bug #"),
            required=True, readonly=True))
    branch_id = Int(title=_("Branch ID"), required=True, readonly=True)
    branch = exported(
        ReferenceChoice(
            title=_("Branch"), schema=IBranch,
            vocabulary="Branch", required=True))
    revision_hint = TextLine(title=_("Revision Hint"))

    bug_task = Object(
        schema=IBugTask, title=_("The bug task that the branch fixes"),
        description=_(
            "the bug task reported against this branch's product or the "
            "first bug task (in case where there is no task reported "
            "against the branch's product)."),
        readonly=True)

    registrant = Object(
        schema=IPerson, readonly=True, required=True,
        title=_("The person who linked the bug to the branch"))
class IBinaryPackageReleaseDownloadCount(Interface):
    """Daily download count of a binary package release in an archive."""
    export_as_webservice_entry()

    id = Int(title=_('ID'), required=True, readonly=True)
    archive = exported(Reference(
        title=_('Archive'), schema=IArchive, required=True,
        readonly=True))
    binary_package_release = Reference(
        title=_('The binary package release'), schema=IBinaryPackageRelease,
        required=True, readonly=True)
    binary_package_name = exported(
        TextLine(
            title=_("Binary package name"),
            required=False, readonly=True))
    binary_package_version = exported(
        TextLine(
            title=_("Binary package version"),
            required=False, readonly=True))
    day = exported(
        Date(title=_('Day of the downloads'), required=True, readonly=True))
    count = exported(
        Int(title=_('Number of downloads'), required=True, readonly=True))
    country = exported(
        ReferenceChoice(
            title=_('Country'), required=False, readonly=True,
            vocabulary='CountryName', schema=ICountry))

    country_code = TextLine(
        title=_("Country code"), required=True, readonly=True,
        description=_(
            'The ISO 3166-2 country code for this count, or "unknown".'))
Example #6
0
class IProductReleaseFilePublic(Interface):
    """Public properties for `IProductReleaseFile`."""

    id = Int(title=_('ID'), required=True, readonly=True)
    productrelease = exported(
        ReferenceChoice(title=_('Project release'),
                        description=_("The parent product release."),
                        schema=Interface,  # Defined later.
                        required=True,
                        vocabulary='ProductRelease'),
        exported_as='project_release')
    libraryfile = exported(
        Bytes(title=_("File"),
              description=_("The file contents."),
              readonly=True,
              required=True),
        exported_as='file')
    signature = exported(
        Bytes(title=_("File signature"),
              description=_("The file signature."),
              readonly=True,
              required=False))
    filetype = exported(
        Choice(title=_("Upstream file type"), required=True,
               vocabulary=UpstreamFileType,
               default=UpstreamFileType.CODETARBALL),
        exported_as='file_type')
    description = exported(
        Text(title=_("Description"), required=False,
             description=_('A detailed description of the file contents')))
    date_uploaded = exported(
        Datetime(title=_('Upload date'),
                 description=_('The date this file was uploaded'),
                 required=True, readonly=True))
class IQuestionsPerson(IQuestionCollection):

    @operation_returns_collection_of(Interface)  # IQuestionTarget.
    @export_read_operation()
    @operation_for_version('devel')
    def getDirectAnswerQuestionTargets():
        """Return a list of IQuestionTargets that a person is subscribed to.

        This will return IQuestionTargets that the person is registered as an
        answer contact because he subscribed himself.
        """

    @operation_returns_collection_of(Interface)  # IQuestionTarget
    @export_read_operation()
    @operation_for_version('devel')
    def getTeamAnswerQuestionTargets():
        """Return a list of IQuestionTargets that are indirect subscriptions.

        This will return IQuestionTargets that the person or team is
        registered as an answer contact because of his membership in a team.
        """

    @operation_parameters(
        search_text=TextLine(
            title=_('Search text'), required=False),
        status=List(
            title=_('Status'), required=False,
            value_type=Choice(vocabulary=QuestionStatus)),
        language=List(
            title=_('Language'), required=False,
            value_type=ReferenceChoice(vocabulary='Language')),
        participation=Choice(
            title=_('Participation'), required=False,
            vocabulary=QuestionParticipation),
        needs_attention=Bool(
            title=_('Needs attentions from'), default=False, required=False),
        sort=Choice(
            title=_('Sort'), required=False,
            vocabulary=QuestionSort))
    @operation_returns_collection_of(Interface)  # IQuestion.
    @export_read_operation()
    @operation_for_version('devel')
    def searchQuestions(search_text=None,
                        # Lp wants a sequence, but lazr.restful only supports
                        # lists; cast the tuple as a list.
                        status=list(QUESTION_STATUS_DEFAULT_SEARCH),
                        language=None, sort=None, participation=None,
                        needs_attention=None):
        """Search the person's questions.
Example #8
0
class ISourcePackageRecipeEditableAttributes(IHasOwner):
    """ISourcePackageRecipe attributes that can be edited.

    These attributes need launchpad.View to see, and launchpad.Edit to change.
    """
    daily_build_archive = exported(
        Reference(IArchive, title=_("The archive to use for daily builds.")))

    builder_recipe = Attribute(
        _("The bzr-builder data structure for the recipe."))

    owner = exported(
        PersonChoice(
            title=_('Owner'),
            required=True,
            readonly=False,
            vocabulary='UserTeamsParticipationPlusSelf',
            description=_("The person or team who can edit this recipe.")))

    distroseries = exported(
        List(ReferenceChoice(schema=IDistroSeries,
                             vocabulary='BuildableDistroSeries'),
             title=_("Default distribution series"),
             description=_("If built daily, these are the distribution "
                           "versions that the recipe will be built for."),
             readonly=True))
    build_daily = exported(
        Bool(title=_("Built daily"),
             description=_(
                 "Automatically build each day, if the source has changed.")))

    name = exported(
        TextLine(title=_("Name"),
                 required=True,
                 constraint=name_validator,
                 description=_(
                     "The name of the recipe is part of the URL and needs to "
                     "be unique for the given owner.")))

    description = exported(
        Description(title=_('Description'),
                    required=False,
                    description=_('A short description of the recipe.')))

    date_last_modified = exported(Datetime(required=True, readonly=True))

    is_stale = Bool(title=_('Recipe is stale.'))
Example #9
0
class IBugBranch(IHasBug):
    """A branch linked to a bug."""

    export_as_webservice_entry()

    bug = exported(BugField(title=_("Bug #"), required=True, readonly=True))
    branch = exported(
        ReferenceChoice(title=_("Branch"),
                        schema=IBranch,
                        vocabulary="Branch",
                        required=True))

    datecreated = Attribute("The date on which I was created.")
    registrant = Object(schema=IPerson,
                        readonly=True,
                        required=True,
                        title=_("The person who linked the bug to the branch"))
class IProductSeriesLimitedView(Interface):

    name = exported(
        ProductSeriesNameField(
            title=_('Name'),
            description=_(
                "The name of the series is a short, unique name "
                "that identifies it, being used in URLs. It must be all "
                "lowercase, with no special characters. For example, '2.0' "
                "or 'trunk'."),
            constraint=name_validator))

    product = exported(
        ReferenceChoice(title=_('Project'),
                        required=True,
                        vocabulary='Product',
                        schema=Interface),  # really IProduct
        exported_as='project')
    productID = Attribute('The product ID.')
Example #11
0
class IQuestionCollection(Interface):
    """An object that can be used to search through a collection of questions.
    """
    @operation_parameters(
        search_text=TextLine(title=_('Search text'), required=False),
        status=List(title=_('Status'),
                    required=False,
                    value_type=Choice(vocabulary=QuestionStatus)),
        language=List(title=_('Language'),
                      required=False,
                      value_type=ReferenceChoice(vocabulary='Language')),
        sort=Choice(title=_('Sort'), required=False, vocabulary=QuestionSort))
    @operation_returns_collection_of(Interface)  # IQuestion.
    @export_read_operation()
    @operation_for_version('devel')
    def searchQuestions(search_text=None,
                        status=list(QUESTION_STATUS_DEFAULT_SEARCH),
                        language=None,
                        sort=None):
        """Return the questions from the collection matching search criteria.

        :param search_text: A string that is matched against the question
            title and description. If None, the search_text is not included as
            a filter criteria.

        :param status: A sequence of QuestionStatus Items. If None or an empty
            sequence, the status is not included as a filter criteria.

        :param language: An ILanguage or a sequence of ILanguage objects to
            match against the question's language. If None or an empty
            sequence, the language is not included as a filter criteria.

        :param sort: An attribute of QuestionSort. If None, a default value is
            used. When there is a search_text value, the default is to sort by
            RELEVANCY, otherwise results are sorted NEWEST_FIRST.
        """

    def getQuestionLanguages():
        """Return the set of ILanguage used by all the questions in the
class IDistroArchSeriesPublic(IHasBuildRecords, IHasOwner):
    """Public attributes for a DistroArchSeries."""

    id = Attribute("Identifier")
    distroseries = exported(
        Reference(IDistroSeries,
                  title=_("The context distroseries"),
                  required=False,
                  readonly=False))
    processor = exported(
        ReferenceChoice(title=_("Processor"),
                        required=True,
                        readonly=True,
                        vocabulary='Processor',
                        schema=IProcessor))
    architecturetag = exported(TextLine(
        title=_("Architecture Tag"),
        description=_(
            "The architecture tag, or short piece of text that "
            "identifies this architecture. All binary packages in the "
            "archive will use this tag in their filename. Please get it "
            "correct. It should really never be changed!"),
        required=True,
        constraint=name_validator),
                               exported_as="architecture_tag")
    official = exported(
        Bool(title=_("Official Support"),
             description=_("Indicate whether or not this port has official "
                           "support from the vendor of the distribution."),
             required=True))
    owner = exported(
        Reference(IPerson,
                  title=_('The person who registered this port.'),
                  required=True))
    package_count = exported(
        Int(title=_("Package Count"),
            description=_('A cache of the number of packages published '
                          'in the RELEASE pocket of this port.'),
            readonly=False,
            required=False))
    supports_virtualized = exported(
        Bool(title=_("PPA support available"),
             description=_("Indicate whether or not this port has support "
                           "for building PPA packages."),
             readonly=True,
             required=False))
    enabled = exported(Bool(
        title=_("Enabled"),
        description=_(
            "Whether or not this DistroArchSeries is enabled for build "
            "creation and publication."),
        readonly=False,
        required=False),
                       as_of="devel")

    # Joins.
    packages = Attribute('List of binary packages in this port.')

    # Page layouts helpers.
    title = exported(
        TextLine(title=_('Title'),
                 description=_("The title of this distroarchseries.")))

    displayname = exported(TextLine(
        title=_("Display name"),
        description=_("The display name of this distroarchseries.")),
                           exported_as="display_name")

    # Other useful bits.
    isNominatedArchIndep = exported(Bool(
        title=_("Is Nominated Arch Independent"),
        description=_(
            'True if this distroarchseries is the NominatedArchIndep '
            'one.')),
                                    exported_as="is_nominated_arch_indep")
    main_archive = exported(
        Reference(
            Interface,  # Really IArchive, circular import fixed below.
            title=_('Main Archive'),
            description=_("The main archive of the distroarchseries.")))
    chroot_url = exported(
        TextLine(title=_("Build chroot URL"),
                 description=_("The URL to the current build chroot for this "
                               "distroarchseries."),
                 readonly=True))

    def updatePackageCount():
        """Update the cached binary package count for this distro arch
        series.
        """

    def getPocketChroot(pocket, exact_pocket=False, image_type=None):
        """Return the PocketChroot for this series, pocket, and image type.

        If exact_pocket is False, this follows pocket dependencies and finds
        the chroot for the closest pocket that exists: for example, if no
        chroot exists for SECURITY, then it will choose the one for RELEASE.
        If exact_pocket is True, this only finds chroots for exactly the
        given pocket.

        The image type defaults to `BuildBaseImageType.CHROOT`.
        """

    def getChroot(default=None, pocket=None, image_type=None):
        """Return the Chroot for this series, pocket, and image type.

        It uses getPocketChroot and if not found returns 'default'.

        The pocket defaults to `PackagePublishingPocket.RELEASE`; the image
        type defaults to `BuildBaseImageType.CHROOT`.
        """

    @operation_parameters(pocket=Choice(vocabulary=PackagePublishingPocket,
                                        required=False),
                          image_type=Choice(vocabulary=BuildBaseImageType,
                                            required=False))
    @export_read_operation()
    @operation_for_version("devel")
    def getChrootURL(pocket=None, image_type=None):
        """Return the chroot URL for this series, pocket, and image type.

        The pocket defaults to "Release"; the image type defaults to "Chroot
        tarball".
        """

    def addOrUpdateChroot(chroot, pocket=None, image_type=None):
        """Return the just added or modified PocketChroot.

        The pocket defaults to `PackagePublishingPocket.RELEASE`; the image
        type defaults to `BuildBaseImageType.CHROOT`.
        """

    def searchBinaryPackages(text):
        """Search BinaryPackageRelease published in this series for those
        matching the given text."""

    def __getitem__(name):
        """Getter"""

    def getBinaryPackage(name):
        """Return the DistroArchSeriesBinaryPackage with the given name in
Example #13
0
class IGitRefView(IHasMergeProposals, IHasRecipes, IPrivacy, IInformationType):
    """IGitRef attributes that require launchpad.View permission."""

    repository = exported(
        ReferenceChoice(
            title=_("Repository"),
            required=True,
            readonly=True,
            vocabulary="GitRepository",
            # Really IGitRepository, patched in _schema_circular_imports.py.
            schema=Interface,
            description=_("The Git repository containing this reference.")))

    repository_url = Attribute(
        "The repository URL, if this is a reference in a remote repository.")

    path = exported(
        TextLine(
            title=_("Path"),
            required=True,
            readonly=True,
            description=_(
                "The full path of this reference, e.g. refs/heads/master.")))

    name = Attribute(
        "A shortened version of the full path to this reference, with any "
        "leading refs/heads/ removed.")

    url_quoted_name = Attribute("The reference name, quoted for use in URLs.")

    commit_sha1 = exported(
        TextLine(
            title=_("Commit SHA-1"),
            required=True,
            readonly=True,
            description=_(
                "The full SHA-1 object name of the commit object referenced by "
                "this reference.")))

    object_type = Choice(title=_("Object type"),
                         required=True,
                         readonly=True,
                         vocabulary=GitObjectType)

    author = Attribute(
        "The author of the commit pointed to by this reference.")
    author_date = Datetime(
        title=_("The author date of the commit pointed to by this reference."),
        required=False,
        readonly=True)

    committer = Attribute(
        "The committer of the commit pointed to by this reference.")
    committer_date = Datetime(title=_(
        "The committer date of the commit pointed to by this reference."),
                              required=False,
                              readonly=True)

    commit_message = Text(title=_(
        "The commit message of the commit pointed to by this reference."),
                          required=False,
                          readonly=True)

    display_name = TextLine(title=_("Display name"),
                            required=True,
                            readonly=True,
                            description=_("Display name of the reference."))

    displayname = Attribute(
        "Copy of display_name for IHasMergeProposals views.")

    commit_message_first_line = TextLine(
        title=_("The first line of the commit message."),
        required=False,
        readonly=True)

    identity = Attribute(
        "The identity of this reference.  This will be the shortened path to "
        "the containing repository, plus a colon, plus the reference path "
        "with any leading refs/heads/ removed; for example, launchpad:master.")

    unique_name = Attribute(
        "The unique name of this reference.  This will be the unique name of "
        "the containing repository, plus a colon, plus the reference path "
        "with any leading refs/heads/ removed; for example, "
        "~launchpad-pqm/launchpad:master.")

    repository_type = Attribute(
        "The type of the repository containing this reference.")

    owner = Attribute("The owner of the repository containing this reference.")

    target = Attribute(
        "The target of the repository containing this reference.")

    namespace = Attribute(
        "The namespace of the repository containing this reference, as an "
        "`IGitNamespace`.")

    def getCodebrowseUrl():
        """Construct a browsing URL for this Git reference."""

    def getCodebrowseUrlForRevision(commit):
        """Construct a browsing URL for this Git at the given commit"""

    information_type = Attribute(
        "The type of information contained in the repository containing this "
        "reference.")

    private = Bool(
        title=_("Private"),
        required=False,
        readonly=True,
        description=_(
            "The repository containing this reference is visible only to its "
            "subscribers."))

    def visibleByUser(user):
        """Can the specified user see the repository containing this
        reference?"""

    def transitionToInformationType(information_type,
                                    user,
                                    verify_policy=True):
        """Set the information type for this reference's repository.

        :param information_type: The `InformationType` to transition to.
        :param user: The `IPerson` who is making the change.
        :param verify_policy: Check if the new information type complies
            with the `IGitNamespacePolicy`.
        """

    reviewer = Attribute(
        "The person or exclusive team that is responsible for reviewing "
        "proposals and merging into this reference.")

    code_reviewer = Attribute(
        "The reviewer if set, otherwise the owner of the repository "
        "containing this reference.")

    def isPersonTrustedReviewer(reviewer):
        """Return true if the `reviewer` is a trusted reviewer.

        The reviewer is trusted if they either own the repository containing
        this reference, or are in the team that owns the repository, or they
        are in the review team for the repository.
        """

    subscriptions = Attribute(
        "GitSubscriptions associated with the repository containing this "
        "reference.")

    subscribers = Attribute(
        "Persons subscribed to the repository containing this reference.")

    def subscribe(person, notification_level, max_diff_lines,
                  code_review_level, subscribed_by):
        """Subscribe this person to the repository containing this reference.

        :param person: The `Person` to subscribe.
        :param notification_level: The kinds of repository changes that
            cause notification.
        :param max_diff_lines: The maximum number of lines of diff that may
            appear in a notification.
        :param code_review_level: The kinds of code review activity that
            cause notification.
        :param subscribed_by: The person who is subscribing the subscriber.
            Most often the subscriber themselves.
        :return: A new or existing `GitSubscription`.
        """

    def getSubscription(person):
        """Return the `GitSubscription` for this person."""

    def unsubscribe(person, unsubscribed_by):
        """Remove the person's subscription to this reference's repository.

        :param person: The person or team to unsubscribe from the repository.
        :param unsubscribed_by: The person doing the unsubscribing.
        """

    def getNotificationRecipients():
        """Return a complete INotificationRecipientSet instance.

        The INotificationRecipientSet instance contains the subscribers
        and their subscriptions.
        """

    landing_targets = Attribute(
        "A collection of the merge proposals where this reference is "
        "the source.")
    _api_landing_targets = exported(
        CollectionField(
            title=_("Landing targets"),
            description=_(
                "A collection of the merge proposals where this reference is "
                "the source."),
            readonly=True,
            # Really IBranchMergeProposal, patched in
            # _schema_circular_imports.py.
            value_type=Reference(Interface)),
        exported_as="landing_targets")
    landing_candidates = Attribute(
        "A collection of the merge proposals where this reference is "
        "the target.")
    _api_landing_candidates = exported(
        CollectionField(
            title=_("Landing candidates"),
            description=_(
                "A collection of the merge proposals where this reference is "
                "the target."),
            readonly=True,
            # Really IBranchMergeProposal, patched in
            # _schema_circular_imports.py.
            value_type=Reference(Interface)),
        exported_as="landing_candidates")
    dependent_landings = exported(
        CollectionField(
            title=_("Dependent landings"),
            description=_(
                "A collection of the merge proposals that are dependent on this "
                "reference."),
            readonly=True,
            # Really IBranchMergeProposal, patched in _schema_circular_imports.py.
            value_type=Reference(Interface)))

    def getPrecachedLandingTargets(user):
        """Return precached landing targets.

        Target and prerequisite repositories are preloaded.
        """

    def getPrecachedLandingCandidates(user):
        """Return precached landing candidates.

        Source and prerequisite repositories are preloaded.
        """

    # XXX cjwatson 2015-04-16: Rename in line with landing_targets above
    # once we have a better name.
    def addLandingTarget(registrant,
                         merge_target,
                         merge_prerequisite=None,
                         date_created=None,
                         needs_review=None,
                         description=None,
                         review_requests=None,
                         commit_message=None):
        """Create a new BranchMergeProposal with this reference as the source.

        Both the target and the prerequisite, if it is there, must be
        references whose repositories have the same target as the source.

        References in personal repositories cannot specify merge proposals.

        :param registrant: The person who is adding the landing target.
        :param merge_target: Must be another reference, and different to
            self.
        :param merge_prerequisite: Optional, but if it is not None it must
            be another reference.
        :param date_created: Used to specify the date_created value of the
            merge request.
        :param needs_review: Used to specify the proposal is ready for
            review right now.
        :param description: A description of the bugs fixed, features added,
            or refactorings.
        :param review_requests: An optional list of (`Person`, review_type).
        """

    @operation_parameters(
        # merge_target and merge_prerequisite are actually IGitRef, patched
        # in _schema_circular_imports.
        merge_target=Reference(schema=Interface),
        merge_prerequisite=Reference(schema=Interface),
        needs_review=Bool(
            title=_("Needs review"),
            description=_(
                "If True, the proposal needs review.  Otherwise, it will be "
                "work in progress.")),
        initial_comment=Text(
            title=_("Initial comment"),
            description=_("Registrant's initial description of proposal.")),
        commit_message=Text(
            title=_("Commit message"),
            description=_("Message to use when committing this merge.")),
        reviewers=List(value_type=Reference(schema=IPerson)),
        review_types=List(value_type=TextLine()))
    @call_with(registrant=REQUEST_USER)
    # Really IBranchMergeProposal, patched in _schema_circular_imports.py.
    @export_factory_operation(Interface, [])
    @operation_for_version("devel")
    def createMergeProposal(registrant,
                            merge_target,
                            merge_prerequisite=None,
                            needs_review=None,
                            initial_comment=None,
                            commit_message=None,
                            reviewers=None,
                            review_types=None):
        """Create a new BranchMergeProposal with this reference as the source.

        Both the merge_target and the merge_prerequisite, if it is there,
        must be references whose repositories have the same target as the
        source.

        References in personal repositories cannot specify merge proposals.
        """

    @operation_parameters(
        status=List(title=_("A list of merge proposal statuses to filter by."),
                    value_type=Choice(vocabulary=BranchMergeProposalStatus)),
        merged_revision_ids=List(
            TextLine(title=_('The target revision ID of the merge.'))))
    @call_with(visible_by_user=REQUEST_USER)
    # Really IBranchMergeProposal, patched in _schema_circular_imports.py.
    @operation_returns_collection_of(Interface)
    @export_read_operation()
    @operation_for_version("devel")
    def getMergeProposals(status=None,
                          visible_by_user=None,
                          merged_revision_ids=None,
                          eager_load=False):
        """Return matching BranchMergeProposals."""

    def getDependentMergeProposals(status=None,
                                   visible_by_user=None,
                                   eager_load=False):
        """Return BranchMergeProposals dependent on merging this reference."""

    pending_updates = Attribute(
        "Whether there are recent changes in this repository that have not "
        "yet been scanned.")

    def getCommits(start,
                   limit=None,
                   stop=None,
                   union_repository=None,
                   start_date=None,
                   end_date=None,
                   handle_timeout=False,
                   logger=None):
        """Get commit information from this reference.

        :param start: The commit to start listing from.
        :param limit: If not None, return no more than this many commits.
        :param stop: If not None, ignore this commit and its ancestors.
        :param union_repository: If not None, resolve commit identifiers in
            this repository as well (particularly useful with `stop`).
        :param start_date: If not None, ignore commits before this date.
        :param end_date: If not None, ignore commits after this date.
        :param handle_timeout: If True and the backend request times out,
            synthesise commit information from what we have in the database.
        :param logger: An optional logger.
        :return: An iterable of commit information dicts.
        """

    def getLatestCommits(quantity=10,
                         extended_details=False,
                         user=None,
                         handle_timeout=False,
                         logger=None):
        """Return a specific number of the latest commits in this ref."""

    has_commits = Attribute("Whether this reference has any commits.")

    def getBlob(filename):
        """Get a blob by file name from this reference.

        :param filename: Relative path of a file in the repository.
        :return: A binary string with the blob content.
        """

    def getLatestScanJob():
        """Return the last IGitRefScanJobSource for the repository"""

    def rescan():
        """Force a rescan of the repository"""
class IProductSeriesView(ISeriesMixin, IHasAppointedDriver, IHasOwner,
                         ISpecificationGoal, IHasMilestones,
                         IHasOfficialBugTags, IHasExpirableBugs,
                         IHasTranslationImports, IHasTranslationTemplates,
                         IServiceUsage):
    status = exported(
        Choice(title=_('Status'),
               required=True,
               vocabulary=SeriesStatus,
               default=SeriesStatus.DEVELOPMENT))

    parent = Attribute('The structural parent of this series - the product')

    datecreated = exported(Datetime(title=_('Date Registered'),
                                    required=True,
                                    readonly=True),
                           exported_as='date_created')

    owner = exported(
        PersonChoice(
            title=_('Owner'),
            required=True,
            vocabulary='ValidOwner',
            description=_('Project owner, either a valid Person or Team')))

    driver = exported(
        PersonChoice(
            title=_("Release manager"),
            description=_(
                "The person or team responsible for decisions about features "
                "and bugs that will be targeted to this series. If you don't "
                "nominate someone here, then the owner of this series will "
                "automatically have those permissions, as will the project "
                "and project group drivers."),
            required=False,
            vocabulary='ValidPersonOrTeam'))

    title = exported(
        Title(title=_('Title'),
              description=_("The product series title.  "
                            "Should be just a few words.")))

    displayname = exported(TextLine(
        title=_('Display Name'),
        description=_(
            "Display name.  In this case we have removed the underlying "
            "database field, and this attribute just returns the name.")),
                           exported_as='display_name')

    releases = exported(
        CollectionField(title=_("An iterator over the releases in this "
                                "Series, sorted with latest release first."),
                        readonly=True,
                        value_type=Reference(schema=IProductRelease)))

    release_files = Attribute("An iterator over the release files in this "
                              "Series, sorted with latest release first.")

    packagings = Attribute("An iterator over the Packaging entries "
                           "for this product series.")

    specifications = Attribute("The specifications targeted to this "
                               "product series.")

    sourcepackages = Attribute(
        _("List of distribution packages for this "
          "product series"))

    milestones = exported(doNotSnapshot(
        CollectionField(title=_("The visible milestones associated with this "
                                "project series, ordered by date expected."),
                        readonly=True,
                        value_type=Reference(schema=IMilestone))),
                          exported_as='active_milestones')

    all_milestones = exported(
        doNotSnapshot(
            CollectionField(title=_(
                "All milestones associated with this project series, "
                "ordered by date expected."),
                            readonly=True,
                            value_type=Reference(schema=IMilestone))))

    branch = exported(
        ReferenceChoice(title=_('Branch'),
                        vocabulary='BranchRestrictedOnProduct',
                        schema=IBranch,
                        required=False,
                        description=_(
                            "The Bazaar branch for this series.  Leave blank "
                            "if this series is not maintained in Bazaar.")))

    translations_autoimport_mode = exported(Choice(
        title=_('Import settings'),
        vocabulary=TranslationsBranchImportMode,
        required=True,
        description=_("Specify which files will be imported from the "
                      "source code branch.")),
                                            as_of="devel")

    potemplate_count = Int(
        title=_("The total number of POTemplates in this series."),
        readonly=True,
        required=True)

    productserieslanguages = Attribute(
        "The set of ProductSeriesLanguages for this series.")

    translations_branch = ReferenceChoice(
        title=_("Translations export branch"),
        vocabulary='HostedBranchRestrictedOnOwner',
        schema=IBranch,
        required=False,
        description=_("A Bazaar branch to commit translation snapshots to.  "
                      "Leave blank to disable."))

    all_specifications = doNotSnapshot(
        Attribute('All specifications linked to this series.'))

    def getCachedReleases():
        """Gets a cached copy of this series' releases.

        Returns None if there is no release."""

    def getLatestRelease():
        """Gets the most recent release in the series.

        Returns None if there is no release."""

    def getRelease(version):
        """Get the release in this series that has the specified version.
        Return None is there is no such release.
        """

    def getPackage(distroseries):
        """Return the SourcePackage for this project series in the supplied
        distroseries. This will use a Packaging record if one exists, but
        it will also work through the ancestry of the distroseries to try
        to find a Packaging entry that may be relevant."""

    def getUbuntuTranslationFocusPackage():
        """Return the SourcePackage that packages this project in Ubuntu's
        translation focus or current series or any series, in that order."""

    def setPackaging(distroseries, sourcepackagename, owner):
        """Create or update a Packaging record for this product series,
        connecting it to the given distroseries and source package name.
        """

    def getPackagingInDistribution(distribution):
        """Return all the Packaging entries for this product series for the
        given distribution. Note that this only returns EXPLICT packaging
        entries, it does not look at distro series ancestry in the same way
        that IProductSeries.getPackage() does.
        """

    def getPOTemplate(name):
        """Return the POTemplate with this name for the series."""

    # where are the tarballs released from this branch placed?
    releasefileglob = exported(TextLine(
        title=_("Release URL pattern"),
        required=False,
        constraint=validate_release_glob,
        description=_('A URL pattern that matches releases that are part '
                      'of this series.  Launchpad automatically scans this '
                      'site to import new releases.  Example: '
                      'http://ftp.gnu.org/gnu/emacs/emacs-21.*.tar.gz')),
                               exported_as='release_finder_url_pattern')

    releaseverstyle = Attribute("The version numbering style for this "
                                "series of releases.")

    is_development_focus = Attribute(
        _("Is this series the development focus for the product?"))

    @operation_parameters(include_inactive=Bool(title=_("Include inactive"),
                                                required=False,
                                                default=False))
    @export_read_operation()
    @export_operation_as('get_timeline')
    def getTimeline(include_inactive):
        """Return basic timeline data useful for creating a diagram.
class ISpecificationView(IHasOwner, IHasLinkedBranches):
    """Specification's attributes and methods that require
    the permission launchpad.LimitedView.
    """

    name = exported(SpecNameField(
        title=_('Name'),
        required=True,
        readonly=False,
        description=_(
            "May contain lower-case letters, numbers, and dashes. "
            "It will be used in the specification url. "
            "Examples: mozilla-type-ahead-find, postgres-smart-serial.")),
                    as_of="devel")
    title = exported(Title(
        title=_('Title'),
        required=True,
        description=_(
            "Describe the feature as clearly as possible in up to 70 "
            "characters. This title is displayed in every feature "
            "list or report.")),
                     as_of="devel")
    specurl = exported(
        SpecURLField(
            title=_('Specification URL'),
            required=False,
            description=_(
                "The URL of the specification. This is usually a wiki page."),
            constraint=valid_webref),
        exported_as="specification_url",
        as_of="devel",
    )
    summary = exported(Summary(
        title=_('Summary'),
        required=True,
        description=_(
            "A single-paragraph description of the feature. "
            "This will also be displayed in most feature listings.")),
                       as_of="devel")

    definition_status = exported(Choice(
        title=_('Definition Status'),
        readonly=True,
        vocabulary=SpecificationDefinitionStatus,
        default=SpecificationDefinitionStatus.NEW,
        description=_(
            "The current status of the process to define the "
            "feature and get approval for the implementation plan.")),
                                 as_of="devel")

    assignee = exported(PublicPersonChoice(
        title=_('Assignee'),
        required=False,
        description=_("The person responsible for implementing the feature."),
        vocabulary='ValidPersonOrTeam'),
                        as_of="devel")
    assigneeID = Attribute('db assignee value')
    drafter = exported(PublicPersonChoice(
        title=_('Drafter'),
        required=False,
        description=_(
            "The person responsible for drafting the specification."),
        vocabulary='ValidPersonOrTeam'),
                       as_of="devel")
    drafterID = Attribute('db drafter value')
    approver = exported(PublicPersonChoice(
        title=_('Approver'),
        required=False,
        description=_(
            "The person responsible for approving the specification, "
            "and for reviewing the code when it's ready to be landed."),
        vocabulary='ValidPersonOrTeam'),
                        as_of="devel")
    approverID = Attribute('db approver value')

    priority = exported(Choice(title=_('Priority'),
                               vocabulary=SpecificationPriority,
                               default=SpecificationPriority.UNDEFINED,
                               required=True),
                        as_of="devel")
    datecreated = exported(
        Datetime(title=_('Date Created'), required=True, readonly=True),
        as_of="devel",
        exported_as="date_created",
    )
    owner = exported(PublicPersonChoice(title=_('Owner'),
                                        required=True,
                                        readonly=True,
                                        vocabulary='ValidPersonOrTeam'),
                     as_of="devel")

    product = Choice(title=_('Project'), required=False, vocabulary='Product')
    distribution = Choice(title=_('Distribution'),
                          required=False,
                          vocabulary='Distribution')

    # Exported as readonly for simplicity, but could be exported as read-write
    # using setTarget() as the mutator.
    target = exported(
        ReferenceChoice(
            title=_('For'),
            required=True,
            vocabulary='DistributionOrProduct',
            description=_(
                "The project for which this proposal is being made."),
            schema=ISpecificationTarget),
        as_of="devel",
        readonly=True,
    )

    productseries = Choice(
        title=_('Series Goal'),
        required=False,
        vocabulary='FilteredProductSeries',
        description=_(
            "Choose a series in which you would like to deliver this "
            "feature. Selecting '(nothing selected)' will clear the goal."))
    distroseries = Choice(
        title=_('Series Goal'),
        required=False,
        vocabulary='FilteredDistroSeries',
        description=_(
            "Choose a series in which you would like to deliver this "
            "feature. Selecting '(nothing selected)' will clear the goal."))

    # milestone
    milestone = exported(ReferenceChoice(
        title=_('Milestone'),
        required=False,
        vocabulary='Milestone',
        description=_(
            "The milestone in which we would like this feature to be "
            "delivered."),
        schema=IMilestone),
                         as_of="devel")

    # nomination to a series for release management
    # XXX: It'd be nice to export goal as read-only, but it's tricky because
    # users will need to be aware of goalstatus as what's returned by .goal
    # may not be the accepted goal.
    goal = Attribute("The series for which this feature is a goal.")
    goalstatus = Choice(
        title=_('Goal Acceptance'),
        vocabulary=SpecificationGoalStatus,
        default=SpecificationGoalStatus.PROPOSED,
        description=_(
            "Whether or not the drivers have accepted this feature as "
            "a goal for the targeted series."))
    goal_proposer = Attribute("The person who nominated the spec for "
                              "this series.")
    date_goal_proposed = Attribute("The date of the nomination.")
    goal_decider = Attribute("The person who approved or declined "
                             "the spec a a goal.")
    date_goal_decided = Attribute("The date the spec was approved "
                                  "or declined as a goal.")

    work_items = List(description=_(
        "All non-deleted work items for this spec, sorted by "
        "their 'sequence'"),
                      value_type=Reference(schema=ISpecificationWorkItem),
                      readonly=True)
    whiteboard = exported(Text(
        title=_('Status Whiteboard'),
        required=False,
        description=_("Any notes on the status of this spec you would like to "
                      "make. Your changes will override the current text.")),
                          as_of="devel")
    workitems_text = exported(WorkItemsText(
        title=_('Work Items'),
        required=False,
        readonly=True,
        description=_(
            "Work items for this specification input in a text format. "
            "Your changes will override the current work items.")),
                              as_of="devel")
    direction_approved = exported(Bool(
        title=_('Basic direction approved?'),
        required=True,
        default=False,
        description=_("Check this to indicate that the drafter and assignee "
                      "have satisfied the approver that they are headed in "
                      "the right basic direction with this specification.")),
                                  as_of="devel")
    man_days = Int(
        title=_("Estimated Developer Days"),
        required=False,
        default=None,
        description=_(
            "An estimate of the "
            "number of developer days it will take to implement this feature. "
            "Please only provide an estimate if you are relatively confident "
            "in the number."))
    implementation_status = exported(Choice(
        title=_("Implementation Status"),
        required=True,
        readonly=True,
        default=SpecificationImplementationStatus.UNKNOWN,
        vocabulary=SpecificationImplementationStatus,
        description=_("The state of progress being made on the actual "
                      "implementation or delivery of this feature.")),
                                     as_of="devel")
    superseded_by = Choice(
        title=_("Superseded by"),
        required=False,
        default=None,
        vocabulary='Specification',
        description=_(
            "The specification "
            "which supersedes this one. Note that selecting a specification "
            "here and pressing Continue will change the specification "
            "status to Superseded."))

    # lifecycle
    starter = exported(PublicPersonChoice(
        title=_('Starter'),
        required=False,
        readonly=True,
        description=_(
            'The person who first set the state of the '
            'spec to the values that we consider mark it as started.'),
        vocabulary='ValidPersonOrTeam'),
                       as_of="devel")
    date_started = exported(Datetime(
        title=_('Date Started'),
        required=False,
        readonly=True,
        description=_('The date when this spec was marked started.')),
                            as_of="devel")

    completer = exported(PublicPersonChoice(
        title=_('Starter'),
        required=False,
        readonly=True,
        description=_(
            'The person who finally set the state of the '
            'spec to the values that we consider mark it as complete.'),
        vocabulary='ValidPersonOrTeam'),
                         as_of="devel")

    date_completed = exported(Datetime(
        title=_('Date Completed'),
        required=False,
        readonly=True,
        description=_(
            'The date when this spec was marked '
            'complete. Note that complete also includes "obsolete" and '
            'superseded. Essentially, it is the state where no more work '
            'will be done on the feature.')),
                              as_of="devel")

    # joins
    subscriptions = Attribute('The set of subscriptions to this spec.')
    subscribers = Attribute('The set of subscribers to this spec.')
    sprints = Attribute('The sprints at which this spec is discussed.')
    sprint_links = Attribute('The entries that link this spec to sprints.')
    dependencies = exported(
        CollectionField(
            title=_('Specs on which this one depends.'),
            value_type=Reference(schema=Interface),  # ISpecification, really.
            readonly=True),
        as_of="devel")
    linked_branches = exported(
        CollectionField(
            title=_("Branches associated with this spec, usually "
                    "branches on which this spec is being implemented."),
            value_type=Reference(schema=Interface),  # ISpecificationBranch
            readonly=True),
        as_of="devel")

    def getDependencies():
        """Specs on which this one depends."""

    def getBlockedSpecs():
        """Specs for which this spec is a dependency."""

    # emergent properties
    informational = Attribute('Is True if this spec is purely informational '
                              'and requires no implementation.')
    is_complete = exported(Bool(
        title=_('Is started'),
        readonly=True,
        required=True,
        description=_(
            'Is True if this spec is already completely implemented. '
            'Note that it is True for informational specs, since '
            'they describe general functionality rather than specific '
            'code to be written. It is also true of obsolete and '
            'superseded specs, since there is no longer any need '
            'to schedule work for them.')),
                           as_of="devel")

    is_incomplete = Attribute(
        'Is True if this work still needs to '
        'be done. Is in fact always the opposite of is_complete.')
    is_blocked = Attribute('Is True if this spec depends on another spec '
                           'which is still incomplete.')
    is_started = exported(Bool(
        title=_('Is started'),
        readonly=True,
        required=True,
        description=_(
            'Is True if the spec is in a state which '
            'we consider to be "started". This looks at the delivery '
            'attribute, and also considers informational specs to be '
            'started when they are approved.')),
                          as_of="devel")

    lifecycle_status = exported(Choice(
        title=_('Lifecycle Status'),
        vocabulary=SpecificationLifecycleStatus,
        default=SpecificationLifecycleStatus.NOTSTARTED,
        readonly=True),
                                as_of="devel")

    def all_deps():
        """All the dependencies, including dependencies of dependencies.

        If a user is provided, filters to only dependencies the user can see.
        """

    def all_blocked():
        """All specs blocked on this, and those blocked on the blocked ones.

        If a user is provided, filters to only blocked dependencies the user
        can see.
        """

    def validateMove(target):
        """Check that the specification can be moved to the target."""

    def getSprintSpecification(sprintname):
        """Get the record that links this spec to the named sprint."""

    def notificationRecipientAddresses():
        """Return the list of email addresses that receive notifications."""

    has_accepted_goal = exported(Bool(
        title=_('Series goal is accepted'),
        readonly=True,
        required=True,
        description=_(
            'Is true if this specification has been '
            'proposed as a goal for a specific series, '
            'and the drivers of that series have accepted the goal.')),
                                 as_of="devel")

    # lifecycle management
    def updateLifecycleStatus(user):
        """Mark the specification as started, and/or complete, if appropriate.

        This will verify that the state of the specification is in fact
        "complete" (there is a completeness test in
        Specification.is_complete) and then record the completer and the
        date_completed. If the spec is not completed, then it ensures that
        nothing is recorded about its completion.

        It returns a SpecificationLifecycleStatus dbschema showing the
        overall state of the specification IF the state has changed.
        """

    # event-related methods
    def getDelta(old_spec, user):
        """Return a dictionary of things that changed between this spec and
        the old_spec.

        This method is primarily used by event subscription code, to
        determine what has changed during an ObjectModifiedEvent.
        """

    # subscription-related methods
    def subscription(person):
        """Return the subscription for this person to this spec, or None."""

    @operation_parameters(person=Reference(IPerson,
                                           title=_('Person'),
                                           required=True),
                          essential=copy_field(
                              ISpecificationSubscription['essential'],
                              required=False))
    @call_with(subscribed_by=REQUEST_USER)
    @export_write_operation()
    @operation_for_version('devel')
    def subscribe(person, subscribed_by=None, essential=False):
        """Subscribe this person to the feature specification."""

    @operation_parameters(person=Reference(IPerson,
                                           title=_('Person'),
                                           required=False))
    @call_with(unsubscribed_by=REQUEST_USER)
    @export_write_operation()
    @operation_for_version('devel')
    def unsubscribe(person, unsubscribed_by):
        """Remove the person's subscription to this spec."""

    def getSubscriptionByName(name):
        """Return a subscription based on the person's name, or None."""

    def isSubscribed(person):
        """Is person subscribed to this spec?

        Returns True if the user is explicitly subscribed to this spec
        (no matter what the type of subscription), otherwise False.

        If person is None, the return value is always False.
        """

    # sprints
    def linkSprint(sprint, user):
        """Put this spec on the agenda of the sprint."""

    def unlinkSprint(sprint):
        """Remove this spec from the agenda of the sprint."""

    # dependencies
    def createDependency(specification):
        """Create a dependency for this spec on the spec provided."""

    def removeDependency(specification):
        """Remove any dependency of this spec on the spec provided."""

    # branches
    def getBranchLink(branch):
        """Return the SpecificationBranch link for the branch, or None."""

    def getLinkedBugTasks(user):
        """Return the bug tasks that are relevant to this blueprint.

        When multiple tasks are on a bug, if one of the tasks is for the
        target, then only that task is returned. Otherwise the default
        bug task is returned.

        :param user: The user doing the search.
        """

    def getAllowedInformationTypes(who):
        """Get a list of acceptable `InformationType`s for this spec."""
Example #16
0
class IBugWatch(IHasBug):
    """A bug on a remote system."""
    export_as_webservice_entry()

    id = Int(title=_('ID'), required=True, readonly=True)

    # Actually refers to Bug; redefined in bug.py.
    bug = exported(
        Reference(title=_('Bug'),
                  schema=Interface,
                  required=True,
                  readonly=True))
    bugtracker = exported(ReferenceChoice(
        title=_('Bug System'),
        required=True,
        schema=IBugTracker,
        vocabulary='BugTracker',
        description=_("You can register new bug trackers from the Launchpad "
                      "Bugs home page.")),
                          exported_as='bug_tracker')
    remotebug = exported(StrippedTextLine(
        title=_('Remote Bug'),
        required=True,
        readonly=False,
        description=_(
            "The bug number of this bug in the remote bug tracker.")),
                         exported_as='remote_bug')
    remotestatus = exported(TextLine(title=_('Remote Status')),
                            exported_as='remote_status')
    remote_importance = exported(TextLine(title=_('Remote Importance')))
    lastchanged = exported(Datetime(title=_('Last Changed')),
                           exported_as='date_last_changed')
    lastchecked = exported(Datetime(title=_('Last Checked')),
                           exported_as='date_last_checked')
    last_error_type = exported(
        Choice(title=_('Last Error Type'), vocabulary=BugWatchActivityStatus))
    datecreated = exported(Datetime(title=_('Date Created'),
                                    required=True,
                                    readonly=True),
                           exported_as='date_created')
    owner = exported(
        Reference(title=_('Owner'),
                  required=True,
                  readonly=True,
                  schema=Interface))
    activity = Attribute('The activity history of this BugWatch.')
    next_check = exported(Datetime(title=_('Next Check')),
                          exported_as='date_next_checked')

    # Useful joins.
    bugtasks = exported(
        CollectionField(
            description=_(
                'The tasks which this watch will affect. '
                'In Launchpad, a bug watch can be linked to one or more '
                'tasks, and if it is linked and we notice a status change '
                'in the watched bug then we will try to update the '
                'Launchpad bug task accordingly.'),
            # value_type is redefined in bugtask.py, to use the right
            # interface.
            value_type=Reference(schema=Interface, )),
        exported_as='bug_tasks')

    # Properties.
    needscheck = Attribute(
        "A True or False indicator of whether or not "
        "this watch needs to be synchronised. The algorithm used considers "
        "the severity of the bug, as well as the activity on the bug, to "
        "ensure that we spend most effort on high-importance and "
        "high-activity bugs.")

    unpushed_comments = Attribute(
        "A set of comments on this BugWatch that need to be pushed to "
        "the remote bug tracker.")

    # Required for Launchpad pages.
    title = exported(Text(title=_('Bug watch title'), readonly=True))

    url = exported(
        Text(title=_('The URL at which to view the remote bug.'),
             readonly=True))

    can_be_rescheduled = Attribute(
        "A True or False indicator of whether or not this watch can be "
        "rescheduled.")

    def updateImportance(remote_importance, malone_importance):
        """Update the importance of the bug watch and any linked bug task.

        The lastchanged attribute gets set to the current time.
        """

    def updateStatus(remote_status, malone_status):
        """Update the status of the bug watch and any linked bug task.

        The lastchanged attribute gets set to the current time.
        """

    def destroySelf():
        """Delete this bug watch."""

    def hasComment(comment_id):
        """Return True if a comment has been imported for the BugWatch.

        If the comment has not been imported, return False.

        :param comment_id: The remote ID of the comment.
        """

    def addComment(comment_id, message):
        """Link and imported comment to the BugWatch.

        :param comment_id: The remote ID of the comment.

        :param message: The imported comment as a Launchpad Message object.
        """

    def getBugMessages(clauses):
        """Return all the `IBugMessage`s that reference this BugWatch.
        
        :param clauses: A iterable of Storm clauses to limit the messages.
        """

    def getImportedBugMessages():
        """Return all the `IBugMessage`s that have been imported."""

    def addActivity(result=None, message=None, oops_id=None):
        """Add an `IBugWatchActivity` record for this BugWatch."""

    def setNextCheck(next_check):
        """Set the next_check time of the watch.

        :raises: `BugWatchCannotBeRescheduled` if
                 `IBugWatch.can_be_rescheduled` is False.
        """

    def reset():
        """Completely reset the watch.
Example #17
0
class IDistroSeriesPublic(ISeriesMixin, IHasAppointedDriver, IHasOwner,
                          IBugTarget, ISpecificationGoal, IHasMilestones,
                          IHasOfficialBugTags, IHasBuildRecords,
                          IHasTranslationImports, IHasTranslationTemplates,
                          IServiceUsage, IHasExpirableBugs):
    """Public IDistroSeries properties."""

    id = Attribute("The distroseries's unique number.")
    name = exported(
        DistroSeriesNameField(title=_("Name"),
                              required=True,
                              description=_("The name of this series."),
                              constraint=name_validator))
    display_name = exported(TextLine(title=_("Display name"),
                                     required=True,
                                     description=_("The series displayname.")),
                            exported_as="displayname")
    displayname = Attribute("Display name (deprecated)")
    fullseriesname = exported(
        TextLine(title=_("Series full name"),
                 required=False,
                 description=_("The series full name, e.g. Ubuntu Warty")))
    title = exported(
        Title(title=_("Title"),
              required=True,
              description=_(
                  "The title of this series. It should be distinctive "
                  "and designed to look good at the top of a page.")))
    description = exported(
        Description(title=_("Description"),
                    required=True,
                    description=_(
                        "A detailed description of this series, with "
                        "information on the architectures covered, the "
                        "availability of security updates and any other "
                        "relevant information.")))
    version = exported(
        DistroSeriesVersionField(
            title=_("Version"),
            required=True,
            description=_("The version string for this series.")))
    distribution = exported(
        Reference(
            Interface,  # Really IDistribution, see circular import fix below.
            title=_("Distribution"),
            required=True,
            description=_("The distribution for which this is a series.")))
    distributionID = Attribute('The distribution ID.')
    named_version = Attribute('The combined display name and version.')
    parent = Attribute('The structural parent of this series - the distro')
    components = Attribute("The series components.")
    # IComponent is not exported on the api.
    component_names = exported(
        List(value_type=TextLine(),
             title=_(u'The series component names'),
             readonly=True))
    upload_components = Attribute("The series components that can be "
                                  "uploaded to.")
    suite_names = exported(
        List(value_type=TextLine(),
             title=_(u'The series pocket names'),
             readonly=True))
    sections = Attribute("The series sections.")
    status = exported(
        Choice(title=_("Status"), required=True, vocabulary=SeriesStatus))
    datereleased = exported(Datetime(title=_("Date released")))
    previous_series = exported(
        ReferenceChoice(
            title=_("Parent series"),
            description=_("The series from which this one was branched."),
            required=True,
            schema=Interface,  # Really IDistroSeries
            vocabulary='DistroSeries'),
        ("devel", dict(exported_as="previous_series")),
        ("1.0", dict(exported_as="parent_series")),
        ("beta", dict(exported_as="parent_series")),
        readonly=True)
    registrant = exported(
        PublicPersonChoice(title=_("Registrant"),
                           vocabulary='ValidPersonOrTeam'))
    owner = exported(
        Reference(
            IPerson,
            title=_("Owning team of the derived series"),
            readonly=True,
            description=_(
                "This attribute mirrors the owner of the distribution.")))
    date_created = exported(
        Datetime(title=_("The date this series was registered.")))
    driver = exported(
        ReferenceChoice(
            title=_("Driver"),
            description=_(
                "The person or team responsible for decisions about features "
                "and bugs that will be targeted to this series of the "
                "distribution."),
            required=False,
            vocabulary='ValidPersonOrTeam',
            schema=IPerson))
    changeslist = exported(
        TextLine(title=_("Email changes to"),
                 required=True,
                 description=_("The mailing list or other email address that "
                               "Launchpad should notify about new uploads."),
                 constraint=email_validator))
    sourcecount = Attribute("Source Packages Counter")
    defer_translation_imports = Bool(
        title=_("Defer translation imports"),
        description=_("Suspends any translation imports for this series"),
        default=True,
        required=True,
    )
    binarycount = Attribute("Binary Packages Counter")

    architecturecount = Attribute("The number of architectures in this "
                                  "series.")
    nominatedarchindep = exported(
        Reference(
            Interface,  # IDistroArchSeries.
            title=_("DistroArchSeries designed to build "
                    "architecture-independent packages whithin this "
                    "distroseries context."),
            default=None,
            required=False))
    messagecount = Attribute("The total number of translatable items in "
                             "this series.")
    distroserieslanguages = Attribute("The set of dr-languages in this "
                                      "series.")

    hide_all_translations = Bool(
        title=u'Hide translations for this release',
        required=True,
        description=(
            u"You may hide all translation for this distribution series so"
            " that only Launchpad administrators will be able to see them."
            " For example, you should hide these translations while they are"
            " being imported from a previous series so that translators"
            " will not be confused by imports that are in progress."),
        default=True)

    language_pack_base = Choice(title=_('Language pack base'),
                                required=False,
                                description=_('''
            Language pack with the export of all translations
            available for this distribution series when it was generated. The
            subsequent update exports will be generated based on this one.
            '''),
                                vocabulary='FilteredFullLanguagePack')

    language_pack_delta = Choice(title=_('Language pack update'),
                                 required=False,
                                 description=_('''
            Language pack with the export of all translation updates
            available for this distribution series since the language pack
            base was generated.
            '''),
                                 vocabulary='FilteredDeltaLanguagePack')

    language_pack_proposed = Choice(title=_('Proposed language pack update'),
                                    required=False,
                                    description=_('''
            Base or update language pack export that is being tested and
            proposed to be used as the new language pack base or
            language pack update for this distribution series.
            '''),
                                    vocabulary='FilteredLanguagePack')

    language_pack_full_export_requested = exported(
        Bool(title=_('Request a full language pack export'),
             required=True,
             description=_('''
            Whether next language pack generation will be a full export. This
            information is useful when update packs are too big and want to
            merge all those changes in the base pack.
            ''')))

    last_full_language_pack_exported = Object(
        title=_('Latest exported language pack with all translation files.'),
        required=False,
        readonly=True,
        schema=ILanguagePack)

    last_delta_language_pack_exported = Object(title=_(
        'Lastest exported language pack with updated translation files.'),
                                               required=False,
                                               readonly=True,
                                               schema=ILanguagePack)

    # related joins
    packagings = Attribute("All of the Packaging entries for this "
                           "distroseries.")
    specifications = Attribute("The specifications targeted to this "
                               "series.")

    language_packs = Attribute(
        "All language packs associated with this distribution series.")

    backports_not_automatic = Bool(
        title=_("Don't upgrade to backports automatically"),
        required=True,
        description=_("""
            Set NotAutomatic: yes and ButAutomaticUpgrades: yes in Release
            files generated for the backports pocket. This tells apt to
            automatically upgrade within backports, but not into it.
            """))

    include_long_descriptions = exported(
        Bool(title=_("Include long descriptions in Packages rather than in "
                     "Translation-en"),
             default=True,
             required=True,
             description=_("""
                If True, write long descriptions to the per-architecture
                Packages files; if False, write them to a Translation-en
                file common across architectures instead. Using a common
                file reduces the bandwidth footprint of enabling multiarch
                on clients, which requires downloading Packages files for
                multiple architectures.""")))

    index_compressors = exported(
        List(value_type=Choice(vocabulary=IndexCompressionType),
             title=_("Compression types to use for published index files"),
             required=True,
             description=_("""
            A list of compression types to use for published index files
            (Packages, Sources, etc.).""")))

    publish_by_hash = exported(
        Bool(title=_("Publish by-hash directories"),
             required=True,
             description=_("""
            Publish archive index files in by-hash directories so that apt
            can retrieve them based on their hash, avoiding race conditions
            between InRelease and other files during mirror updates.""")))

    advertise_by_hash = exported(
        Bool(title=_("Advertise by-hash directories"),
             required=True,
             description=_("""
            Advertise by-hash directories with a flag in the Release file so
            that apt uses them by default.  Only effective if
            publish_by_hash is also set.""")))

    strict_supported_component_dependencies = exported(Bool(
        title=_("Strict dependencies of supported components"),
        required=True,
        description=_("""
            If True, packages in supported components (main and restricted)
            may not build-depend on packages in unsupported components.  Do
            not rely on the name of this attribute, even for reading; it is
            currently subject to change.""")),
                                                       as_of="devel")

    inherit_overrides_from_parents = Bool(
        title=_("Inherit overrides from parents"),
        readonly=False,
        required=True)

    main_archive = exported(
        Reference(
            Interface,  # Really IArchive, see below for circular import fix.
            title=_('Distribution Main Archive')))

    supported = exported(
        Bool(title=_("Supported"),
             description=_(
                 "Whether or not this series is currently supported.")))

    def isUnstable():
        """Whether or not a distroseries is unstable.

        The distribution is "unstable" until it is released; after that
        point, all development on the Release pocket is stopped and
        development moves on to the other pockets.
        """

    def getLatestUploads():
        """Return the latest five source uploads for this DistroSeries.

        It returns a list containing up to five elements as
        IDistributionSourcePackageRelease instances
        """

    # DistroArchSeries lookup properties/methods.
    architectures = Attribute("All architectures in this series.")

    enabled_architectures = exported(
        doNotSnapshot(
            CollectionField(
                title=_("Enabled architectures"),
                description=_("All architectures in this series with the "
                              "'enabled' flag set."),
                value_type=Reference(schema=Interface),  # IDistroArchSeries
                readonly=True)),
        exported_as="architectures")

    virtualized_architectures = Attribute(
        "All architectures in this series where PPA is supported.")

    buildable_architectures = Attribute(
        "All architectures in this series with available chroot tarball.")

    def __getitem__(archtag):
        """Return the distroarchseries for this distroseries with the
        given architecturetag.
        """

    def __str__():
        """Return the name of the distroseries."""

    def getDistroArchSeriesByProcessor(processor):
        """Return the distroarchseries for this distroseries with the
        given architecturetag from a `IProcessor`.

        :param processor: An `IProcessor`
        :return: An `IDistroArchSeries` or None when none was found.
        """

    @operation_parameters(archtag=TextLine(title=_("The architecture tag"),
                                           required=True))
    @operation_returns_entry(Interface)
    @export_read_operation()
    def getDistroArchSeries(archtag):
        """Return the distroarchseries for this distroseries with the
        given architecturetag.
        """

    # End of DistroArchSeries lookup methods.

    def updateStatistics(ztm):
        """Update all the Rosetta stats for this distro series."""

    def updatePackageCount():
        """Update the binary and source package counts for this distro
        series."""

    @operation_parameters(name=TextLine(
        title=_("The name of the source package"), required=True))
    @operation_returns_entry(ISourcePackage)
    @export_read_operation()
    def getSourcePackage(name):
        """Return a source package in this distro series by name.

        The name given may be a string or an ISourcePackageName-providing
        object. The source package may not be published in the distro series.
        """

    def getTranslatableSourcePackages():
        """Return a list of Source packages in this distribution series
        that can be translated.
        """

    def getPrioritizedUnlinkedSourcePackages():
        """Return a list of package summaries that need packaging links.

        A summary is a dict of package (`ISourcePackage`), total_bugs,
        and total_messages (translatable messages).
        """

    def getPrioritizedPackagings():
        """Return a list of packagings that need more upstream information."""

    def getMostRecentlyLinkedPackagings():
        """Return a list of packagings that are the most recently linked.

        At most five packages are returned of those most recently linked to an
        upstream.
        """

    @operation_parameters(
        created_since_date=Datetime(
            title=_("Created Since Timestamp"),
            description=_(
                "Return items that are more recent than this timestamp."),
            required=False),
        status=Choice(
            vocabulary=PackageUploadStatus,
            title=_("Package Upload Status"),
            description=_("Return only items that have this status."),
            required=False),
        archive=Reference(
            # Really IArchive, patched in _schema_circular_imports.py
            schema=Interface,
            title=_("Archive"),
            description=_("Return only items for this archive."),
            required=False),
        pocket=Choice(
            vocabulary=PackagePublishingPocket,
            title=_("Pocket"),
            description=_("Return only items targeted to this pocket"),
            required=False),
        custom_type=Choice(vocabulary=PackageUploadCustomFormat,
                           title=_("Custom Type"),
                           description=_(
                               "Return only items with custom files of this "
                               "type."),
                           required=False),
        name=TextLine(title=_("Package or file name"), required=False),
        version=TextLine(title=_("Package version"), required=False),
        exact_match=Bool(title=_("Exact match"),
                         description=_(
                             "Whether to filter name and version by exact "
                             "matching."),
                         required=False),
    )
    # Really IPackageUpload, patched in _schema_circular_imports.py
    @operation_returns_collection_of(Interface)
    @export_read_operation()
    def getPackageUploads(status=None,
                          created_since_date=None,
                          archive=None,
                          pocket=None,
                          custom_type=None,
                          name=None,
                          version=None,
                          exact_match=False):
        """Get package upload records for this distribution series.

        :param status: Filter results by this `PackageUploadStatus`, or list
            of statuses.
        :param created_since_date: If specified, only returns items uploaded
            since the timestamp supplied.
        :param archive: Filter results for this `IArchive`.
        :param pocket: Filter results by this `PackagePublishingPocket` or a
            list of `PackagePublishingPocket`.
        :param custom_type: Filter results by this
            `PackageUploadCustomFormat`.
        :param name: Filter results by this file name or package name.
        :param version: Filter results by this version number string.
        :param exact_match: If True, look for exact string matches on the
            `name` and `version` filters.  If False, look for a substring
            match so that e.g. a package "kspreadsheetplusplus" would match
            the search string "spreadsheet".  Defaults to False.
        :return: A result set containing `IPackageUpload`.
        """

    def getUnlinkedTranslatableSourcePackages():
        """Return a list of source packages that can be translated in
        this distribution series but which lack Packaging links.
        """

    def getBinaryPackage(name):
        """Return a DistroSeriesBinaryPackage for this name.

        The name given may be an IBinaryPackageName or a string.  The
        binary package may not be published in the distro series.
        """

    def getCurrentSourceReleases(source_package_names):
        """Get the current release of a list of source packages.

        :param source_package_names: a list of `ISourcePackageName`
            instances.

        :return: a dict where the key is a `ISourcePackage`
            and the value is a `IDistributionSourcePackageRelease`.
        """

    def getPublishedSources(sourcepackage_or_name,
                            pocket=None,
                            version=None,
                            include_pending=False,
                            archive=None):
        """Return the SourcePackagePublishingHistory(s)

        Deprecated.  Use IArchive.getPublishedSources instead.

        Given a ISourcePackageName or name.

        If pocket is not specified, we look in all pockets.

        If version is not specified, return packages with any version.

        If 'include_pending' is True, we return also the pending publication
        records, those packages that will get published in the next publisher
        run (it's only useful when we need to know if a given package is
        known during a publisher run, mostly in pre-upload checks)

        If 'archive' is not specified consider publication in the
        main_archive, otherwise respect the given value.
        """

    def getAllPublishedSources():
        """Return all currently published sources for the distroseries.

        Return publications in the main archives only.
        """

    def getAllUncondemnedSources():
        """Return all uncondemned sources for the distroseries.

        An uncondemned publication is one without scheduleddeletiondate set.

        Return publications in the main archives only.
        """

    def getAllPublishedBinaries():
        """Return all currently published binaries for the distroseries.

        Return publications in the main archives only.
        """

    def getAllUncondemnedBinaries():
        """Return all uncondemned binaries for the distroseries.

        An uncondemned publication is one without scheduleddeletiondate set.

        Return publications in the main archives only.
        """

    def getDistroSeriesLanguage(language):
        """Return the DistroSeriesLanguage for this distroseries and the
        given language, or None if there's no DistroSeriesLanguage for this
        distribution and the given language.
        """

    def getDistroSeriesLanguageOrDummy(language):
        """Return the DistroSeriesLanguage for this distroseries and the
        given language, or a DummyDistroSeriesLanguage.
        """

    def createUploadedSourcePackageRelease(sourcepackagename,
                                           version,
                                           maintainer,
                                           builddepends,
                                           builddependsindep,
                                           architecturehintlist,
                                           component,
                                           creator,
                                           urgency,
                                           changelog,
                                           changelog_entry,
                                           dsc,
                                           dscsigningkey,
                                           section,
                                           dsc_maintainer_rfc822,
                                           dsc_standards_version,
                                           dsc_format,
                                           dsc_binaries,
                                           archive,
                                           copyright,
                                           build_conflicts,
                                           build_conflicts_indep,
                                           dateuploaded=None,
                                           source_package_recipe_build=None,
                                           user_defined_fields=None,
                                           homepage=None,
                                           buildinfo=None):
        """Create an uploads `SourcePackageRelease`.

        Set this distroseries set to be the uploadeddistroseries.

        All arguments are mandatory, they are extracted/built when
        processing and uploaded source package:

         :param dateuploaded: timestamp, if not provided will be UTC_NOW
         :param sourcepackagename: `ISourcePackageName`
         :param version: string, a debian valid version
         :param maintainer: IPerson designed as package maintainer
         :param creator: IPerson, package uploader
         :param component: IComponent
         :param section: ISection
         :param urgency: dbschema.SourcePackageUrgency
         :param dscsigningkey: IGPGKey used to sign the DSC file
         :param dsc: string, original content of the dsc file
         :param copyright: string, the original debian/copyright content
         :param changelog: LFA ID of the debian/changelog file in librarian
         :param changelog_entry: string, changelog extracted from the
                                 changesfile
         :param architecturehintlist: string, DSC architectures
         :param builddepends: string, DSC build dependencies
         :param builddependsindep: string, DSC architecture independent build
                                   dependencies.
         :param build_conflicts: string, DSC Build-Conflicts content
         :param build_conflicts_indep: string, DSC Build-Conflicts-Indep
                                       content
         :param dsc_maintainer_rfc822: string, DSC maintainer field
         :param dsc_standards_version: string, DSC standards version field
         :param dsc_format: string, DSC format version field
         :param dsc_binaries:  string, DSC binaries field
         :param archive: IArchive to where the upload was targeted
         :param dateuploaded: optional datetime, if omitted assumed nowUTC
         :param source_package_recipe_build: optional SourcePackageRecipeBuild
         :param user_defined_fields: optional sequence of key-value pairs with
                                     user defined fields.
         :param homepage: optional string with (unchecked) upstream homepage
                          URL
         :param buildinfo: optional LFA with build information file
         :return: the just creates `SourcePackageRelease`
        """

    def getComponentByName(name):
        """Get the named component.

        Raise NotFoundError if the component is not in the permitted component
        list for this distroseries.
        """

    def getSectionByName(name):
        """Get the named section.

        Raise NotFoundError if the section is not in the permitted section
        list for this distroseries.
        """

    def addSection(section):
        """SQLObject provided method to fill a related join key section."""

    def getBinaryPackagePublishing(archtag, pocket, component, archive):
        """Get BinaryPackagePublishings in a DistroSeries.

        Can optionally restrict the results by architecturetag, pocket and/or
        component.

        If archive is passed, restricted the results to the given archive,
        if it is suppressed the results will be restricted to the
        distribution 'main_archive'.
        """

    def getSourcePackagePublishing(pocket, component, archive):
        """Return a selectResult of ISourcePackagePublishingHistory.

        According status and pocket.
        If archive is passed, restricted the results to the given archive,
        if it is suppressed the results will be restricted to the
        distribution 'main_archive'.
        """

    def searchPackages(text):
        """Search through the packge cache for this distroseries and return
        DistroSeriesBinaryPackage objects that match the given text.
        """

    def createQueueEntry(pocket,
                         archive,
                         changesfilename=None,
                         changesfilecontent=None,
                         changes_file_alias=None,
                         signingkey=None,
                         package_copy_job=None):
        """Create a queue item attached to this distroseries.

        Create a new `PackageUpload` to the given pocket and archive.

        The default state is NEW.  Any further state changes go through
        the Queue state-machine.

        :param pocket: The `PackagePublishingPocket` to upload to.
        :param archive: The `Archive` to upload to.  Must be for the same
            `Distribution` as this series.
        :param changesfilename: Name for the upload's .changes file.  You may
            specify a changes file by passing both `changesfilename` and
            `changesfilecontent`, or by passing `changes_file_alias`.
        :param changesfilecontent: Text for the changes file.  It will be
            signed and stored in the Librarian.  Must be passed together with
            `changesfilename`; alternatively, you may provide a
            `changes_file_alias` to replace both of these.
        :param changes_file_alias: A `LibraryFileAlias` containing the
            .changes file.  Security warning: unless the file has already
            been checked, this may open us up to replay attacks as per bugs
            159304 and 451396.  Use `changes_file_alias` only if you know
            this can't happen.
        :param signingkey: `IGPGKey` used to sign the changes file, or None if
            it is unsigned.
        :return: A new `PackageUpload`.
        """

    def newArch(architecturetag, processor, official, owner, enabled=True):
        """Create a new port or DistroArchSeries for this DistroSeries."""

    def getPOFileContributorsByLanguage(language):
        """People who translated strings to the given language.

        The people that translated only IPOTemplate objects that are not
        current will not appear in the returned list.
        """

    def getSuite(pocket):
        """Return the suite for this distro series and the given pocket.

        :param pocket: A `DBItem` of `PackagePublishingPocket`.
        :return: A string.
        """

    def isSourcePackageFormatPermitted(format):
        """Check if the specified source format is allowed in this series.

        :param format: The SourcePackageFormat to check.
        """

    @operation_returns_collection_of(Interface)
    @export_read_operation()
    def getDerivedSeries():
        """Get all `DistroSeries` derived from this one."""

    @operation_returns_collection_of(Interface)
    @export_read_operation()
    def getParentSeries():
        """Get all parent `DistroSeries`."""

    @operation_parameters(
        parent_series=Reference(
            schema=Interface,  # IDistroSeries
            title=_("The parent series to consider."),
            required=False),
        difference_type=Choice(
            vocabulary=DistroSeriesDifferenceType,
            title=_("Only return differences of this type."),
            required=False),
        source_package_name_filter=TextLine(title=_(
            "Only return differences for packages matching this "
            "name."),
                                            required=False),
        status=Choice(vocabulary=DistroSeriesDifferenceStatus,
                      title=_("Only return differences of this status."),
                      required=False),
        child_version_higher=Bool(title=_(
            "Only return differences for which the child's version "
            "is higher than the parent's."),
                                  required=False),
    )
    @operation_returns_collection_of(Interface)
    @export_read_operation()
    @operation_for_version('devel')
    def getDifferencesTo(parent_series, difference_type,
                         source_package_name_filter, status,
                         child_version_higher):
        """Return the differences between this series and the specified
        parent_series (or all the parent series if parent_series is None).

        :param parent_series: The parent series for which the differences
            should be returned. All parents are considered if this is None.
        :param difference_type: The type of the differences to return.
        :param source_package_name_filter: A package name to use as a filter
            for the differences.
        :param status: The status of the differences to return.
        :param child_version_higher: Only return differences for which the
            child's version is higher than the parent's version.
        """

    def isDerivedSeries():
        """Is this series a derived series?

        A derived series has one or more parent series.
        """

    def isInitializing():
        """Is this series initializing?"""

    def isInitialized():
        """Has this series been initialized?"""

    def getInitializationJob():
        """Get the last `IInitializeDistroSeriesJob` for this series.

        :return: `None` if no job is found or an `IInitializeDistroSeriesJob`.
        """

    @operation_parameters(
        since=Datetime(
            title=_("Minimum creation timestamp"),
            description=_("Ignore comments that are older than this."),
            required=False),
        source_package_name=TextLine(
            title=_("Name of source package"),
            description=_("Only return comments for this source package."),
            required=False))
    @operation_returns_collection_of(Interface)
    @export_read_operation()
    @operation_for_version('devel')
    def getDifferenceComments(since=None, source_package_name=None):
        """Get `IDistroSeriesDifferenceComment` items.
Example #18
0
class ISourcePackagePublic(IBugTarget, IHasBranches, IHasMergeProposals,
                           IHasOfficialBugTags, IHasCodeImports,
                           IHasTranslationImports, IHasTranslationTemplates,
                           IHasDrivers, IHasOwner):
    """Public attributes for SourcePackage."""

    name = exported(
        TextLine(title=_("Name"),
                 required=True,
                 readonly=True,
                 description=_("The text name of this source package.")))

    display_name = exported(TextLine(
        title=_("Display name"),
        required=True,
        readonly=True,
        description=_("A displayname, constructed, for this package")),
                            exported_as="displayname")

    displayname = Attribute("Display name (deprecated)")

    path = Attribute("A path to this package, <distro>/<series>/<package>")

    title = Attribute("Title.")

    summary = Attribute(
        'A description of the binary packages built from this package.')

    format = Attribute(
        "Source Package Format. This is the format of the "
        "current source package release for this name in this "
        "distribution or distroseries. Calling this when there is "
        "no current sourcepackagerelease will raise an exception.")

    distinctreleases = Attribute(
        "Return a distinct list "
        "of sourcepackagepublishinghistory for this source package.")

    distribution = exported(
        Reference(
            Interface,
            # Really IDistribution, circular import fixed in
            # _schema_circular_imports.
            title=_("Distribution"),
            required=True,
            readonly=True,
            description=_("The distribution for this source package.")))

    # The interface for this is really IDistroSeries, but importing that would
    # cause circular imports. Set in _schema_circular_imports.
    distroseries = exported(
        Reference(Interface,
                  title=_("Distribution Series"),
                  required=True,
                  readonly=True,
                  description=_("The DistroSeries for this SourcePackage")))

    sourcepackagename = Attribute("SourcePackageName")

    # This is really a reference to an IProductSeries.
    productseries = exported(
        ReferenceChoice(
            title=_("Project series"),
            required=False,
            vocabulary="ProductSeries",
            readonly=True,
            schema=Interface,
            description=_(
                "The registered project series that this source package "
                "is based on. This series may be the same as the one that "
                "earlier versions of this source packages were based on.")))

    releases = Attribute(
        "The full set of source package releases that "
        "have been published in this distroseries under this source "
        "package name. The list should be sorted by version number.")

    currentrelease = Attribute("""The latest published SourcePackageRelease
        of a source package with this name in the distribution or
        distroseries, or None if no source package with that name is
        published in this distroseries.""")

    direct_packaging = Attribute(
        "Return the Packaging record that is "
        "explicitly for this distroseries and source package name, "
        "or None if such a record does not exist. You should probably "
        "use ISourcePackage.packaging, which will also look through the "
        "distribution ancestry to find a relevant packaging record.")

    packaging = Attribute(
        "The best Packaging record we have for this "
        "source package. If we have one for this specific distroseries "
        "and sourcepackagename, it will be returned, otherwise we look "
        "for a match in parent and ubuntu distro seriess.")

    published_by_pocket = Attribute(
        "The set of source package releases "
        "currently published in this distro series, organised by "
        "pocket. The result is a dictionary, with the pocket dbschema "
        "as a key, and a list of {'spr': source package release, "
        "'component_name': component name} as the value.")

    linked_branches = Attribute(
        "A mapping of pockets to officially linked branches, ordered by "
        "pocket enum value.")

    development_version = Attribute(
        "This package on the distro's current series.")

    distribution_sourcepackage = Attribute(
        "The IDistributionSourcePackage for this source package.")

    drivers = Attribute(
        "The drivers for the distroseries for this source package.")

    owner = Attribute("The owner of the distroseries for this source package.")

    def __hash__():
        """Sourcepackage hash method.

        This is required to make source packages usable as dictionary
        keeps since the __eq__ method is provided.
        """

    def __eq__(other):
        """Sourcepackage comparison method.

        Sourcepackages compare equal only if their distroseries and
        sourcepackagename compare equal.
        """

    def __ne__(other):
        """Sourcepackage comparison method.

        Sourcepackages compare not equal if either of their distroseries or
        sourcepackagename compare not equal.
        """

    @operation_parameters(productseries=Reference(schema=IProductSeries))
    @call_with(owner=REQUEST_USER)
    @export_write_operation()
    @operation_for_version('devel')
    def setPackaging(productseries, owner):
        """Update the existing packaging record, or create a new packaging
        record, that links the source package to the given productseries,
        and record that it was done by the owner.
        """

    @operation_parameters(productseries=Reference(schema=IProductSeries))
    @call_with(owner=REQUEST_USER)
    @export_write_operation()
    @operation_for_version('devel')
    def setPackagingReturnSharingDetailPermissions(productseries, owner):
        """Like setPackaging(), but returns getSharingDetailPermissions().

        This method is intended for AJAX usage on the +sharing-details
        page.
        """

    @export_write_operation()
    @operation_for_version('devel')
    def deletePackaging():
        """Delete the packaging for this sourcepackage."""

    def getSharingDetailPermissions():
        """Return a dictionary of user permissions for +sharing-details page.

        This shows whether the user can change
        - The project series
        - The project series target branch
        - The project series autoimport mode
        - The project translation usage setting
        """

    def getSuiteSourcePackage(pocket):
        """Return the `ISuiteSourcePackage` for this package in 'pocket'.

        :param pocket: A `DBItem` of `PackagePublishingPocket`.
        :return: An `ISuiteSourcePackage`.
        """

    def getPocketPath(pocket):
        """Get the path to the given pocket of this package.

        :param pocket: A `DBItem` of `PackagePublishingPocket`.
        :return: A string.
        """

    @operation_parameters(pocket=Choice(title=_("Pocket"),
                                        required=True,
                                        vocabulary=PackagePublishingPocket))
    # Actually returns an IBranch, but we say Interface here to avoid circular
    # imports. Correct interface specified in _schema_circular_imports.
    @operation_returns_entry(Interface)
    @export_read_operation()
    def getBranch(pocket):
        """Get the official branch for this package in the given pocket.

        :param pocket: A `PackagePublishingPocket`.
        :return: An `IBranch`.
        """

    latest_published_component = Object(
        title=u'The component in which the package was last published.',
        schema=IComponent,
        readonly=True,
        required=False)

    latest_published_component_name = exported(
        TextLine(title=u'The name of the component in which the package'
                 ' was last published.',
                 readonly=True,
                 required=False))

    def get_default_archive(component=None):
        """Get the default archive of this package.

        If 'component' is a partner component, then the default archive is the
        partner archive. Otherwise, the primary archive of the associated
        distribution.

        :param component: The `IComponent` to base the default archive
            decision on. If None, defaults to the last published component.
        :raise NoPartnerArchive: If returning the partner archive is
            appropriate, but no partner archive exists.
        :return: `IArchive`.
        """

    def getLatestTranslationsUploads():
        """Find latest Translations tarballs as produced by Soyuz.

        :return: A list of `ILibraryFileAlias`es, usually of size zero
            or one.  If not, they are sorted from oldest to newest.
        """

    @export_read_operation()
    def linkedBranches():
        """Get the official branches for this package.
Example #19
0
class IProjectGroupPublic(ICanGetMilestonesDirectly, IHasAppointedDriver,
                          IHasBranches, IHasBugs, IHasDrivers, IHasIcon,
                          IHasLogo, IHasMergeProposals, IHasMilestones,
                          IHasMugshot, IHasOwner, IHasSpecifications,
                          IHasSprints, IMakesAnnouncements, IKarmaContext,
                          IHasOfficialBugTags, IServiceUsage):
    """Public IProjectGroup properties."""

    id = Int(title=_('ID'), readonly=True)

    # The following milestone collections are copied from IHasMilestone so that
    # we can override the collection value types to be IProjectGroupMilestone.
    milestones = copy_field(
        IHasMilestones['milestones'],
        value_type=Reference(schema=IProjectGroupMilestone))

    all_milestones = copy_field(
        IHasMilestones['all_milestones'],
        value_type=Reference(schema=IProjectGroupMilestone))

    owner = exported(
        PublicPersonChoice(
            title=_('Maintainer'),
            required=True,
            vocabulary='ValidPillarOwner',
            description=_("The restricted team, moderated team, or person "
                          "who maintains the project group information in "
                          "Launchpad.")))

    registrant = exported(
        PublicPersonChoice(title=_('Registrant'),
                           required=True,
                           readonly=True,
                           vocabulary='ValidPersonOrTeam',
                           description=_(
                               "Project group registrant. Must be a valid "
                               "Launchpad Person.")))

    display_name = exported(
        TextLine(title=_('Display Name'),
                 description=_(
                     "Appropriately capitalised, "
                     'and typically ending in "Project". '
                     "Examples: the Apache Project, the Mozilla Project, "
                     "the Gimp Project.")))

    displayname = Attribute('Display name (deprecated)')

    title = exported(
        Title(title=_('Title'),
              description=_("The full name of the project group, "
                            "which can contain spaces, special characters, "
                            "etc.")))

    summary = exported(
        Summary(
            title=_('Project Group Summary'),
            description=_(
                "A short paragraph to introduce the project group's work.")))

    description = exported(
        Text(title=_('Description'),
             description=_(
                 "Details about the project group's work, goals, and "
                 "how to contribute. Use plain text, paragraphs are preserved "
                 "and URLs are linked in pages. Don't repeat the Summary.")))

    datecreated = exported(Datetime(
        title=_('Date Created'),
        description=_("The date this project group was created in Launchpad."),
        readonly=True),
                           exported_as="date_created")

    driver = exported(
        PublicPersonChoice(
            title=_("Driver"),
            description=_(
                "This is a project group-wide appointment. Think carefully "
                "here! This person or team will be able to set feature goals "
                "and approve bug targeting and backporting for ANY series in "
                "ANY project in this group. You can also appoint drivers "
                "at the level of a specific project or series. So you may "
                "just want to leave this space blank, and instead let the "
                "individual projects and series have drivers."),
            required=False,
            vocabulary='ValidPersonOrTeam'))

    homepageurl = exported(URIField(title=_('Homepage URL'),
                                    required=False,
                                    allowed_schemes=['http', 'https', 'ftp'],
                                    allow_userinfo=False,
                                    description=_(
                                        "The project group home page. "
                                        "Please include the http://")),
                           exported_as="homepage_url")

    wikiurl = exported(URIField(
        title=_('Wiki URL'),
        required=False,
        allowed_schemes=['http', 'https', 'ftp'],
        allow_userinfo=False,
        description=_("The URL of this project group's wiki, "
                      "if it has one. Please include the http://")),
                       exported_as="wiki_url")

    lastdoap = TextLine(title=_('Last-parsed RDF fragment'),
                        description=_("The last RDF fragment for this "
                                      "entity that we received and parsed, or "
                                      "generated."),
                        required=False)

    sourceforgeproject = exported(TextLine(
        title=_("SourceForge Project Name"),
        description=_("The SourceForge project name for this "
                      "project group, if it is in SourceForge."),
        required=False),
                                  exported_as="sourceforge_project")

    freshmeatproject = exported(TextLine(
        title=_("Freshmeat Project Name"),
        description=_("The Freshmeat project name for this "
                      "project group, if it is in Freshmeat. "
                      "[DEPRECATED]"),
        required=False),
                                exported_as="freshmeat_project")

    homepage_content = exported(
        Text(title=_("Homepage Content"),
             required=False,
             description=_(
                 "The content of this project group's home page. Edit this "
                 "and it will be displayed for all the world to see. It is "
                 "NOT a wiki so you cannot undo changes.")))

    icon = exported(
        IconImageUpload(
            title=_("Icon"),
            required=False,
            default_image_resource='/@@/project',
            description=_(
                "A small image of exactly 14x14 pixels and at most 5kb in "
                "size, that can be used to identify this project group. The "
                "icon will be displayed in Launchpad everywhere that we link "
                "to this project group. For example in listings or tables of "
                "active project groups.")))

    logo = exported(
        LogoImageUpload(
            title=_("Logo"),
            required=False,
            default_image_resource='/@@/project-logo',
            description=_(
                "An image of exactly 64x64 pixels that will be displayed in "
                "the heading of all pages related to this project group. It "
                "should be no bigger than 50kb in size.")))

    mugshot = exported(
        MugshotImageUpload(
            title=_("Brand"),
            required=False,
            default_image_resource='/@@/project-mugshot',
            description=_(
                "A large image of exactly 192x192 pixels, that will be "
                "displayed on this project group's home page in Launchpad. "
                "It should be no bigger than 100kb in size. ")))

    bugtracker = exported(ReferenceChoice(
        title=_('Bug Tracker'),
        required=False,
        vocabulary='BugTracker',
        schema=IBugTracker,
        description=_(
            "The bug tracker the projects in this project group use.")),
                          exported_as="bug_tracker")

    # products.value_type will be set to IProduct once IProduct is defined.
    products = exported(CollectionField(
        title=_('List of active projects for this project group.'),
        value_type=Reference(Interface)),
                        exported_as="projects")

    bug_reporting_guidelines = exported(
        Text(title=(u"If I\N{right single quotation mark}m reporting a bug, "
                    u"I should include, if possible"),
             description=(u"These guidelines will be shown to "
                          "anyone reporting a bug."),
             required=False,
             max_length=50000))

    bug_reported_acknowledgement = exported(
        Text(title=(u"After reporting a bug, I can expect the following."),
             description=(u"This message of acknowledgement will be displayed "
                          "to anyone after reporting a bug."),
             required=False,
             max_length=50000))

    enable_bugfiling_duplicate_search = Bool(
        title=u"Search for possible duplicate bugs when a new bug is filed",
        required=False,
        readonly=True)

    translatables = Attribute("Products that are translatable in LP")

    def getProduct(name):
        """Get a product with name `name`."""

    def getConfigurableProducts():
        """Get all products that can be edited by user."""

    def has_translatable():
        """Return a boolean showing the existance of translatables products.
        """

    def has_branches():
        """Return a boolean showing the existance of products with branches.
        """

    def hasProducts():
        """Returns True if a project has products associated with it, False
        otherwise.
        """

    def getSeries(series_name):
        """Return a ProjectGroupSeries object with name `series_name`."""

    product_milestones = Attribute('all the milestones for all the products.')
Example #20
0
class ITranslationPolicy(Interface):
    """Permissions and sharing policy for translatable pillars.

    A translation policy defines who can edit translations, and who can
    add suggestions.  (The ability to edit also implies the ability to
    enter suggestions).  Everyone else is allowed only to view the
    translations.

    The policy can "invite" the user to edit or suggest; or it can
    merely "allow" them to.  Whoever is invited is also allowed, but
    administrators and certain other special users may be allowed
    without actually being invited.

    The invitation is based purely on the access model configured by the
    user: translation team and translation policy.
    """

    translationgroup = exported(ReferenceChoice(
        title=_("Translation group"),
        description=_(
            "The translation group that helps review "
            " translations for this project or distribution. The group's "
            " role depends on the permissions policy selected below."),
        required=False,
        vocabulary='TranslationGroup',
        schema=ITranslationGroup),
                                as_of="devel")

    translationpermission = exported(Choice(
        title=_("Translation permissions policy"),
        description=_("The policy this project or distribution uses to "
                      " balance openness and control for their translations."),
        required=True,
        vocabulary=TranslationPermission),
                                     as_of="devel")

    def getTranslationGroups():
        """List all applicable translation groups.

        This may be an empty list, or a list containing just this
        policy's translation group, or for a product that is part of a
        project group, possibly a list of two translation groups.

        If there is an inherited policy, its translation group comes
        first.  Duplicates are removed.
        """

    def getTranslators(language, store=None):
        """Find the applicable `TranslationGroup`(s) and translators.

        Zero, one, or two translation groups may apply.  Each may have a
        `Translator` for the language, with either a person or a team
        assigned.

        In the case of a product in a project group, there may be up to
        two entries.  In that case, the entry from the project group
        comes first.

        :param language: The language that you want the translators for.
        :type language: ILanguage
        :param store: Optionally a specific store to retrieve from.
        :type store: Store
        :return: A result set of zero or more tuples:
            (`TranslationGroup`, `Translator`, `Person`).  The
            translation group is always present and unique.  The person
            is present if and only if the translator is present.  The
            translator is unique if present, but the person need not be.
        """

    def getEffectiveTranslationPermission():
        """Get the effective `TranslationPermission`.

        Returns the strictest applicable permission out of
        `self.translationpermission` and any inherited
        `TranslationPermission`.
        """

    def invitesTranslationEdits(person, language):
        """Does this policy invite `person` to edit translations?

        The decision is based on the chosen `TranslationPermission`,
        `TranslationGroup`(s), the presence of a translation team, and
        `person`s membership of the translation team.

        As one extreme, the OPEN model invites editing by anyone.  The
        opposite extreme is CLOSED, which invites editing only by
        members of the applicable translation team.

        :param person: The user.
        :type person: IPerson
        :param language: The language to translate to.  This will be
            used to look up the applicable translation team(s).
        :type language: ILanguage
        """

    def invitesTranslationSuggestions(person, language):
        """Does this policy invite `person` to enter suggestions?

        Similar to `invitesTranslationEdits`, but for the activity of
        entering suggestions.  This carries less risk, so generally a
        wider public is invited to do this than to edit.
        """

    def allowsTranslationEdits(person, language):
        """Is `person` allowed to edit translations to `language`?

        Similar to `invitesTranslationEdits`, except administrators and
        in the case of Product translations, owners of the product are
        always allowed even if they are not invited.
        """

    def allowsTranslationSuggestions(person, language):
        """Is `person` allowed to enter suggestions for `language`?

        Similar to `invitesTranslationSuggestions, except administrators
        and in the case of Product translations, owners of the product
        are always allowed even if they are not invited.
        """

    def sharesTranslationsWithOtherSide(person,
                                        language,
                                        sourcepackage=None,
                                        purportedly_upstream=False):
        """Should translations be shared across `TranslationSide`s?
Example #21
0
class IBugTask(IHasDateCreated, IHasBug, IBugTaskDelete):
    """A bug needing fixing in a particular product or package."""
    export_as_webservice_entry()

    id = Int(title=_("Bug Task #"))
    bug = exported(
        BugField(title=_("Bug"), readonly=True))
    product = Choice(
        title=_('Project'), required=False, vocabulary='Product')
    productID = Attribute('The product ID')
    productseries = Choice(
        title=_('Series'), required=False, vocabulary='ProductSeries')
    productseriesID = Attribute('The product series ID')
    sourcepackagename = Choice(
        title=_("Package"), required=False,
        vocabulary='SourcePackageName')
    sourcepackagenameID = Attribute('The sourcepackagename ID')
    distribution = Choice(
        title=_("Distribution"), required=False, vocabulary='Distribution')
    distributionID = Attribute('The distribution ID')
    distroseries = Choice(
        title=_("Series"), required=False,
        vocabulary='DistroSeries')
    distroseriesID = Attribute('The distroseries ID')
    milestone = exported(ReferenceChoice(
        title=_('Milestone'),
        required=False,
        readonly=True,
        vocabulary='BugTaskMilestone',
        schema=Interface))  # IMilestone
    milestoneID = Attribute('The id of the milestone.')

    # The status and importance's vocabularies do not
    # contain an UNKNOWN item in bugtasks that aren't linked to a remote
    # bugwatch; this would be better described in a separate interface,
    # but adding a marker interface during initialization is expensive,
    # and adding it post-initialization is not trivial.
    # Note that status is a property because the model only exposes INCOMPLETE
    # but the DB stores INCOMPLETE_WITH_RESPONSE and
    # INCOMPLETE_WITHOUT_RESPONSE for query efficiency.
    status = exported(
        Choice(title=_('Status'), vocabulary=BugTaskStatus,
               default=BugTaskStatus.NEW, readonly=True))
    _status = Attribute('The actual status DB column used in queries.')
    importance = exported(
        Choice(title=_('Importance'), vocabulary=BugTaskImportance,
               default=BugTaskImportance.UNDECIDED, readonly=True))
    assignee = exported(
        PersonChoice(
            title=_('Assigned to'), required=False,
            vocabulary='ValidAssignee',
            readonly=True))
    assigneeID = Int(title=_('The assignee ID (for eager loading)'))
    bugtargetdisplayname = exported(
        Text(title=_("The short, descriptive name of the target"),
             readonly=True),
        exported_as='bug_target_display_name')
    bugtargetname = exported(
        Text(title=_("The target as presented in mail notifications"),
             readonly=True),
        exported_as='bug_target_name')
    bugwatch = exported(
        ReferenceChoice(
            title=_("Remote Bug Details"), required=False,
            schema=IBugWatch,
            vocabulary='BugWatch', description=_(
                "Select the bug watch that "
                "represents this task in the relevant bug tracker. If none "
                "of the bug watches represents this particular bug task, "
                "leave it as (None). Linking the remote bug watch with the "
                "task in this way means that a change in the remote bug "
                "status will change the status of this bug task in "
                "Launchpad.")),
        exported_as='bug_watch')
    date_assigned = exported(
        Datetime(title=_("Date Assigned"),
                 description=_("The date on which this task was assigned "
                               "to someone."),
                 readonly=True,
                 required=False))
    datecreated = exported(
        Datetime(title=_("Date Created"),
                 description=_("The date on which this task was created."),
                 readonly=True),
        exported_as='date_created')
    date_confirmed = exported(
        Datetime(title=_("Date Confirmed"),
                 description=_("The date on which this task was marked "
                               "Confirmed."),
                 readonly=True,
                 required=False))
    date_incomplete = exported(
        Datetime(title=_("Date Incomplete"),
                 description=_("The date on which this task was marked "
                               "Incomplete."),
                 readonly=True,
                 required=False))
    date_inprogress = exported(
        Datetime(title=_("Date In Progress"),
                 description=_("The date on which this task was marked "
                               "In Progress."),
                 readonly=True,
                 required=False),
        exported_as='date_in_progress')
    date_closed = exported(
        Datetime(title=_("Date Closed"),
                 description=_("The date on which this task was marked "
                               "either Won't Fix, Invalid or Fix Released."),
                 readonly=True,
                 required=False))
    date_left_new = exported(
        Datetime(title=_("Date left new"),
                 description=_("The date on which this task was marked "
                               "with a status higher than New."),
                 readonly=True,
                 required=False))
    date_triaged = exported(
        Datetime(title=_("Date Triaged"),
                 description=_("The date on which this task was marked "
                               "Triaged."),
                 readonly=True,
                 required=False))
    date_fix_committed = exported(
        Datetime(title=_("Date Fix Committed"),
                 description=_("The date on which this task was marked "
                               "Fix Committed."),
                 readonly=True,
                 required=False))
    date_fix_released = exported(
        Datetime(title=_("Date Fix Released"),
                 description=_("The date on which this task was marked "
                               "Fix Released."),
                 readonly=True,
                 required=False))
    date_left_closed = exported(
        Datetime(title=_("Date left closed"),
                 description=_("The date on which this task was "
                               "last reopened."),
                 readonly=True,
                 required=False))
    age = Datetime(title=_("Age"),
                   description=_("The age of this task, expressed as the "
                                 "length of time between the creation date "
                                 "and now."))
    task_age = Int(title=_("Age of the bug task"),
            description=_("The age of this task in seconds, a delta between "
                         "now and the date the bug task was created."))
    owner = exported(
        Reference(title=_("The owner"), schema=Interface, readonly=True))
    target = exported(Reference(
        title=_('Target'), required=True, schema=Interface,  # IBugTarget
        readonly=True,
        description=_("The software in which this bug should be fixed.")))
    title = exported(
        Text(title=_("The title of the bug related to this bugtask"),
             readonly=True))
    related_tasks = exported(
        CollectionField(
            description=_(
                "IBugTasks related to this one, namely other "
                "IBugTasks on the same IBug."),
            value_type=Reference(schema=Interface),  # Will be specified later
            readonly=True))
    pillar = Choice(
        title=_('Pillar'),
        description=_("The LP pillar (product or distribution) "
                      "associated with this task."),
        vocabulary='DistributionOrProduct', readonly=True)
    other_affected_pillars = Attribute(
        "The other pillars (products or distributions) affected by this bug. "
        "This returns a list of pillars OTHER THAN the pillar associated "
        "with this particular bug.")
    # This property does various database queries. It is a property so a
    # "snapshot" of its value will be taken when a bugtask is modified, which
    # allows us to compare it to the current value and see if there are any
    # new subscribers that should get an email containing full bug details
    # (rather than just the standard change mail.) It is a property on
    # IBugTask because we currently only ever need this value for events
    # handled on IBugTask.
    bug_subscribers = Field(
        title=_("A list of IPersons subscribed to the bug, whether directly "
                "or indirectly."), readonly=True)

    conjoined_master = Attribute(
        "The series-specific bugtask in a conjoined relationship")
    conjoined_slave = Attribute(
        "The generic bugtask in a conjoined relationship")

    is_complete = exported(
        Bool(description=_(
                "True or False depending on whether or not there is more "
                "work required on this bug task."),
             readonly=True))

    @operation_returns_collection_of(Interface)  # Actually IBug.
    @call_with(user=REQUEST_USER, limit=10)
    @export_read_operation()
    def findSimilarBugs(user, limit=10):
        """Return the list of possible duplicates for this BugTask."""

    @call_with(user=REQUEST_USER)
    @operation_parameters(person=copy_field(assignee))
    @export_read_operation()
    @operation_for_version("devel")
    def getContributorInfo(user, person):
        """Is the person a contributor to bugs in this task's pillar?

        :param user: The user doing the search. Private bugs that this
            user doesn't have access to won't be included in the search.
        :param person: The person to check to see if they are a contributor.

        Return a dict with the following values:
        is_contributor: True if the user has any bugs assigned to him in the
        context of this bug task's pillar, either directly or by team
        participation.
        person_name: the displayname of the person
        pillar_name: the displayname of the bug task's pillar

        This API call is provided for use by the client Javascript where the
        calling context does not have access to the person or pillar names.
        """

    def getConjoinedMaster(bugtasks, bugtasks_by_package=None):
        """Return the conjoined master in the given bugtasks, if any.

        :param bugtasks: The bugtasks to be considered when looking for
            the conjoined master.
        :param bugtasks_by_package: A cache, mapping a
            `ISourcePackageName` to a list of bug tasks targeted to such
            a package name. Both distribution and distro series tasks
            should be included in this list.

        This method exists mainly to allow calculating the conjoined
        master from a cached list of bug tasks, reducing the number of
        db queries needed.
        """

    def subscribe(person, subscribed_by):
        """Subscribe this person to the underlying bug.

        This method was documented as being required here so that
        MentorshipOffers could happen on IBugTask. If that was the sole reason
        this method should be deletable. When we move to context-less bug
        presentation (where the bug is at /bugs/n?task=ubuntu) then we can
        eliminate this if it is no longer useful.
        """

    def isSubscribed(person):
        """Return True if the person is an explicit subscriber to the
        underlying bug for this bugtask.

        This method was documented as being required here so that
        MentorshipOffers could happen on IBugTask. If that was the sole
        reason then this method should be deletable.  When we move to
        context-less bug presentation (where the bug is at
        /bugs/n?task=ubuntu) then we can eliminate this if it is no
        longer useful.
        """

    @mutator_for(milestone)
    @rename_parameters_as(new_milestone='milestone')
    @operation_parameters(new_milestone=copy_field(milestone))
    @call_with(user=REQUEST_USER)
    @export_write_operation()
    def transitionToMilestone(new_milestone, user):
        """Set the BugTask milestone.

        Set the bugtask milestone, making sure that the user is
        authorised to do so.
        """

    @mutator_for(importance)
    @rename_parameters_as(new_importance='importance')
    @operation_parameters(new_importance=copy_field(importance))
    @call_with(user=REQUEST_USER)
    @export_write_operation()
    def transitionToImportance(new_importance, user):
        """Set the BugTask importance.

        Set the bugtask importance, making sure that the user is
        authorised to do so.
        """

    def canTransitionToStatus(new_status, user):
        """Return True if the user is allowed to change the status to
        `new_status`.

        :new_status: new status from `BugTaskStatus`
        :user: the user requesting the change

        Some status transitions, e.g. Triaged, require that the user
        be a bug supervisor or the owner of the project.
        """

    @mutator_for(status)
    @rename_parameters_as(new_status='status')
    @operation_parameters(
        new_status=copy_field(status))
    @call_with(user=REQUEST_USER)
    @export_write_operation()
    def transitionToStatus(new_status, user):
        """Perform a workflow transition to the new_status.

        :new_status: new status from `BugTaskStatus`
        :user: the user requesting the change

        For certain statuses, e.g. Confirmed, other actions will
        happen, like recording the date when the task enters this
        status.

        Some status transitions require extra conditions to be met.
        See `canTransitionToStatus` for more details.
        """

    def userCanSetAnyAssignee(user):
        """Check if the current user can set anybody sa a bugtask assignee.

        Owners, drivers, bug supervisors and Launchpad admins can always
        assign to someone else.  Other users can assign to someone else if a
        bug supervisor is not defined.
        """

    def userCanUnassign(user):
        """Check if the current user can set assignee to None."""

    @mutator_for(assignee)
    @operation_parameters(assignee=copy_field(assignee))
    @export_write_operation()
    def transitionToAssignee(assignee, validate=True):
        """Perform a workflow transition to the given assignee.

        When the bugtask assignee is changed from None to an IPerson
        object, the date_assigned is set on the task. If the assignee
        value is set to None, date_assigned is also set to None.
        """

    def validateTransitionToTarget(target):
        """Check whether a transition to this target is legal.

        :raises IllegalTarget: if the new target is not allowed.
        """

    @mutator_for(target)
    @call_with(user=REQUEST_USER)
    @operation_parameters(
        target=copy_field(target))
    @export_write_operation()
    def transitionToTarget(target, user):
        """Convert the bug task to a different bug target."""

    def updateTargetNameCache():
        """Update the targetnamecache field in the database.

        This method is meant to be called when an IBugTask is created or
        modified and will also be called from the update_stats.py cron script
        to ensure that the targetnamecache is properly updated when, for
        example, an IDistribution is renamed.
        """

    def asEmailHeaderValue():
        """Return a value suitable for an email header value for this bugtask.

        The return value is a single line of arbitrary length, so header
        folding should be done by the callsite, as needed.

        For an upstream task, this value might look like:

          product=firefox; status=New; importance=Critical; assignee=None;

        See doc/bugmail-headers.txt for a complete explanation and more
        examples.
        """

    def getDelta(old_task):
        """Compute the delta from old_task to this task.

        Returns an IBugTaskDelta or None if there were no changes between
        old_task and this task.
        """

    def getPackageComponent():
        """Return the task's package's component or None.

        Returns the component associated to the current published
        package in that distribution's current series. If the task is
        not a package task, returns None.
        """

    def userHasDriverPrivileges(user):
        """Does the user have driver privileges on the current bugtask?

        :return: A boolean.
        """

    def userHasBugSupervisorPrivileges(user):
        """Is the user privileged and allowed to change details on a bug?
Example #22
0
class ICodeImport(Interface):
    """A code import to a Bazaar Branch."""

    export_as_webservice_entry()

    id = Int(readonly=True, required=True)
    date_created = Datetime(title=_("Date Created"),
                            required=True,
                            readonly=True)

    branch = exported(
        ReferenceChoice(title=_('Branch'),
                        required=True,
                        readonly=True,
                        vocabulary='Branch',
                        schema=IBranch,
                        description=_("The Bazaar branch produced by the "
                                      "import system.")))

    registrant = PublicPersonChoice(
        title=_('Registrant'),
        required=True,
        readonly=True,
        vocabulary='ValidPersonOrTeam',
        description=_("The person who initially requested this import."))

    review_status = exported(
        Choice(title=_("Review Status"),
               vocabulary=CodeImportReviewStatus,
               default=CodeImportReviewStatus.REVIEWED,
               readonly=True,
               description=_("Only reviewed imports are processed.")))

    rcs_type = exported(
        Choice(title=_("Type of RCS"),
               readonly=True,
               required=True,
               vocabulary=RevisionControlSystems,
               description=_("The version control system to import from. "
                             "Can be CVS or Subversion.")))

    url = exported(
        URIField(
            title=_("URL"),
            required=False,
            readonly=True,
            description=_("The URL of the VCS branch."),
            allowed_schemes=["http", "https", "svn", "git", "bzr", "ftp"],
            allow_userinfo=True,
            allow_port=True,
            allow_query=False,  # Query makes no sense in Subversion.
            allow_fragment=False,  # Fragment makes no sense in Subversion.
            trailing_slash=False))  # See http://launchpad.net/bugs/56357.

    cvs_root = exported(
        TextLine(
            title=_("Repository"),
            required=False,
            readonly=True,
            constraint=validate_cvs_root,
            description=_(
                "The CVSROOT. "
                "Example: :pserver:[email protected]:/cvs/gnome")))

    cvs_module = exported(
        TextLine(title=_("Module"),
                 required=False,
                 readonly=True,
                 constraint=validate_cvs_module,
                 description=_("The path to import within the repository."
                               " Usually, it is the name of the project.")))

    date_last_successful = exported(
        Datetime(title=_("Last successful"), required=False, readonly=True))

    update_interval = Timedelta(
        title=_("Update interval"),
        required=False,
        description=
        _("The user-specified time between automatic updates of this import. "
          "If this is unspecified, the effective update interval is a default "
          "value selected by Launchpad administrators."))

    effective_update_interval = Timedelta(
        title=_("Effective update interval"),
        required=True,
        readonly=True,
        description=_(
            "The effective time between automatic updates of this import. "
            "If the user did not specify an update interval, this is a default "
            "value selected by Launchpad administrators."))

    def getImportDetailsForDisplay():
        """Get a one-line summary of the location this import is from."""

    import_job = Choice(
        title=_("Current job"),
        readonly=True,
        vocabulary='CodeImportJob',
        description=_(
            "The current job for this import, either pending or running."))

    results = Attribute("The results for this code import.")

    consecutive_failure_count = Attribute(
        "How many times in a row this import has failed.")

    def updateFromData(data, user):
        """Modify attributes of the `CodeImport`.

        Creates and returns a MODIFY `CodeImportEvent` if changes were made.

        This method preserves the invariant that a `CodeImportJob` exists for
        a given import if and only if its review_status is REVIEWED, creating
        and deleting jobs as necessary.

        :param data: dictionary whose keys are attribute names and values are
            attribute values.
        :param user: user who made the change, to record in the
            `CodeImportEvent`.  May be ``None``.
        :return: The MODIFY `CodeImportEvent`, if any changes were made, or
            None if no changes were made.
        """

    def tryFailingImportAgain(user):
        """Try a failing import again.

        This method sets the review_status back to REVIEWED and requests the
        import be attempted as soon as possible.

        The import must be in the FAILING state.

        :param user: the user who is requesting the import be tried again.
        """

    @call_with(requester=REQUEST_USER)
    @export_write_operation()
    def requestImport(requester, error_if_already_requested=False):
        """Request that an import be tried soon.
Example #23
0
class IProductLimitedView(IHasIcon, IHasLogo, IHasOwner, ILaunchpadUsage):
    """Attributes that must be visible for person with artifact grants
    on bugs, branches or specifications for the product.
    """

    display_name = exported(
        TextLine(
            title=_('Display Name'),
            description=_("""The name of the project as it would appear in a
                paragraph.""")),
        exported_as='display_name')

    displayname = Attribute('Display name (deprecated)')

    icon = exported(
        IconImageUpload(
            title=_("Icon"), required=False,
            default_image_resource='/@@/product',
            description=_(
                "A small image of exactly 14x14 pixels and at most 5kb in "
                "size, that can be used to identify this project. The icon "
                "will be displayed next to the project name everywhere in "
                "Launchpad that we refer to the project and link to it.")))

    logo = exported(
        LogoImageUpload(
            title=_("Logo"), required=False,
            default_image_resource='/@@/product-logo',
            description=_(
                "An image of exactly 64x64 pixels that will be displayed in "
                "the heading of all pages related to this project. It should "
                "be no bigger than 50kb in size.")))

    name = exported(
        ProductNameField(
            title=_('Name'),
            constraint=name_validator,
            description=_(
                "At least one lowercase letter or number, followed by "
                "letters, numbers, dots, hyphens or pluses. "
                "Keep this name short; it is used in URLs as shown above.")))

    owner = exported(
        PersonChoice(
            title=_('Maintainer'),
            required=True,
            vocabulary='ValidPillarOwner',
            description=_("The restricted team, moderated team, or person "
                          "who maintains the project information in "
                          "Launchpad.")))
    projectgroup = exported(
        ReferenceChoice(
            title=_('Part of'),
            required=False,
            vocabulary='ProjectGroup',
            schema=IProjectGroup,
            description=_(
                'Project group. This is an overarching initiative that '
                'includes several related projects. For example, the Mozilla '
                'Project produces Firefox, Thunderbird and Gecko. This '
                'information is used to group those projects in a coherent '
                'way. If you make this project part of a group, the group '
                'preferences and decisions around bug tracking, translation '
                'and security policy will apply to this project.')),
        exported_as='project_group')

    title = exported(
        Title(
            title=_('Title'),
            description=_("The project title. Should be just a few words."),
            readonly=True))
Example #24
0
class IQuestion(IHasOwner):
    """A single question, often a support request."""

    export_as_webservice_entry(as_of='beta')

    id = exported(Int(title=_('Question Number'),
                      required=True,
                      readonly=True,
                      description=_("The tracking number for this question.")),
                  as_of="devel")
    title = exported(TextLine(
        title=_('Summary'),
        required=True,
        description=_("A one-line summary of the issue or problem.")),
                     as_of="devel")
    description = exported(Text(
        title=_('Description'),
        required=True,
        description=_(
            "Include as much detail as possible: what "
            u"you\N{right single quotation mark}re trying to achieve, what steps "
            "you take, what happens, and what you think should happen instead."
        )),
                           as_of="devel")
    status = exported(Choice(title=_('Status'),
                             vocabulary=QuestionStatus,
                             default=QuestionStatus.OPEN,
                             readonly=True),
                      as_of="devel")
    priority = Choice(title=_('Priority'),
                      vocabulary=QuestionPriority,
                      default=QuestionPriority.NORMAL)
    # XXX flacoste 2006-10-28: It should be more precise to define a new
    # vocabulary that excludes the English variants.
    language = exported(ReferenceChoice(
        title=_('Language'),
        vocabulary='Language',
        schema=ILanguage,
        description=_('The language in which this question is written.')),
                        as_of="devel")
    owner = exported(PublicPersonChoice(title=_('Owner'),
                                        required=True,
                                        readonly=True,
                                        vocabulary='ValidPersonOrTeam'),
                     as_of="devel")
    assignee = exported(PublicPersonChoice(
        title=_('Assignee'),
        required=False,
        description=_("The person responsible for helping to resolve the "
                      "question."),
        vocabulary='ValidPersonOrTeam'),
                        as_of="devel")
    answerer = exported(PublicPersonChoice(
        title=_('Answered By'),
        required=False,
        description=_("The person who last provided a response intended to "
                      "resolve the question."),
        vocabulary='ValidPersonOrTeam'),
                        as_of="devel",
                        readonly=True)
    answer = exported(Reference(
        title=_('Answer'),
        required=False,
        description=_(
            "The IQuestionMessage that contains the answer "
            "confirmed by the owner as providing a solution to their "
            "problem."),
        schema=IQuestionMessage),
                      readonly=True,
                      as_of="devel")
    datecreated = exported(Datetime(title=_('Date Created'),
                                    required=True,
                                    readonly=True),
                           exported_as='date_created',
                           readonly=True,
                           as_of="devel")
    datedue = exported(Datetime(
        title=_('Date Due'),
        required=False,
        default=None,
        description=_(
            "The date by which we should have resolved this question.")),
                       exported_as='date_due',
                       readonly=True,
                       as_of="devel")
    datelastquery = exported(Datetime(
        title=_("Date Last Queried"),
        required=True,
        description=_("The date on which we last heard from the "
                      "customer (owner).")),
                             exported_as='date_last_query',
                             readonly=True,
                             as_of="devel")
    datelastresponse = exported(Datetime(
        title=_("Date last Responded"),
        required=False,
        description=_(
            "The date on which we last communicated "
            "with the customer. The combination of datelastquery and "
            "datelastresponse tells us in whose court the ball is.")),
                                exported_as='date_last_response',
                                readonly=True,
                                as_of="devel")
    date_solved = exported(Datetime(
        title=_("Date Answered"),
        required=False,
        description=_(
            "The date on which the question owner confirmed that the "
            "question is Solved.")),
                           exported_as='date_solved',
                           readonly=True,
                           as_of="devel")
    product = Choice(title=_('Upstream Project'),
                     required=False,
                     vocabulary='Product',
                     description=_(
                         'Select the upstream project with which you need '
                         'support.'))
    distribution = Choice(title=_('Distribution'),
                          required=False,
                          vocabulary='Distribution',
                          description=_(
                              'Select '
                              'the distribution for which you need support.'))
    sourcepackagename = Choice(
        title=_('Source Package'),
        required=False,
        vocabulary='SourcePackageName',
        description=_(
            'The source package '
            'in the distribution which contains the software with which you '
            'are experiencing difficulties.'))
    whiteboard = Text(
        title=_('Status Whiteboard'),
        required=False,
        description=_('Up-to-date notes on the status of the question.'))
    # other attributes
    target = exported(Reference(
        title=_('This question is about'),
        required=True,
        schema=IQuestionTarget,
        description=_('The distribution, source package, or project the '
                      'question pertains to.')),
                      as_of="devel")
    faq = Object(title=_('Linked FAQ'),
                 description=_(
                     'The FAQ document containing the long answer to this '
                     'question.'),
                 readonly=True,
                 required=False,
                 schema=IFAQ)

    # joins
    subscriptions = Attribute('The set of subscriptions to this question.')
    reopenings = Attribute("Records of times when this question was reopened.")
    messages = exported(CollectionField(
        title=_("Messages"),
        description=_(
            "The list of messages that were exchanged as part of this "
            "question , sorted from first to last."),
        value_type=Reference(schema=IQuestionMessage),
        required=True,
        default=[],
        readonly=True),
                        as_of='devel')

    # Workflow methods
    def setStatus(user, new_status, comment, datecreated=None):
        """Change the status of this question.

        Set the question's status to new_status and add an IQuestionMessage
        with action SETSTATUS.

        Only the question target owner or admin can change the status using
        this method.

        An InvalidQuestiontateError is raised when this method is called
        with new_status equals to the current question status.

        Return the created IQuestionMessage.

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

        :user: The IPerson making the change.
        :new_status: The new QuestionStatus
        :comment: A string or IMessage containing an explanation for the
                  change.
        :datecreated: Date for the message. Defaults to the current time.
        """

    can_request_info = Attribute(
        'Whether the question is in a state where a user can request more '
        'information from the question owner.')

    def requestInfo(user, question, datecreated=None):
        """Request more information from the question owner.

        Add an IQuestionMessage with action REQUESTINFO containing the
        question. The question's status is changed to NEEDSINFO, and the
        datelastresponse attribute is updated to the message creation date.

        The user requesting more information cannot be the question's owner.
        This workflow method should only be called when the question status is
        OPEN or NEEDSINFO. An InvalidQuestionStateError is raised otherwise.

        It can also be called when the question is in the ANSWERED state, but
        in that case, the status will stay unchanged.

        Return the created IQuestionMessage.

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

        :user: IPerson requesting for the information.
        :question: A string or IMessage containing the question.
        :datecreated: Date for the answer. Defaults to the current time.
        """

    can_give_info = Attribute(
        'Whether the question is in a state where the question owner can '
        'give more information on the question.')

    def giveInfo(reply, datecreated=None):
        """Reply to the information request.

        Add an IQuestionMessage with action GIVEINFO. The question status is
        changed to OPEN, the datelastquery attribute is updated to the
        message creation time.

        This method should only be called on behalf of the question owner when
        the question is in the OPEN or NEEDSINFO state. An
        InvalidQuestionStateError is raised otherwise.

        Return the created IQuestionMessage.

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

        :reply: A string or IMessage containing the new information.
        :datecreated: Date for the message. Defaults to the current time.
        """

    can_give_answer = Attribute(
        'Whether the question is in a state a user can provide an answer on '
        'the question.')

    def giveAnswer(user, answer, datecreated=None):
        """Give an answer to this question.

        If the user is not the question's owner, add an IQuestionMessage with
        action ANSWER containing an answer for the question. This changes the
        question's status to ANSWERED and updates the datelastresponse
        attribute to the message's creation date.

        When the question owner answers the question, add an IQuestionMessage
        with action CONFIRM. The question status is changed to SOLVED, the
        answerer attribute is updated to contain the question owner, the
        answer attribute will be updated to point at the new message, the
        datelastresponse and date_solved attributes are updated to the
        message creation date.

        This workflow method should only be called when the question status is
        one of OPEN, ANSWERED or NEEDSINFO. An InvalidQuestionStateError is
        raised otherwise.

        Return the created IQuestionMessage.

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

        :user: IPerson giving the answer.
        :answer: A string or IMessage containing the answer.
        :datecreated: Date for the message. Defaults to the current time.
        """

    def linkFAQ(user, faq, comment, datecreated=None):
        """Link a FAQ as an answer to this question.

        Exactly like giveAnswer() but also link the IFAQ faq object to this
        question.

        Return the created IQuestionMessage.

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

        :param user: IPerson linking the faq.
        :param faq: The IFAQ containing the answer.
        :param comment: A string or IMessage explaining how the FAQ is
            relevant.
        :param datecreated: Date for the message. Defaults to the current
            time.
        """

    can_confirm_answer = Attribute(
        'Whether the question is in a state for the question owner to '
        'confirm that an answer solved their problem.')

    def confirmAnswer(comment, answer=None, datecreated=None):
        """Confirm that a solution to the question was found.

        Add an IQuestionMessage with action CONFIRM. The question status is
        changed to SOLVED. If the answer parameter is not None, it is recorded
        in the answer attribute and the answerer attribute is set to that
        message's owner. The datelastresponse and date_solved attributes are
        updated to the message creation date.

        This workflow method should only be called on behalf of the question
        owner, when the question status is ANSWERED, or when the status is
        OPEN or NEEDSINFO but an answer was already provided. An
        InvalidQuestionStateError is raised otherwise.

        Return the created IQuestionMessage.

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

       :comment: A string or IMessage containing a comment.
        :answer: The IQuestionMessage that contain the answer to the question.
                 It must be one of the IQuestionMessage of this question.
        :datecreated: Date for the message. Defaults to the current time.
        """

    def canReject(user):
        """Test if a user can reject the question.

        Return true only if user is an answer contact for the question target,
        the question target owner or part of the administration team.
        """

    @operation_parameters(
        comment=Text(title=_("An explanation of the rejection")))
    @call_with(user=REQUEST_USER)
    @export_factory_operation(IQuestionMessage, [])
    @operation_for_version("devel")
    def reject(user, comment, datecreated=None):
        """Mark this question as INVALID.

        Add an IQuestionMessage with action REJECT. The question status is
        changed to INVALID. The created message is set as the question answer
        and its owner as the question answerer. The datelastresponse and
        date_solved are updated to the message creation.

        Only answer contacts for the question target, the target owner or a
        member of the admin team can reject a request. All questions can be
        rejected.

        Return the created IQuestionMessage.

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

        :user: The user rejecting the request.
        :comment: A string or IMessage containing an explanation of the
                  rejection.
        :datecreated: Date for the message. Defaults to the current time.
        """

    def expireQuestion(user, comment, datecreated=None):
        """Mark a question as EXPIRED.

        Add an IQuestionMessage with action EXPIRE. This changes the question
        status to EXPIRED and update the datelastresponse attribute to the new
        message creation date.

        This workflow method should only be called when the question status is
        one of OPEN or NEEDSINFO. An InvalidQuestionStateError is raised
        otherwise.

        Return the created IQuestionMessage.

        (Note this method is named expireQuestion and not expire because of
        conflicts with SQLObject.)

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

        :user: IPerson expiring the request.
        :comment: A string or IMessage containing an explanation for the
                  expiration.
        :datecreated: Date for the message. Defaults to the current time.
        """

    can_reopen = Attribute(
        'Whether the question state is a state where the question owner '
        'could reopen it.')

    def reopen(comment, datecreated=None):
        """Reopen a question that was ANSWERED, EXPIRED or SOLVED.

        Add an IQuestionMessage with action REOPEN. This changes the question
        status to OPEN and update the datelastquery attribute to the new
        message creation date. When the question was in the SOLVED state, this
        method should reset the date_solved, answerer and answer attributes.

        This workflow method should only be called on behalf of the question
        owner, when the question status is in one of ANSWERED, EXPIRED or
        SOLVED. An InvalidQuestionStateError is raised otherwise.

        Return the created IQuestionMessage.

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

        :comment: A string or IMessage containing more information about the
                  request.
        :datecreated: Date for the message. Defaults to the current time.
        """

    def addComment(user, comment, datecreated=None):
        """Add a comment on the question.

        Create an IQuestionMessage with action COMMENT. It leaves the question
        status unchanged.

        This method should fire an IObjectCreatedEvent for the created
        IQuestionMessage and an IObjectModifiedEvent for the question.

        :user: The IPerson making the comment.
        :comment: A string or IMessage containing the comment.
        :datecreated: Date for the message. Defaults to the current time.
        """

    # subscription-related methods

    @operation_parameters(person=Reference(IPerson,
                                           title=_('Person'),
                                           required=True))
    @call_with(subscribed_by=REQUEST_USER)
    @export_write_operation()
    @operation_for_version("devel")
    def subscribe(person, subscribed_by=None):
        """Subscribe `person` to the question.

        :param person: the subscriber.
        :param subscribed_by: the person who created the subscription.
        :return: an `IQuestionSubscription`.
        """

    def isSubscribed(person):
        """Return a boolean indicating whether the person is subscribed."""

    @operation_parameters(person=Reference(IPerson,
                                           title=_('Person'),
                                           required=False))
    @call_with(unsubscribed_by=REQUEST_USER)
    @export_write_operation()
    @operation_for_version("devel")
    def unsubscribe(person, unsubscribed_by):
        """Unsubscribe `person` from the question.

        :param person: the subscriber.
        :param unsubscribed_by: the person who removed the subscription.
        """

    def getDirectSubscribers():
        """Return the persons who are subscribed to this question.

        :return: A list of persons sorted by displayname.
        """

    def getDirectSubscribersWithDetails():
        """Get direct subscribers and their subscriptions for the question.

        :returns: A ResultSet of tuples (Person, QuestionSubscription)
            representing a subscriber and their question subscription.
        """

    def getIndirectSubscribers():
        """Return the persons who are implicitly subscribed to this question.

        :return: A list of persons sorted by displayname.
        """

    def getRecipients():
        """Return the set of person to notify about changes in this question.

        That is the union of getDirectSubscribers() and
        getIndirectSubscribers().

        :return: An `INotificationRecipientSet` containing the persons to
            notify along the rationale for doing so.
        """

    direct_recipients = Attribute(
        "Return An `INotificationRecipientSet` containing the persons to "
        "notify along the rationale for doing so.")

    indirect_recipients = Attribute(
        "Return the INotificationRecipientSet of answer contacts for the "
        "question's target as well as the question's assignee.")

    @operation_parameters(comment_number=Int(
        title=_('The number of the comment in the list of messages.'),
        required=True),
                          visible=Bool(title=_('Show this comment?'),
                                       required=True))
    @call_with(user=REQUEST_USER)
    @export_write_operation()
    @operation_for_version('devel')
    def setCommentVisibility(user, comment_number, visible):
        """Set the visible attribute on a question message.
Example #25
0
class IProductView(
    ICanGetMilestonesDirectly, IHasAppointedDriver, IHasBranches,
    IHasExternalBugTracker,
    IHasMergeProposals, IHasMilestones, IHasExpirableBugs,
    IHasMugshot, IHasSprints, IHasTranslationImports,
    ITranslationPolicy, IKarmaContext, IMakesAnnouncements,
    IOfficialBugTagTargetPublic, IHasOOPSReferences,
    IHasRecipes, IHasCodeImports, IServiceUsage, IHasGitRepositories):
    """Public IProduct properties."""

    registrant = exported(
        PublicPersonChoice(
            title=_('Registrant'),
            required=True,
            readonly=True,
            vocabulary='ValidPersonOrTeam',
            description=_("This person registered the project in "
                          "Launchpad.")))

    driver = exported(
        PersonChoice(
            title=_("Driver"),
            description=_(
                "This person or team will be able to set feature goals for "
                "and approve bug targeting or backporting for ANY major "
                "series in this project. You might want to leave this blank "
                "and just appoint a team for each specific series, rather "
                "than having one project team that does it all."),
            required=False, vocabulary='ValidPersonOrTeam'))

    summary = exported(
        Summary(
            title=_('Summary'),
            description=_(
                "A short paragraph to introduce the project's work.")))

    description = exported(
        Description(
            title=_('Description'),
            required=False,
            description=_(
                "Details about the project's work, highlights, goals, and "
                "how to contribute. Use plain text, paragraphs are preserved "
                "and URLs are linked in pages. Don't repeat the Summary.")))

    datecreated = exported(
        Datetime(
            title=_('Date Created'),
            required=True, readonly=True,
            description=_("The date this project was created in Launchpad.")),
        exported_as='date_created')

    homepageurl = exported(
        URIField(
            title=_('Homepage URL'),
            required=False,
            allowed_schemes=['http', 'https', 'ftp'], allow_userinfo=False,
            description=_("""The project home page. Please include
                the http://""")),
        exported_as="homepage_url")

    wikiurl = exported(
        URIField(
            title=_('Wiki URL'),
            required=False,
            allowed_schemes=['http', 'https', 'ftp'], allow_userinfo=False,
            description=_("""The full URL of this project's wiki, if it has
                one. Please include the http://""")),
        exported_as='wiki_url')

    screenshotsurl = exported(
        URIField(
            title=_('Screenshots URL'),
            required=False,
            allowed_schemes=['http', 'https', 'ftp'], allow_userinfo=False,
            description=_("""The full URL for screenshots of this project,
                if available. Please include the http://""")),
        exported_as='screenshots_url')

    downloadurl = exported(
        URIField(
            title=_('Download URL'),
            required=False,
            allowed_schemes=['http', 'https', 'ftp'], allow_userinfo=False,
            description=_("""The full URL where downloads for this project
                are located, if available. Please include the http://""")),
        exported_as='download_url')

    programminglang = exported(
        TextLine(
            title=_('Programming Languages'),
            required=False,
            description=_("""A comma delimited list of programming
                languages used for this project.""")),
        exported_as='programming_language')

    sourceforgeproject = exported(
        TextLine(
            title=_('Sourceforge Project'),
            required=False,
            constraint=sourceforge_project_name_validator,
            description=_("""The SourceForge project name for
                this project, if it is in sourceforge.""")),
        exported_as='sourceforge_project')

    freshmeatproject = exported(
        TextLine(
            title=_('Freshmeat Project'),
            required=False, description=_("""The Freshmeat project name for
                this project, if it is in freshmeat. [DEPRECATED]""")),
        exported_as='freshmeat_project')

    homepage_content = Text(
        title=_("Homepage Content"), required=False,
        description=_(
            "The content of this project's home page. Edit this and it will "
            "be displayed for all the world to see. It is NOT a wiki "
            "so you cannot undo changes."))

    mugshot = exported(
        MugshotImageUpload(
            title=_("Brand"), required=False,
            default_image_resource='/@@/product-mugshot',
            description=_(
                "A large image of exactly 192x192 pixels, that will be "
                "displayed on this project's home page in Launchpad. It "
                "should be no bigger than 100kb in size.")),
        exported_as='brand')

    autoupdate = Bool(
        title=_('Automatic update'),
        description=_("Whether or not this project's attributes are "
                      "updated automatically."))

    private_bugs = exported(
        Bool(
            title=_('Private bugs (obsolete; always False)'), readonly=True,
            description=_("Replaced by bug_sharing_policy.")),
        ('devel', dict(exported=False)))

    branch_sharing_policy = exported(Choice(
        title=_('Branch sharing policy'),
        description=_("Sharing policy for this project's branches."),
        required=True, readonly=True, vocabulary=BranchSharingPolicy),
        as_of='devel')
    bug_sharing_policy = exported(Choice(
        title=_('Bug sharing policy'),
        description=_("Sharing policy for this project's bugs."),
        required=True, readonly=True, vocabulary=BugSharingPolicy),
        as_of='devel')
    specification_sharing_policy = exported(Choice(
        title=_('Blueprint sharing policy'),
        description=_("Sharing policy for this project's specifications."),
        required=True, readonly=True, vocabulary=SpecificationSharingPolicy),
        as_of='devel')

    licenses = exported(
        Set(title=_('Licences'),
            value_type=Choice(vocabulary=License)))

    license_info = exported(
        Description(
            title=_('Description of additional licences'),
            required=False,
            description=_(
                "Description of licences that do not appear in the list "
                "above.")))

    bugtracker = exported(
        ProductBugTracker(
            title=_('Bugs are tracked'),
            vocabulary="BugTracker"),
        exported_as='bug_tracker')

    sourcepackages = Attribute(_("List of packages for this product"))

    date_next_suggest_packaging = exported(
        Datetime(
            title=_('Next suggest packaging date'),
            description=_(
                "Obsolete. The date to resume Ubuntu package suggestions."),
            required=False),
        ('devel', dict(exported=False)))

    distrosourcepackages = Attribute(_("List of distribution packages for "
        "this product"))

    ubuntu_packages = Attribute(
        _("List of distribution packages for this product in Ubuntu"))

    series = exported(
        doNotSnapshot(
            CollectionField(value_type=Object(schema=IProductSeries))))

    development_focus = exported(
        ReferenceChoice(
            title=_('Development focus'), required=True,
            vocabulary='FilteredProductSeries',
            schema=IProductSeries,
            description=_(
                'The series that represents the master or trunk branch. '
                'The Bazaar URL lp:<project> points to the development focus '
                'series branch.')))
    development_focusID = Attribute("The development focus ID.")

    releases = exported(
        doNotSnapshot(
            CollectionField(
                title=_("An iterator over the ProductReleases for "
                        "this product."),
                readonly=True,
                value_type=Reference(schema=IProductRelease))))

    translation_focus = exported(
        ReferenceChoice(
            title=_("Translation focus"), required=False,
            vocabulary='FilteredProductSeries',
            schema=IProductSeries,
            description=_(
                'Project series that translators should focus on.')))

    translatable_packages = Attribute(
        "A list of the source packages for this product that can be "
        "translated sorted by distroseries.name and sourcepackage.name.")

    translatable_series = Attribute(
        "A list of the series of this product for which we have translation "
        "templates.")

    obsolete_translatable_series = Attribute("""
        A list of the series of this product with obsolete translation
        templates.""")

    primary_translatable = Attribute(
        "The best guess we have for what new translators will want to "
        "translate for a given product: the latest series for which we have "
        "templates, and failing that, an Ubuntu package.")

    translationgroups = Attribute("The list of applicable translation "
        "groups for a product. There can be several: one from the product, "
        "and potentially one from the project, too.")

    commercial_subscription = exported(
        Reference(
            ICommercialSubscription,
            title=_("Commercial subscriptions"),
            description=_(
                "An object which contains the timeframe and the voucher "
                "code of a subscription.")))

    commercial_subscription_is_due = exported(
            Bool(
                title=_("Commercial subscription is due"),
                readonly=True,
                description=_(
                    "Whether the project's licensing requires a new "
                    "commercial subscription to use launchpad.")))

    has_current_commercial_subscription = Attribute("""
        Whether the project has a current commercial subscription.""")

    license_status = Attribute("""
        Whether the licence is OPENSOURCE, UNREVIEWED, or PROPRIETARY.""")

    remote_product = exported(
        TextLine(
            title=_('Remote bug tracker project id'), required=False,
            description=_(
                "Some bug trackers host multiple projects at the same URL "
                "and require an identifier for the specific project.")))

    active_or_packaged_series = Attribute(
        _("Series that are active and/or have been packaged."))

    packagings = Attribute(_("All the packagings for the project."))

    security_contact = exported(
        TextLine(
            title=_('Security contact'), required=False, readonly=True,
            description=_('Security contact (obsolete; always None)')),
            ('devel', dict(exported=False)), as_of='1.0')

    vcs = exported(
        Choice(
            title=_("VCS"),
            required=False,
            vocabulary=VCSType,
            description=_(
                "Version control system for this project's code.")))

    inferred_vcs = Choice(
        title=_("Inferred VCS"),
        readonly=True,
        vocabulary=VCSType,
        description=_(
            "Inferred version control system for this project's code."))

    def getAllowedBugInformationTypes():
        """Get the information types that a bug in this project can have.

        :return: A sequence of `InformationType`s.
        """

    def getDefaultBugInformationType():
        """Get the default information type of a new bug in this project.

        :return: The `InformationType`.
        """

    def getVersionSortedSeries(statuses=None, filter_statuses=None):
        """Return all the series sorted by the name field as a version.

        The development focus field is an exception. It will always
        be sorted first.

        :param statuses: If statuses is not None, only include series
                         which are in the given statuses.
        :param filter_statuses: Filter out any series with statuses listed in
                                filter_statuses.
        """

    def redeemSubscriptionVoucher(voucher, registrant, purchaser,
                                  subscription_months, whiteboard=None,
                                  current_datetime=None):
        """Redeem a voucher and extend the subscription expiration date.

        The voucher must have already been verified to be redeemable.
        :param voucher: The voucher id as tracked in the external system.
        :param registrant: Who is redeeming the voucher.
        :param purchaser: Who purchased the voucher.  May not be known.
        :param subscription_months: integer indicating the number of months
            the voucher is for.
        :param whiteboard: Notes for this activity.
        :param current_datetime: Current time.  Will be datetime.now() if not
            specified.
        :return: None
        """

    def getPackage(distroseries):
        """Return a package in that distroseries for this product."""

    @operation_parameters(
        name=TextLine(title=_("Name"), required=True))
    @operation_returns_entry(IProductSeries)
    @export_read_operation()
    def getSeries(name):
        """Return the series for this product for the given name, or None."""

    @operation_parameters(
        version=TextLine(title=_("Version"), required=True))
    @operation_returns_entry(IProductRelease)
    @export_read_operation()
    def getRelease(version):
        """Return the release for this product that has the version given."""

    def getMilestonesAndReleases():
        """Return all the milestones and releases for this product."""

    def packagedInDistros():
        """Returns the distributions this product has been packaged in."""

    def userCanEdit(user):
        """Can the user edit this product?"""

    def getLinkedBugWatches():
        """Return all the bug watches that are linked to this Product.

        Being linked, means that a bug watch having the same bug tracker
        as this Product is using, is linked to a bug task targeted to
        this Product.
        """

    @operation_parameters(
        include_inactive=Bool(title=_("Include inactive"),
                              required=False, default=False))
    @export_read_operation()
    @export_operation_as('get_timeline')
    def getTimeline(include_inactive):
        """Return basic timeline data useful for creating a diagram.
Example #26
0
class IBuilderView(IHasBuildRecords, IHasOwner):

    id = Attribute("Builder identifier")

    processor = exported(ReferenceChoice(
        title=_('Processor'),
        required=True,
        vocabulary='Processor',
        schema=IProcessor,
        description=_(
            'DEPRECATED: Processor identifying jobs which can be built by '
            'this device. Use `processors` instead to handle multiple '
            'supported architectures.')),
                         as_of='devel')

    processors = exported(List(
        title=_("Processors"),
        description=_("Processors identifying jobs which can be built by this "
                      "device."),
        value_type=ReferenceChoice(vocabulary='Processor', schema=IProcessor)),
                          as_of='devel')

    owner = exported(
        PersonChoice(title=_('Owner'),
                     required=True,
                     vocabulary='ValidOwner',
                     description=_('Builder owner, a Launchpad member which '
                                   'will be responsible for this device.')))

    url = exported(
        TextLine(title=_('URL'),
                 required=True,
                 constraint=builder_url_validator,
                 description=_(
                     'The URL to the build machine, used as a unique '
                     'identifier. Includes protocol, host and port only, '
                     'e.g.: http://farm.com:8221/')))

    name = exported(
        TextLine(
            title=_('Name'),
            required=True,
            constraint=name_validator,
            description=_('Builder Slave Name used for reference purposes')))

    title = exported(
        Title(title=_('Title'),
              required=True,
              description=_(
                  'The builder slave title. Should be just a few words.')))

    virtualized = exported(
        Bool(title=_('Virtualized'),
             required=True,
             default=False,
             description=_('Whether or not the builder is a virtual Xen '
                           'instance.')))

    manual = exported(
        Bool(title=_('Manual Mode'),
             required=False,
             default=False,
             description=_('The auto-build system does not dispatch '
                           'jobs automatically for slaves in manual mode.')))

    builderok = exported(
        Bool(title=_('Builder State OK'),
             required=True,
             default=True,
             description=_('Whether or not the builder is ok')))

    failnotes = exported(
        Text(title=_('Failure Notes'),
             required=False,
             description=_('The reason for a builder not being ok')))

    vm_host = exported(
        TextLine(title=_('VM host'),
                 required=False,
                 description=_('The machine hostname hosting the virtual '
                               'buildd-slave, e.g.: foobar-host.ppa')))

    vm_reset_protocol = exported(
        Choice(title=_("VM reset protocol"),
               vocabulary=BuilderResetProtocol,
               readonly=False,
               required=False,
               description=_("The protocol version for resetting the VM.")))

    active = exported(
        Bool(title=_('Publicly Visible'),
             required=False,
             default=True,
             description=_('Whether or not to present the builder publicly.')))

    currentjob = Attribute("BuildQueue instance for job being processed.")

    current_build = exported(
        Reference(
            title=_("Current build"),
            required=False,
            readonly=True,
            schema=Interface,  # Really IBuildFarmJob.
            description=_("The job currently running on this builder.")),
        as_of="devel")

    failure_count = exported(
        Int(title=_('Failure Count'),
            required=False,
            default=0,
            description=_("Number of consecutive failures for this builder.")))

    version = exported(
        Text(title=_('Version'),
             required=False,
             description=_('The version of launchpad-buildd on the slave.')))

    clean_status = exported(
        Choice(
            title=_("Clean status"),
            vocabulary=BuilderCleanStatus,
            readonly=True,
            description=_(
                "The readiness of the slave to take a job. Only internal build "
                "infrastructure bots need to or should write to this.")))

    date_clean_status_changed = exported(
        Datetime(title=_("Date clean status changed"),
                 readonly=True,
                 description=_(
                     "The date the builder's clean status last changed.")))

    def gotFailure():
        """Increment failure_count on the builder."""

    def resetFailureCount():
        """Set the failure_count back to zero."""

    def failBuilder(reason):
        """Mark builder as failed for a given reason."""

    def acquireBuildCandidate():
        """Acquire a build candidate in an atomic fashion.
Example #27
0
class IBugNomination(IHasBug, IHasOwner):
    """A nomination for a bug to be fixed in a specific series.

    A nomination can apply to an IDistroSeries or an IProductSeries.
    """
    export_as_webservice_entry(publish_web_link=False)

    # We want to customize the titles and descriptions of some of the
    # attributes of our parent interfaces, so we redefine those specific
    # attributes below.
    id = Int(title=_("Bug Nomination #"))
    bug = exported(Reference(schema=IBug, readonly=True))
    date_created = exported(Datetime(
        title=_("Date Submitted"),
        description=_("The date on which this nomination was submitted."),
        required=True, readonly=True))
    date_decided = exported(Datetime(
        title=_("Date Decided"),
        description=_(
            "The date on which this nomination was approved or declined."),
        required=False, readonly=True))
    distroseries = exported(ReferenceChoice(
        title=_("Series"), required=False, readonly=True,
        vocabulary="DistroSeries", schema=IDistroSeries))
    productseries = exported(ReferenceChoice(
        title=_("Series"), required=False, readonly=True,
        vocabulary="ProductSeries", schema=IProductSeries))
    owner = exported(PublicPersonChoice(
        title=_('Submitter'), required=True, readonly=True,
        vocabulary='ValidPersonOrTeam'))
    ownerID = Attribute('The db id of the owner.')
    decider = exported(PublicPersonChoice(
        title=_('Decided By'), required=False, readonly=True,
        vocabulary='ValidPersonOrTeam'))
    target = exported(Reference(
        schema=IBugTarget,
        title=_("The IProductSeries or IDistroSeries of this nomination.")))
    status = exported(Choice(
        title=_("Status"), vocabulary=BugNominationStatus,
        default=BugNominationStatus.PROPOSED, readonly=True))

    @call_with(approver=REQUEST_USER)
    @export_write_operation()
    def approve(approver):
        """Approve this bug for fixing in a series.

        :approver: The IPerson that approves this nomination and that
                   will own the created bugtasks.

        The status is set to APPROVED and the appropriate IBugTask(s)
        are created for the nomination target.

        A nomination in any state can be approved. If the nomination is
        /already/ approved, this method is a noop.
        """

    @call_with(decliner=REQUEST_USER)
    @export_write_operation()
    def decline(decliner):
        """Decline this bug for fixing in a series.

        :decliner: The IPerson that declines this nomination.

        The status is set to DECLINED.

        If called on a nomination that is in APPROVED state, a
        BugNominationStatusError is raised. If the nomination was
        already DECLINED, this method is a noop.
        """

    # Helper methods for making status checking more readable.
    def isProposed():
        """Is this nomination in Proposed state?"""

    def isDeclined():
        """Is this nomination in Declined state?"""

    def isApproved():
        """Is this nomination in Approved state?"""

    @call_with(person=REQUEST_USER)
    @export_read_operation()
    def canApprove(person):
        """Is this person allowed to approve the nomination?"""
Example #28
0
class ISnapEditableAttributes(IHasOwner):
    """`ISnap` attributes that can be edited.

    These attributes need launchpad.View to see, and launchpad.Edit to change.
    """
    date_last_modified = exported(Datetime(
        title=_("Date last modified"), required=True, readonly=True))

    owner = exported(PersonChoice(
        title=_("Owner"), required=True, readonly=False,
        vocabulary="AllUserTeamsParticipationPlusSelf",
        description=_("The owner of this snap package.")))

    distro_series = exported(Reference(
        IDistroSeries, title=_("Distro Series"),
        required=False, readonly=False,
        description=_(
            "The series for which the snap package should be built.  If not "
            "set, Launchpad will infer an appropriate series from "
            "snapcraft.yaml.")))

    name = exported(TextLine(
        title=_("Name"), required=True, readonly=False,
        constraint=name_validator,
        description=_("The name of the snap package.")))

    description = exported(Text(
        title=_("Description"), required=False, readonly=False,
        description=_("A description of the snap package.")))

    branch = exported(ReferenceChoice(
        title=_("Bazaar branch"), schema=IBranch, vocabulary="Branch",
        required=False, readonly=False,
        description=_(
            "A Bazaar branch containing a snap/snapcraft.yaml, "
            "build-aux/snap/snapcraft.yaml, snapcraft.yaml, or "
            ".snapcraft.yaml recipe at the top level.")))

    git_repository = exported(ReferenceChoice(
        title=_("Git repository"),
        schema=IGitRepository, vocabulary="GitRepository",
        required=False, readonly=True,
        description=_(
            "A Git repository with a branch containing a snap/snapcraft.yaml, "
            "build-aux/snap/snapcraft.yaml, snapcraft.yaml, or "
            ".snapcraft.yaml recipe at the top level.")))

    git_repository_url = exported(URIField(
        title=_("Git repository URL"), required=False, readonly=True,
        description=_(
            "The URL of a Git repository with a branch containing a "
            "snap/snapcraft.yaml, build-aux/snap/snapcraft.yaml, "
            "snapcraft.yaml, or .snapcraft.yaml recipe at the top level."),
        allowed_schemes=["git", "http", "https"],
        allow_userinfo=True,
        allow_port=True,
        allow_query=False,
        allow_fragment=False,
        trailing_slash=False))

    git_path = TextLine(
        title=_("Git branch path"), required=False, readonly=False,
        description=_(
            "The path of the Git branch containing a snap/snapcraft.yaml, "
            "build-aux/snap/snapcraft.yaml, snapcraft.yaml, or "
            ".snapcraft.yaml recipe at the top level."))
    _api_git_path = exported(
        TextLine(
            title=git_path.title, required=False, readonly=False,
            description=git_path.description),
        exported_as="git_path")

    git_ref = exported(Reference(
        IGitRef, title=_("Git branch"), required=False, readonly=False,
        description=_(
            "The Git branch containing a snap/snapcraft.yaml, "
            "build-aux/snap/snapcraft.yaml, snapcraft.yaml, or "
            ".snapcraft.yaml recipe at the top level.")))

    build_source_tarball = exported(Bool(
        title=_("Build source tarball"),
        required=True, readonly=False,
        description=_(
            "Whether builds of this snap package should also build a tarball "
            "containing all source code, including external dependencies.")))

    auto_build = exported(Bool(
        title=_("Automatically build when branch changes"),
        required=True, readonly=False,
        description=_(
            "Whether this snap package is built automatically when the branch "
            "containing its snap/snapcraft.yaml, "
            "build-aux/snap/snapcraft.yaml, snapcraft.yaml, or "
            ".snapcraft.yaml recipe changes.")))

    auto_build_archive = exported(Reference(
        IArchive, title=_("Source archive for automatic builds"),
        required=False, readonly=False,
        description=_(
            "The archive from which automatic builds of this snap package "
            "should be built.")))

    auto_build_pocket = exported(Choice(
        title=_("Pocket for automatic builds"),
        vocabulary=PackagePublishingPocket, required=False, readonly=False,
        description=_(
            "The package stream within the source distribution series to use "
            "when building the snap package.")))

    auto_build_channels = exported(Dict(
        title=_("Source snap channels for automatic builds"),
        key_type=TextLine(), required=False, readonly=False,
        description=_(
            "A dictionary mapping snap names to channels to use when building "
            "this snap package.  Currently only 'core' and 'snapcraft' keys "
            "are supported.")))

    is_stale = Bool(
        title=_("Snap package is stale and is due to be rebuilt."),
        required=True, readonly=False)

    store_upload = exported(Bool(
        title=_("Automatically upload to store"),
        required=True, readonly=False,
        description=_(
            "Whether builds of this snap package are automatically uploaded "
            "to the store.")))

    # XXX cjwatson 2016-12-08: We should limit this to series that are
    # compatible with distro_series, but that entails validating the case
    # where both are changed in a single PATCH request in such a way that
    # neither is compatible with the old value of the other.  As far as I
    # can tell lazr.restful only supports per-field validation.
    store_series = exported(ReferenceChoice(
        title=_("Store series"),
        schema=ISnappySeries, vocabulary="SnappySeries",
        required=False, readonly=False,
        description=_(
            "The series in which this snap package should be published in the "
            "store.")))

    store_distro_series = ReferenceChoice(
        title=_("Store and distro series"),
        schema=ISnappyDistroSeries, vocabulary="SnappyDistroSeries",
        required=False, readonly=False)

    store_name = exported(TextLine(
        title=_("Registered store package name"),
        required=False, readonly=False,
        description=_(
            "The registered name of this snap package in the store.")))

    store_secrets = List(
        value_type=TextLine(), title=_("Store upload tokens"),
        required=False, readonly=False,
        description=_(
            "Serialized secrets issued by the store and the login service to "
            "authorize uploads of this snap package."))

    store_channels = exported(List(
        title=_("Store channels"),
        required=False, readonly=False, constraint=channels_validator,
        description=_(
            "Channels to release this snap package to after uploading it to "
            "the store. A channel is defined by a combination of an optional "
            " track, a risk, and an optional branch, e.g. "
            "'2.1/stable/fix-123', '2.1/stable', 'stable/fix-123', or "
            "'stable'.")))
Example #29
0
class IBugTaskSearchBase(Interface):
    """The basic search controls."""
    searchtext = TextLine(title=_("Bug ID or search text."), required=False)
    status = List(title=_('Status'),
                  description=_('Show only bugs with the given status value '
                                'or list of values.'),
                  value_type=Choice(title=_('Status'),
                                    vocabulary=BugTaskStatusSearch,
                                    default=BugTaskStatusSearch.NEW),
                  default=list(DEFAULT_SEARCH_BUGTASK_STATUSES),
                  required=False)
    importance = List(title=_('Importance'),
                      description=_('Show only bugs with the given importance '
                                    'or list of importances.'),
                      value_type=IBugTask['importance'],
                      required=False)
    information_type = List(
        title=_('Information Type'),
        description=_('Show only bugs with the given information type '
                      'or list of information types.'),
        value_type=Choice(title=_('Information Type'),
                          vocabulary=InformationType),
        required=False)
    assignee = Choice(title=_('Assignee'),
                      description=_('Person entity assigned for this bug.'),
                      vocabulary='ValidAssignee',
                      required=False)
    bug_reporter = Choice(
        title=_('Bug reporter'),
        description=_('Person entity that filed the bug report.'),
        vocabulary='ValidAssignee',
        required=False)
    omit_dupes = Bool(title=_('Omit bugs marked as duplicate,'),
                      required=False,
                      default=True)
    omit_targeted = Bool(title=_('Omit bugs targeted to a series'),
                         required=False,
                         default=True)
    has_patch = Bool(title=_('Show only bugs with patches available.'),
                     required=False,
                     default=False)
    has_no_package = Bool(title=_('Exclude bugs with packages specified'),
                          required=False,
                          default=False)
    milestone = List(
        title=_('Milestone'),
        description=_('Show only bug tasks targeted to this milestone.'),
        value_type=ReferenceChoice(title=_('Milestone'),
                                   vocabulary='Milestone',
                                   schema=Interface),  # IMilestone
        required=False)
    component = List(title=_('Component'),
                     description=_('Distribution package archive grouping. '
                                   'E.g. main, universe, multiverse'),
                     value_type=IComponent['name'],
                     required=False)
    tag = List(title=_("Tag"), value_type=SearchTag(), required=False)
    status_upstream = List(
        title=_('Status upstream'),
        description=_('Indicates the status of any remote watches '
                      'associated with the bug.  Possible values '
                      'include: pending_bugwatch, hide_upstream, '
                      'resolved_upstream, and open_upstream.'),
        value_type=Choice(vocabulary=UPSTREAM_STATUS_VOCABULARY),
        required=False)
    has_cve = Bool(title=_('Show only bugs associated with a CVE'),
                   required=False)
    structural_subscriber = Choice(
        title=_('Structural Subscriber'),
        vocabulary='ValidPersonOrTeam',
        description=_(
            'Show only bugs in projects, series, distributions, and packages '
            'that this person or team is subscribed to.'),
        required=False)
    bug_commenter = Choice(
        title=_('Bug commenter'),
        vocabulary='ValidPersonOrTeam',
        description=_('Show only bugs commented on by this person.'),
        required=False)
    subscriber = Choice(title=_('Bug subscriber'),
                        vocabulary='ValidPersonOrTeam',
                        description=_('Show only bugs this person or team '
                                      'is directly subscribed to.'),
                        required=False)
    affects_me = Bool(title=_('Show only bugs affecting me'), required=False)
    has_branches = Bool(title=_('Show bugs with linked branches'),
                        required=False,
                        default=True)
    has_no_branches = Bool(title=_('Show bugs without linked branches'),
                           required=False,
                           default=True)
    has_blueprints = Bool(title=_('Show bugs with linked blueprints'),
                          required=False,
                          default=True)
    has_no_blueprints = Bool(title=_('Show bugs without linked blueprints'),
                             required=False,
                             default=True)
class IDistributionMirror(Interface):
    """A mirror of a given distribution."""
    export_as_webservice_entry()

    id = Int(title=_('The unique id'), required=True, readonly=True)
    owner = exported(
        PublicPersonChoice(
            title=_('Owner'),
            readonly=False,
            vocabulary='ValidOwner',
            required=True,
            description=_(
                "The person who is set as the current administrator of this"
                "mirror.")))
    distribution = exported(
        Reference(
            Interface,
            # Really IDistribution, circular import fixed in
            # _schema_circular_imports.
            title=_("Distribution"),
            required=True,
            readonly=True,
            description=_("The distribution that is mirrored")))
    name = exported(
        DistributionMirrorNameField(
            title=_('Name'),
            required=True,
            readonly=False,
            description=_('A short and unique name for this mirror.'),
            constraint=name_validator))
    displayname = exported(
        TextLine(title=_('Organisation'),
                 required=False,
                 readonly=False,
                 description=_(
                     'The name of the organization hosting this mirror.')))
    description = exported(
        TextLine(title=_('Description'), required=False, readonly=False))
    http_base_url = exported(
        DistroMirrorHTTPURIField(
            title=_('HTTP URL'),
            required=False,
            readonly=False,
            allowed_schemes=['http'],
            allow_userinfo=False,
            allow_query=False,
            allow_fragment=False,
            trailing_slash=True,
            description=_('e.g.: http://archive.ubuntu.com/ubuntu/')))
    ftp_base_url = exported(
        DistroMirrorFTPURIField(
            title=_('FTP URL'),
            required=False,
            readonly=False,
            allowed_schemes=['ftp'],
            allow_userinfo=False,
            allow_query=False,
            allow_fragment=False,
            trailing_slash=True,
            description=_('e.g.: ftp://archive.ubuntu.com/ubuntu/')))
    rsync_base_url = exported(
        DistroMirrorRsyncURIField(
            title=_('Rsync URL'),
            required=False,
            readonly=False,
            allowed_schemes=['rsync'],
            allow_userinfo=False,
            allow_query=False,
            allow_fragment=False,
            trailing_slash=True,
            description=_('e.g.: rsync://archive.ubuntu.com/ubuntu/')))
    enabled = exported(
        Bool(title=_('This mirror was probed successfully.'),
             required=False,
             readonly=True,
             default=False))
    speed = exported(
        Choice(title=_('Link Speed'),
               required=True,
               readonly=False,
               vocabulary=MirrorSpeed))
    country = exported(
        ReferenceChoice(
            title=_('Location'),
            description=_("The country in which this mirror is based."),
            required=True,
            readonly=False,
            vocabulary='CountryName',
            schema=ICountry))
    content = exported(
        Choice(title=_('Content'),
               required=True,
               readonly=False,
               description=_(
                   'Choose "CD Image" if this mirror contains CD images of '
                   'this distribution. Choose "Archive" if this is a '
                   'mirror of packages for this distribution.'),
               vocabulary=MirrorContent))
    status = exported(
        Choice(
            title=_('Status'),
            required=True,
            readonly=False,
            vocabulary=MirrorStatus,
            description=_("The current status of a mirror's registration.")))

    title = Attribute('The title of this mirror')
    cdimage_series = Attribute('All MirrorCDImageDistroSeries of this mirror')
    source_series = Attribute('All MirrorDistroSeriesSources of this mirror')
    arch_series = Attribute('All MirrorDistroArchSeries of this mirror')
    last_probe_record = Attribute(
        'The last MirrorProbeRecord for this mirror.')
    all_probe_records = Attribute('All MirrorProbeRecords for this mirror.')
    has_ftp_or_rsync_base_url = Bool(
        title=_('Does this mirror have a FTP or Rsync base URL?'))
    arch_mirror_freshness = Attribute(
        'The freshness of this mirror\'s archive mirrors')
    source_mirror_freshness = Attribute(
        'The freshness of this mirror\'s source mirrors')
    base_url = Attribute('The HTTP or FTP base URL of this mirror')
    date_created = exported(
        Datetime(
            title=_('Date Created'),
            required=True,
            readonly=True,
            description=_("The date on which this mirror was registered.")))
    country_dns_mirror = exported(
        Bool(title=_('Country DNS Mirror'),
             description=_('Whether this is a country mirror in DNS.'),
             required=False,
             readonly=True,
             default=False))

    reviewer = exported(
        PublicPersonChoice(
            title=_('Reviewer'),
            required=False,
            readonly=True,
            vocabulary='ValidPersonOrTeam',
            description=_("The person who last reviewed this mirror.")))
    date_reviewed = exported(
        Datetime(
            title=_('Date reviewed'),
            required=False,
            readonly=True,
            description=_(
                "The date on which this mirror was last reviewed by a mirror "
                "admin.")))

    official_candidate = exported(
        Bool(title=_('Apply to be an official mirror of this distribution'),
             required=False,
             readonly=False,
             default=True))
    whiteboard = exported(
        Whiteboard(title=_('Whiteboard'),
                   required=False,
                   readonly=False,
                   description=_(
                       "Notes on the current status of the mirror (only "
                       "visible to admins and the mirror's registrant).")))

    @export_read_operation()
    def canTransitionToCountryMirror():
        """Verify if a mirror can be set as a country mirror or return
        False."""

    @mutator_for(country_dns_mirror)
    @operation_parameters(country_dns_mirror=copy_field(country_dns_mirror))
    @export_write_operation()
    def transitionToCountryMirror(country_dns_mirror):
        """Method run on changing country_dns_mirror."""

    @invariant
    def mirrorMustHaveHTTPOrFTPURL(mirror):
        if not (mirror.http_base_url or mirror.ftp_base_url):
            raise Invalid('A mirror must have at least an HTTP or FTP URL.')

    def getSummarizedMirroredSourceSeries():
        """Return a summarized list of this distribution_mirror's
        MirrorDistroSeriesSource objects.

        Summarized, in this case, means that it ignores pocket and components
        and returns the MirrorDistroSeriesSource with the worst freshness for
        each distroseries of this distribution mirror.
        """

    def getSummarizedMirroredArchSeries():
        """Return a summarized list of this distribution_mirror's
        MirrorDistroArchSeries objects.

        Summarized, in this case, means that it ignores pocket and components
        and returns the MirrorDistroArchSeries with the worst freshness for
        each distro_arch_series of this distribution mirror.
        """

    @export_read_operation()
    def getOverallFreshness():
        """Return this mirror's overall freshness.

        For ARCHIVE mirrors, the overall freshness is the worst freshness of
        all of this mirror's content objects (MirrorDistroArchSeries,
        MirrorDistroSeriesSource or MirrorCDImageDistroSeriess).

        For RELEASE mirrors, the overall freshness is either UPTODATE, if the
        mirror contains all ISO images that it should or UNKNOWN if it doesn't
        contain one or more ISO images.
        """

    @export_read_operation()
    def isOfficial():
        """Return True if this is an official mirror."""

    def shouldDisable(expected_file_count=None):
        """Should this mirror be marked disabled?

        If this is a RELEASE mirror then expected_file_count must not be None,
        and it should be disabled if the number of cdimage_series it
        contains is smaller than the given expected_file_count.

        If this is an ARCHIVE mirror, then it should be disabled only if it
        has no content at all.

        We could use len(get_expected_cdimage_paths()) to obtain the
        expected_file_count, but that's not a good idea because that method
        gets the expected paths from releases.ubuntu.com, which is something
        we don't have control over.
        """

    def disable(notify_owner, log):
        """Disable this mirror and notify the distro's mirror admins by email.

        :param notify_owner: If True, an identical notification is sent to the
        mirror owner.

        :param log: The log of requests/responses from the last time this
        mirror was probed.  This is only necessary because we want to include
        a snippet of the log in the email notification but the content can
        only be read back from the librarian after we commit the transaction
        (and we really don't want to do it here).

        This method can't be called before a probe record has been created
        because we'll link to the latest probe record in the email we send to
        notify the owner.

        The notification(s) are actually sent only if this mirror was
        previously enabled or if it was probed only once.
        """

    def newProbeRecord(log_file):
        """Create and return a new MirrorProbeRecord for this mirror."""

    def deleteMirrorDistroArchSeries(distro_arch_series, pocket, component):
        """Delete the MirrorDistroArchSeries with the given arch series and
        pocket, in case it exists.
        """

    def ensureMirrorDistroArchSeries(distro_arch_series, pocket, component):
        """Check if we have a MirrorDistroArchSeries with the given arch
        series and pocket, creating one if not.

        Return that MirrorDistroArchSeries.
        """

    def ensureMirrorDistroSeriesSource(distroseries, pocket, component):
        """Check if we have a MirrorDistroSeriesSource with the given distro
        series, creating one if not.

        Return that MirrorDistroSeriesSource.
        """

    def deleteMirrorDistroSeriesSource(distroseries, pocket, component):
        """Delete the MirrorDistroSeriesSource with the given distro series,
        in case it exists.
        """

    def ensureMirrorCDImageSeries(arch_series, flavour):
        """Check if we have a MirrorCDImageDistroSeries with the given
        arch series and flavour, creating one if not.

        Return that MirrorCDImageDistroSeries.
        """

    def deleteMirrorCDImageSeries(arch_series, flavour):
        """Delete the MirrorCDImageDistroSeries with the given arch
        series and flavour, in case it exists.
        """

    def deleteAllMirrorCDImageSeries():
        """Delete all MirrorCDImageDistroSeriess of this mirror."""

    def getExpectedPackagesPaths():
        """Get all paths where we can find Packages.gz files on this mirror.

        Return a list containing, for each path, the DistroArchSeries,
        the PackagePublishingPocket and the Component to which that given
        Packages.gz file refer to and the path to the file itself.
        """

    def getExpectedSourcesPaths():
        """Get all paths where we can find Sources.gz files on this mirror.