def setUp(self):
     super(LaunchpadTargetWidgetTestCase, self).setUp()
     self.product = self.factory.makeProduct('pting')
     field = Reference(
         __name__='target', schema=Interface, title=u'target')
     field = field.bind(Thing())
     request = LaunchpadTestRequest()
     self.widget = BranchTargetWidget(field, request)
 def setUp(self):
     super(LaunchpadTargetWidgetTestCase, self).setUp()
     self.distribution, self.package = self.factory.makeDSPCache(
         distro_name='fnord', package_name='snarf')
     self.project = self.factory.makeProduct('pting')
     field = Reference(
         __name__='target', schema=Interface, title=u'target')
     field = field.bind(Thing())
     request = LaunchpadTestRequest()
     self.widget = LaunchpadTargetWidget(field, request)
Exemple #3
0
class IPackageUpload(Interface):
    """A Queue item for the archive uploader."""

    export_as_webservice_entry(publish_web_link=False)

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

    status = exported(
        Choice(
            vocabulary=PackageUploadStatus,
            description=_("The status of this upload."),
            title=_("Queue status"), required=False, readonly=True,
            ))

    distroseries = exported(
        Reference(
            # Really IDistroSeries, patched in
            # _schema_circular_imports.py
            schema=Interface,
            description=_("The distroseries targeted by this upload."),
            title=_("Series"), required=True, readonly=False,
            ))

    pocket = exported(
        Choice(
            # Really PackagePublishingPocket, patched in
            # _schema_circular_imports.py
            vocabulary=DBEnumeratedType,
            description=_("The pocket targeted by this upload."),
            title=_("The pocket"), required=True, readonly=False,
            ))

    date_created = exported(
        Datetime(
            title=_('Date created'),
            description=_("The date this package upload was done.")))

    changesfile = Attribute("The librarian alias for the changes file "
                            "associated with this upload")
    changes_file_url = exported(
        TextLine(
            title=_("Changes file URL"),
            description=_("Librarian URL for the changes file associated with "
                          "this upload. Will be None if the upload was copied "
                          "from another series."),
            required=False, readonly=True),
        as_of="devel")

    signing_key = Attribute("Changesfile Signing Key.")

    package_copy_job = Reference(
        schema=IPackageCopyJob,
        description=_("The PackageCopyJob for this upload, if it has one."),
        title=_("Raw Package Copy Job"), required=False, readonly=True)

    concrete_package_copy_job = Reference(
        schema=IPackageCopyJob,
        description=_("Concrete IPackageCopyJob implementation, if any."),
        title=_("Package Copy Job"), required=False, readonly=True)

    archive = exported(
        Reference(
            # Really IArchive, patched in _schema_circular_imports.py
            schema=Interface,
            description=_("The archive for this upload."),
            title=_("Archive"), required=True, readonly=True))
    sources = Attribute("The queue sources associated with this queue item")
    builds = Attribute("The queue builds associated with the queue item")

    customfiles = Attribute("Custom upload files associated with this "
                            "queue item")
    custom_file_urls = exported(
        List(
            title=_("Custom file URLs"),
            description=_("Librarian URLs for all the custom files attached "
                          "to this upload."),
            value_type=TextLine(),
            required=False,
            readonly=True),
        ("devel", dict(exported=False)), exported=True)

    copy_source_archive = exported(
        Reference(
            # Really IArchive, patched in _schema_circular_imports.py
            schema=Interface,
            description=_("The archive from which this package was copied, if "
                          "any."),
            title=_("Copy source archive"), required=False, readonly=True))

    displayname = exported(
        TextLine(
            title=_("Generic displayname for a queue item"), readonly=True),
        exported_as="display_name")
    displayversion = exported(
        TextLine(
            title=_("This item's displayable source package version"),
            readonly=True),
        exported_as="display_version")
    displayarchs = exported(
        TextLine(
            title=_("Architectures related to this item"), readonly=True),
        exported_as="display_arches")

    sourcepackagerelease = Attribute(
        "The source package release for this item")

    searchable_names = TextLine(
        title=_("Searchable names for this item"), readonly=True)
    searchable_versions = List(
        title=_("Searchable versions for this item"), readonly=True)

    package_name = exported(
        TextLine(
            title=_("Name of the uploaded source package"), readonly=True),
        as_of="devel")

    package_version = exported(
        TextLine(title=_("Source package version"), readonly=True),
        as_of="devel")

    component_name = exported(
        TextLine(title=_("Source package component name"), readonly=True),
        as_of="devel")

    section_name = exported(
        TextLine(title=_("Source package section name"), readonly=True),
        as_of="devel")

    contains_source = exported(
        Bool(
            title=_("Whether or not this upload contains sources"),
            readonly=True),
        as_of="devel")
    contains_build = exported(
        Bool(
            title=_("Whether or not this upload contains binaries"),
            readonly=True),
        as_of="devel")
    contains_copy = exported(
        Bool(
            title=_("Whether or not this upload contains a copy from another "
                    "series."),
            readonly=True),
        as_of="devel")
    contains_installer = Attribute(
        "whether or not this upload contains installers images")
    contains_translation = Attribute(
        "whether or not this upload contains translations")
    contains_upgrader = Attribute(
        "whether or not this upload contains upgrader images")
    contains_ddtp = Attribute(
        "whether or not this upload contains DDTP images")
    contains_uefi = Attribute(
        "whether or not this upload contains a signed UEFI boot loader image")
    isPPA = Attribute(
        "Return True if this PackageUpload is a PPA upload.")

    components = Attribute(
        """The set of components used in this upload.

        For sources, this is the component on the associated
        sourcepackagerelease.  For binaries, this is all the components
        on all the binarypackagerelease records arising from the build.
        """)

    @export_read_operation()
    @operation_for_version("devel")
    def sourceFileUrls():
        """URLs for all the source files attached to this upload.

        :return: A collection of URLs for this upload.
        """

    @export_read_operation()
    @operation_for_version("devel")
    def binaryFileUrls():
        """URLs for all the binary files attached to this upload.

        :return: A collection of URLs for this upload.
        """

    @export_read_operation()
    @operation_for_version("devel")
    def customFileUrls():
        """URLs for all the custom files attached to this upload.

        :return: A collection of URLs for this upload.
        """

    @export_read_operation()
    @operation_for_version("devel")
    def getBinaryProperties():
        """The properties of the binaries associated with this queue item.

        :return: A list of dictionaries, each containing the properties of a
            single binary.
        """

    def getFileByName(filename):
        """Return the corresponding `ILibraryFileAlias` in this context.

        The following file types (and extension) can be looked up in the
        PackageUpload context:

         * Changes files: '.changes';
         * Source files: '.orig.tar.gz', 'tar.gz', '.diff.gz' and '.dsc'.
         * Custom files: '.tar.gz'.

        :param filename: the exact filename to be looked up.

        :raises NotFoundError if no file could be found.

        :return the corresponding `ILibraryFileAlias` if the file was found.
        """

    def setUnapproved():
        """Set queue state to UNAPPROVED."""

    def setAccepted():
        """Set queue state to ACCEPTED.

        Perform the required checks on its content, so we guarantee data
        integrity by code.
        """

    def setDone():
        """Set queue state to DONE."""

    def setRejected():
        """Set queue state to REJECTED."""

    def acceptFromUploader(changesfile_path, logger=None):
        """Perform upload acceptance during upload-time.

         * Move the upload to accepted queue in all cases.
         * Publish and close bugs for 'single-source' uploads.
         * Skip bug-closing for PPA uploads.
         * Grant karma to people involved with the upload.
        """

    @export_write_operation()
    @call_with(user=REQUEST_USER)
    @operation_for_version("devel")
    def acceptFromQueue(logger=None, dry_run=False, user=None):
        """Call setAccepted, do a syncUpdate, and send notification email.

         * Grant karma to people involved with the upload.
        """

    @export_write_operation()
    @operation_parameters(
        comment=TextLine(title=_("Rejection comment"), required=False))
    @call_with(user=REQUEST_USER)
    @operation_for_version("devel")
    def rejectFromQueue(user, logger=None, dry_run=False, comment=None):
        """Call setRejected, do a syncUpdate, and send notification email."""

    def realiseUpload(logger=None):
        """Take this ACCEPTED upload and create the publishing records for it
        as appropriate.

        When derivation is taken into account, this may result in queue items
        being created for derived distributions.

        If a logger is provided, messages will be written to it as the upload
        is entered into the publishing records.

        Return a list containing the publishing records created.
        """

    def addSource(spr):
        """Add the provided source package release to this queue entry."""

    def addBuild(build):
        """Add the provided build to this queue entry."""

    def addCustom(library_file, custom_type):
        """Add the provided library file alias as a custom queue entry of
        the given custom type.
        """

    def syncUpdate():
        """Write updates made on this object to the database.

        This should be used when you can't wait until the transaction is
        committed to have some updates actually written to the database.
        """

    def notify(summary_text=None, changes_file_object=None, logger=None):
        """Notify by email when there is a new distroseriesqueue entry.

        This will send new, accept, announce and rejection messages as
        appropriate.

        :param summary_text: Any additional text to append to the auto-
            generated summary.  This is also the only text used if there is
            a rejection message generated.

        :param changes_file_object: An open file object pointing at the
            changes file.  Current, only nascentupload need supply this
            as the transaction is not committed to the DB at that point so
            data needs to be obtained from the changes file.

        :param logger: Specify a logger object if required.  Mainly for tests.
        """

    @operation_parameters(
        new_component=TextLine(title=u"The new component name."),
        new_section=TextLine(title=u"The new section name."))
    @call_with(allowed_components=None, user=REQUEST_USER)
    @export_write_operation()
    @operation_for_version('devel')
    def overrideSource(new_component=None, new_section=None,
                       allowed_components=None, user=None):
        """Override the source package contained in this queue item.

        :param new_component: An IComponent to replace the existing one
            in the upload's source.
        :param new_section: An ISection to replace the existing one
            in the upload's source.
        :param allowed_components: A sequence of components that the
            callsite is allowed to override from and to.
        :param user: The user requesting the override change, used if
            allowed_components is None.

        :raises QueueInconsistentStateError: if either the existing
            or the new_component are not in the allowed_components
            sequence.

        The override values may be None, in which case they are not
        changed.

        :return: True if the source was overridden.
        """

    @operation_parameters(
        changes=List(
            title=u"A sequence of changes to apply.",
            description=(
                u"Each item may have a 'name' item which specifies the binary "
                "package name to override; otherwise, the change applies to "
                "all binaries in the upload. It may also have 'component', "
                "'section', and 'priority' items which replace the "
                "corresponding existing one in the upload's overridden "
                "binaries."),
            value_type=Dict(key_type=TextLine())))
    @call_with(allowed_components=None, user=REQUEST_USER)
    @export_write_operation()
    @operation_for_version('devel')
    def overrideBinaries(changes, allowed_components=None, user=None):
        """Override binary packages in a binary queue item.
Exemple #4
0
class IBinaryPackagePublishingHistoryPublic(IPublishingView):
    """A binary package publishing record."""

    id = Int(title=_('ID'), required=True, readonly=True)
    binarypackagenameID = Int(
        title=_('The DB id for the binarypackagename.'),
        required=False, readonly=False)
    binarypackagename = Attribute('The binary package name being published')
    binarypackagereleaseID = Int(
        title=_('The DB id for the binarypackagerelease.'),
        required=False, readonly=False)
    binarypackagerelease = Attribute(
        "The binary package release being published")
    source_package_name = Attribute(
        'The source package name that built this binary.')
    distroarchseriesID = Int(
        title=_("The DB id for the distroarchseries."),
        required=False, readonly=False)
    distroarchseries = exported(
        Reference(
            # Really IDistroArchSeries (fixed in
            #_schema_circular_imports.py).
            Interface,
            title=_("Distro Arch Series"),
            description=_('The distroarchseries being published into'),
            required=False, readonly=False,
            ),
        exported_as="distro_arch_series")
    distroseries = Attribute("The distroseries being published into")
    component = Int(
            title=_('The component being published into'),
            required=False, readonly=False,
            )
    section = Int(
            title=_('The section being published into'),
            required=False, readonly=False,
            )
    priority = Int(
            title=_('The priority being published into'),
            required=False, readonly=False,
            )
    phased_update_percentage = exported(
        Int(
            title=_('The percentage of users for whom this package should be '
                    'recommended, or None to publish the update for everyone'),
            required=False, readonly=True,
            ))
    datepublished = exported(
        Datetime(
            title=_("Date Published"),
            description=_('The date on which this record was published'),
            required=False, readonly=False,
            ),
        exported_as="date_published")
    scheduleddeletiondate = exported(
        Datetime(
            title=_("Scheduled Deletion Date"),
            description=_('The date on which this record is scheduled for '
                    'deletion'),
            required=False, readonly=False,
            ),
        exported_as="scheduled_deletion_date")
    status = exported(
        Choice(
            title=_('Status'),
            description=_('The status of this publishing record'),
            vocabulary=PackagePublishingStatus,
            required=False, readonly=False,
            ))
    pocket = exported(
        Choice(
            title=_('Pocket'),
            description=_('The pocket into which this entry is published'),
            vocabulary=PackagePublishingPocket,
            required=True, readonly=True,
            ))
    supersededby = Int(
            title=_('The build which superseded this one'),
            required=False, readonly=False,
            )
    datecreated = exported(
        Datetime(
            title=_('Date Created'),
            description=_('The date on which this record was created'),
            required=True, readonly=False,
            ),
        exported_as="date_created")
    datesuperseded = exported(
        Datetime(
            title=_("Date Superseded"),
            description=_(
                'The date on which this record was marked superseded'),
            required=False, readonly=False,
            ),
        exported_as="date_superseded")
    datemadepending = exported(
        Datetime(
            title=_("Date Made Pending"),
            description=_(
                'The date on which this record was set as pending removal'),
            required=False, readonly=False,
            ),
        exported_as="date_made_pending")
    dateremoved = exported(
        Datetime(
            title=_("Date Removed"),
            description=_(
                'The date on which this record was removed from the '
                'published set'),
            required=False, readonly=False,
            ),
        exported_as="date_removed")
    archive = exported(
        Reference(
            # Really IArchive (fixed in _schema_circular_imports.py).
            Interface,
            title=_('Archive'),
            description=_("The context archive for this publication."),
            required=True, readonly=True,
            ))
    removed_by = exported(
        Reference(
            IPerson,
            title=_("Removed By"),
            description=_('The Person responsible for the removal'),
            required=False, readonly=False,
        ))
    removal_comment = exported(
        Text(
            title=_("Removal Comment"),
            description=_(
                'Reason why this publication is going to be removed.'),
            required=False, readonly=False))

    distroarchseriesbinarypackagerelease = Attribute("The object that "
        "represents this binarypackagerelease in this distroarchseries.")

    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))
    build = exported(
        Reference(
            # Really IBinaryPackageBuild, fixed in _schema_circular_imports.
            Interface,
            title=_("Build"),
            description=_("The build that produced this binary package."),
            required=True, readonly=True))
    architecture_specific = exported(
        Bool(
            title=_("Architecture Specific"),
            required=False, readonly=True))
    priority_name = exported(
        TextLine(
            title=_("Priority Name"),
            required=False, readonly=True))
    is_debug = exported(
        Bool(
            title=_("Debug Package"),
            description=_("Is this a debug package publication?"),
            required=False, readonly=True),
        as_of="devel")

    def supersede(dominant=None, logger=None):
        """Supersede this publication.

        :param dominant: optional `IBinaryPackagePublishingHistory` which is
            triggering the domination.
        :param logger: optional object to which debug information will be
            logged.
        """

    def copyTo(distroseries, pocket, archive):
        """Copy this publication to another location.

        Architecture independent binary publications are copied to all
        supported architectures in the destination distroseries.

        :return: a list of `IBinaryPackagePublishingHistory` records
            representing the binaries copied to the destination location.
        """

    @export_read_operation()
    def getDownloadCount():
        """Get the download count of this binary package in this archive.

        This is currently only meaningful for PPAs."""

    @operation_parameters(
        start_date=Date(title=_("Start date"), required=False),
        end_date=Date(title=_("End date"), required=False))
    @operation_returns_collection_of(IBinaryPackageReleaseDownloadCount)
    @export_read_operation()
    def getDownloadCounts(start_date=None, end_date=None):
        """Get detailed download counts for this binary.

        :param start_date: The optional first date to return.
        :param end_date: The optional last date to return.
        """

    @operation_parameters(
        start_date=Date(title=_("Start date"), required=False),
        end_date=Date(title=_("End date"), required=False))
    @export_read_operation()
    def getDailyDownloadTotals(start_date=None, end_date=None):
        """Get the daily download counts for this binary.

        :param start_date: The optional first date to return.
        :param end_date: The optional last date to return.
        """

    @export_read_operation()
    @operation_parameters(
        include_meta=Bool(title=_("Include Metadata"), required=False))
    @operation_for_version("devel")
    def binaryFileUrls(include_meta=False):
        """URLs for this binary publication's binary files.
Exemple #5
0
class IBugAttachment(IHasBug):
    """A file attachment to an IBug.

    Launchpadlib example of accessing content of an attachment::

        for attachment in bug.attachments:
            buffer = attachment.data.open()
            for line in buffer:
                print line
            buffer.close()

    Launchpadlib example of accessing metadata about an attachment::

        attachment = bug.attachments[0]
        print "title:", attachment.title
        print "ispatch:", attachment.type

    For information about the file-like object returned by
    attachment.data.open() see lazr.restfulclient's documentation of the
    HostedFile object.

    Details about the message associated with an attachment can be found on
    the "message" attribute::

        message = attachment.message
        print "subject:", message.subject.encode('utf-8')
        print "owner:", message.owner.display_name.encode('utf-8')
        print "created:", message.date_created
    """
    export_as_webservice_entry()

    id = Int(title=_('ID'), required=True, readonly=True)
    bug = exported(
        Reference(Interface, title=_('The bug the attachment belongs to.')))
    type = exported(
        Choice(title=_('Attachment Type'),
               description=_(
                   'The type of the attachment, for example Patch or '
                   'Unspecified.'),
               vocabulary=BugAttachmentType,
               default=BugAttachmentType.UNSPECIFIED,
               required=True))
    title = exported(
        Title(title=_('Title'),
              description=_(
                  'A short and descriptive description of the attachment'),
              required=True))
    libraryfile = Bytes(title=_("The attachment content."), required=True)
    data = exported(
        Bytes(title=_("The attachment content."), required=True,
              readonly=True))
    message = exported(
        Reference(IMessage,
                  title=_("The message that was created when we "
                          "added this attachment.")))
    is_patch = Bool(title=_('Patch?'),
                    description=_('Is this attachment a patch?'),
                    readonly=True)

    @call_with(user=REQUEST_USER)
    @export_write_operation()
    def removeFromBug(user):
        """Remove the attachment from the bug."""

    def destroySelf():
        """Delete this record.

        The library file content for this attachment is set to None.
        """

    def getFileByName(filename):
        """Return the `ILibraryFileAlias for the given file name.
class IPlainPackageCopyJob(IRunnableJob):
    """A no-frills job to copy packages between `IArchive`s."""

    target_pocket = Int(title=_("Target package publishing pocket"),
                        required=True,
                        readonly=True)

    error_message = Int(title=_("Error message"), required=True, readonly=True)

    include_binaries = Bool(title=_("Copy binaries"),
                            required=False,
                            readonly=True)

    sponsored = Reference(schema=IPerson,
                          title=_('Sponsored Person'),
                          required=False,
                          readonly=True)

    unembargo = Bool(title=_("Unembargo restricted files"),
                     required=False,
                     readonly=True)

    auto_approve = Bool(title=_("Automatic approval"),
                        required=False,
                        readonly=True)

    source_distroseries = Reference(schema=IDistroSeries,
                                    title=_('Source DistroSeries.'),
                                    required=False,
                                    readonly=True)

    source_pocket = Int(title=_("Source package publishing pocket"),
                        required=False,
                        readonly=True)

    phased_update_percentage = Int(title=_("Phased update percentage"),
                                   required=False,
                                   readonly=True)

    def addSourceOverride(override):
        """Add an `ISourceOverride` to the metadata."""

    def setErrorMessage(message):
        """Set the error message."""

    def getSourceOverride():
        """Get an `ISourceOverride` from the metadata."""

    def findSourcePublication():
        """Find the appropriate origin `ISourcePackagePublishingHistory`."""

    copy_policy = Choice(title=_("Applicable copy policy"),
                         values=PackageCopyPolicy,
                         required=True,
                         readonly=True)

    def getOperationDescription():
        """Return a description of the copy operation."""

    def getErrorRecipients():
        """Return a list of email-ids to notify about copy errors."""
class IBugSubscriptionFilterAttributes(Interface):
    """Attributes of `IBugSubscriptionFilter`."""

    id = Int(required=True, readonly=True)

    structural_subscription = exported(
        Reference(
            IStructuralSubscription,
            title=_("Structural subscription"),
            required=True, readonly=True))

    find_all_tags = exported(
        Bool(
            title=_("Find all tags"),
            description=_(
                "If enabled, all tags must match, "
                "else at least one tag must match."),
            required=True, default=False))
    include_any_tags = Bool(
        title=_("Include any tags"),
        required=True, default=False)
    exclude_any_tags = Bool(
        title=_("Exclude all tags"),
        required=True, default=False)
    bug_notification_level = exported(
        Choice(
            title=_("Bug notification level"), required=True,
            vocabulary=BugNotificationLevel,
            default=BugNotificationLevel.COMMENTS,
            description=_("The volume and type of bug notifications "
                          "this subscription will generate.")))

    description = exported(
        Text(
            title=_("A short description of this filter"),
            required=False))

    statuses = exported(
        FrozenSet(
            title=_("The statuses interested in (empty for all)"),
            required=True, default=frozenset(),
            value_type=Choice(
                title=_('Status'), vocabulary=BugTaskStatus)))

    importances = exported(
        FrozenSet(
            title=_("The importances interested in (empty for all)"),
            required=True, default=frozenset(),
            value_type=Choice(
                title=_('Importance'), vocabulary=BugTaskImportance)))

    tags = exported(
        FrozenSet(
            title=_("The tags interested in"),
            required=True, default=frozenset(),
            value_type=SearchTag()))

    information_types = exported(
        FrozenSet(
            title=_("The information types interested in (empty for all)"),
            required=True, default=frozenset(),
            value_type=Choice(
                title=_('Information type'), vocabulary=InformationType)))
class ITranslationTemplatesBuild(IBuildFarmJob):
    """The build information for translation templates builds."""

    branch = Reference(
        title=_("The branch that this build operates on."),
        required=True, readonly=True, schema=IBranch)
Exemple #9
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.
class IBranchTarget(Interface):
    """A target of branches.

    A product contains branches, a source package on a distroseries contains
    branches, and a person contains 'junk' branches.
    """

    context = Attribute('The primary context.')

    name = Attribute("The name of the target.")

    components = Attribute(
        "An iterable of the objects that make up this branch target, from "
        "most-general to most-specific. In a URL, these would normally "
        "appear from left to right.")

    displayname = Attribute("The display name of this branch target.")

    default_stacked_on_branch = Reference(
        # Should be an IBranch, but circular imports prevent it.
        schema=Interface,
        title=_("Default stacked-on branch"),
        required=True,
        readonly=True,
        description=_(
            'The branch that new branches will be stacked on by default.'))

    default_merge_target = Attribute(
        "The branch to merge other branches into for this target.")

    supports_merge_proposals = Attribute(
        "Does this target support merge proposals at all?")

    supports_short_identities = Attribute(
        "Does this target support shortened bazaar identities?")

    supports_code_imports = Attribute(
        "Does this target support code imports at all?")

    allow_recipe_name_from_target = Attribute(
        "Can recipe names reasonably be generated from the target name "
        "rather than the branch name?")

    def areBranchesMergeable(other_target):
        """Are branches from other_target mergeable into this target?"""

    def __eq__(other):
        """Is this target the same as another target?"""

    def __ne__(other):
        """Is this target not the same as another target?"""

    def getNamespace(owner):
        """Return a `IBranchNamespace` for 'owner' and this target."""

    collection = Attribute("An IBranchCollection for this target.")

    def assignKarma(person, action_name, date_created=None):
        """Assign karma to the person on the appropriate target."""

    def getBugTask(bug):
        """Get the BugTask for a given bug related to the branch target."""

    def getRelatedSeriesBranchInfo(parent_branch, limit_results=None):
        """Find development branch info related to this parent branch.

        The result is a list of tuples:
            (branch, product_series)
        where:
            branch: the related branch.
            product_series: the product series associated with the branch.

        The development focus is first in the list.

        :param parent_branch: `IBranch` we are finding related branches for.
        :param limit_results: if not None, limit the number of results to the
            specified value.
        """

    def getRelatedPackageBranchInfo(parent_branch, limit_results=None):
        """Find package branch info related to this parent branch.
Exemple #11
0
class IPOTemplate(IRosettaStats):
    """A translation template."""

    export_as_webservice_entry(singular_name='translation_template',
                               plural_name='translation_templates')

    id = exported(
        Int(title=u"The translation template id.",
            required=True,
            readonly=True))

    name = exported(
        TextLine(title=_("Template name"),
                 description=_(
                     "The name of this PO template, for example "
                     "'evolution-2.2'. Each translation template has a "
                     "unique name in its package. It's important to get this "
                     "correct, because Launchpad will recommend alternative "
                     "translations based on the name."),
                 constraint=valid_name,
                 required=True))

    translation_domain = exported(
        TextLine(
            title=_("Translation domain"),
            description=_(
                "The translation domain for a translation template. "
                "Used with PO file format when generating MO files for inclusion "
                "in language pack or MO tarball exports."),
            required=True))

    description = exported(
        Text(
            title=_("Description"),
            description=_(
                "Please provide a brief description of the content "
                "of this translation template, for example, telling translators "
                "if this template contains strings for end-users or other "
                "developers."),
            required=False))

    header = Text(
        title=_('Header'),
        description=_("The standard template header in its native format."),
        required=True)

    iscurrent = exported(Bool(
        title=_("Template is active"),
        description=_(
            "If unchecked, people can no longer change the template's "
            "translations."),
        required=True,
        default=True),
                         exported_as='active')

    owner = exported(
        PersonChoice(
            title=_("Owner"),
            required=True,
            description=_(
                "The owner of the template in Launchpad can edit the template "
                "and change it's status, and can also upload new versions "
                "of the template when a new release is made or when the "
                "translation strings have been changed during development."),
            vocabulary="ValidOwner"))

    productseries = Choice(title=_("Series"),
                           required=False,
                           vocabulary="ProductSeries")

    distroseries = Choice(title=_("Series"),
                          required=False,
                          vocabulary="DistroSeries")

    sourcepackagename = Choice(
        title=_("Source Package Name"),
        description=_("The source package that uses this template."),
        required=False,
        vocabulary="SourcePackageName")

    sourcepackagenameID = Int(
        title=_("Source Package Name ID"),
        description=_("The ID of the source package that uses this template."),
        required=False,
        readonly=True)

    sourcepackage = Reference(
        ISourcePackage,
        title=u"Source package this template is for, if any.",
        required=False,
        readonly=True)

    from_sourcepackagename = Choice(
        title=_("From Source Package Name"),
        description=_(
            "The source package this template comes from (set it only if it's"
            " different from the previous 'Source Package Name'."),
        required=False,
        vocabulary="SourcePackageName")

    sourcepackageversion = TextLine(title=_("Source Package Version"),
                                    required=False)

    binarypackagename = Choice(
        title=_("Binary Package"),
        description=_("The package in which this template's translations are "
                      "installed."),
        required=False,
        vocabulary="BinaryPackageName")

    languagepack = exported(Bool(
        title=_("Include translations for this template in language packs?"),
        description=_(
            "Check this box if this template is part of a language pack so "
            "its translations should be exported that way."),
        required=True,
        default=False),
                            exported_as='exported_in_languagepacks')

    path = exported(
        TextLine(title=_(
            "Path of the template in the source tree, including filename."),
                 required=True))

    source_file = Object(title=_('Source file for this translation template'),
                         readonly=True,
                         schema=ILibraryFileAlias)

    source_file_format = exported(Choice(
        title=_("File format for the source file"),
        required=False,
        vocabulary=TranslationFileFormat),
                                  exported_as='format')

    priority = exported(
        Int(title=_('Priority'),
            required=True,
            default=0,
            description=_(
                'A number that describes how important this template is. Often '
                'there are multiple templates, and you can use this as a way '
                'of indicating which are more important and should be '
                'translated first. Pick any number - higher priority '
                'templates will generally be listed first.')))

    datecreated = Datetime(
        title=_('When this translation template was created.'),
        required=True,
        readonly=True)

    translationgroups = Attribute(
        _('''
            The `ITranslationGroup` objects that handle translations for this
            template.
            There can be several because they can be inherited from project to
            product, for example.
            '''))

    translationpermission = Choice(title=_('Translation permission'),
                                   required=True,
                                   readonly=True,
                                   description=_('''
            The permission system which is used for this translation template.
            This is inherited from the product, project and/or distro in which
            the translation template is found.
            '''),
                                   vocabulary='TranslationPermission')

    pofiles = exported(
        CollectionField(
            title=_("All translation files that exist for this template."),
            # Really IPOFile, see _schema_circular_imports.py.
            value_type=Reference(schema=Interface)),
        exported_as='translation_files')

    relatives_by_source = Attribute(
        _('''All `IPOTemplate` objects that have the same source.
            For example those that came from the same productseries or the
            same source package.
            '''))

    displayname = TextLine(title=_('The translation template brief name.'),
                           required=True,
                           readonly=True)

    title = TextLine(title=_('The translation template title.'),
                     required=True,
                     readonly=True)

    product = Object(
        title=_('The `IProduct` to which this translation template belongs.'),
        required=False,
        readonly=True,
        # Really IProduct, see _schema_circular_imports.py.
        schema=Interface)

    distribution = Object(title=_(
        'The `IDistribution` to which this translation template '
        'belongs.'),
                          readonly=True,
                          schema=IDistribution)

    messagecount = exported(Int(
        title=_('The number of translation messages for this template.'),
        required=True,
        readonly=True),
                            exported_as='message_count')

    language_count = exported(
        Int(title=_('The number of languages for which we have translations.'),
            required=True,
            readonly=True))

    translationtarget = Attribute(
        _('''
            The direct object in which this template is attached.
            This will either be an `ISourcePackage` or an `IProductSeries`.
            '''))

    date_last_updated = exported(
        Datetime(title=_('Date for last update'), required=True))

    uses_english_msgids = Bool(title=_("Uses English strings as msgids"),
                               readonly=True,
                               description=_("""
            Some formats, such as Mozilla's XPI, use symbolic msgids where
            gettext uses the original English strings to identify messages.
            """))

    translation_side = Int(title=_("Translation side"),
                           required=True,
                           readonly=True)

    def __iter__():
        """Return an iterator over current `IPOTMsgSet` in this template."""

    def clearPOFileCache():
        """Clear `POFile`-related cached data.

        As you work with a `POTemplate`, some data about its `POFile`s
        gets cached.  But if you're iterating over the template's
        translations one `POFile` at a time, you can drop any cached
        data about a `POFile` as soon as you're done with it.  Use this
        method to do that.
        """

    def setActive(active):
        """Toggle the iscurrent flag.

        Takes care of updating the suggestive potempalte cache when the
        template is disabled.
        """

    def getHeader():
        """Return an `ITranslationHeaderData` representing its header."""

    def getPOTMsgSetByMsgIDText(singular_text,
                                plural_text=None,
                                only_current=False,
                                context=None):
        """Return `IPOTMsgSet` indexed by `singular_text` from this template.

        If the key is a string or a unicode object, returns the
        `IPOTMsgSet` in this template that has a primary message ID
        with the given text.

        If `only_current` is True, then get only current message sets.

        If `context` is not None, look for a message set with that context
        value.

        If `plural_text` is not None, also filter by that plural text.

        If no `IPOTMsgSet` is found, return None.
        """

    def getPOTMsgSetBySequence(sequence):
        """Return the `IPOTMsgSet` with the given sequence or None.

        :arg sequence: The sequence number when the `IPOTMsgSet` appears.

        The sequence number must be > 0.
        """

    def getPOTMsgSets(current=True, prefetch=True):
        """Return an iterator over `IPOTMsgSet` objects in this template.

        :param current: Whether to limit the search to current
            POTMsgSets.
        :param prefetch: Whether to prefetch the `POMsgID`s attached to
            the POTMsgSets.  This is for optimization only.
        :return: All current POTMsgSets for the template if `current` is
            True, or all POTMsgSets for the template otherwise.
        """

    def getTranslationCredits():
        """Return an iterator over translation credits.

        Return all `IPOTMsgSet` objects in this template that are translation
        credits.
        """

    def getPOTMsgSetsCount(current=True):
        """Return the number of POTMsgSet objects related to this object.

        The current argument is used to select only current POTMsgSets or all
        of them.
        """

    def __getitem__(key):
        """Same as getPOTMsgSetByMsgIDText(), with only_current=True
        """

    def sharingKey():
        """A key for determining the sharing precedence of a template.

        Active templates have precedence over inactive ones.
        Development foci have precendence over non-development foci.
        Product development foci have precedence over Package development
        foci.
        """

    def getPOTMsgSetByID(id):
        """Return the POTMsgSet object related to this POTemplate with the id.

        If there is no POTMsgSet with that id and for that POTemplate, return
        None.
        """

    def languages():
        """This Return the set of languages for which we have POFiles for
        this POTemplate.
        """

    def getPOFileByPath(path):
        """Get the PO file of the given path.

        Return None if there is no such `IPOFile`.
        """

    def getPOFileByLang(language_code):
        """Get the PO file of the given language.

        Return None if there is no such POFile.
        """

    def getOtherSidePOTemplate():
        """Get the POTemplate with the same name on the other side of a
        packaging link.
        """

    def hasPluralMessage():
        """Test whether this template has any message sets which are plural
        message sets."""

    def export():
        """Return a serialized version as a string using its native format."""

    def exportWithTranslations():
        """Return an ExportedTranslationFile using its native format.

        It include all translations available.
        """

    def expireAllMessages():
        """Mark all of our message sets as not current (sequence=0)"""

    def newPOFile(language_code, create_sharing=True):
        """Return a new `IPOFile` for the given language.

        Raise LanguageNotFound if the language does not exist in the
        database.

        We should not have already an `IPOFile` for the given language_code.

        :param language_code: The code of the language for which to create
            the IPOFile.
        :param requester: The requester person. If given and will have edit
            permissions on the IPOFile, it becomes the owner. Otherwise
            rosetta_experts own the file.
        :param create_sharing: Whether the IPOFile should be created in all
            sharing templates, too. Should only be set to False to avoid
            loops when creating a new IPOTemplate.
        """

    def getDummyPOFile(language, requester=None, check_for_existing=True):
        """Return a DummyPOFile if there isn't already a persistent `IPOFile`

        Raise `LanguageNotFound` if the language does not exist in the
        database.

        This method is designed to be used by read only actions. This way you
        only create a POFile when you actually need to store data.

        We should not have already a POFile for the given language:
        if check_for_existing is set to False, no check will be done for this.
        """

    def createPOTMsgSetFromMsgIDs(msgid_singular,
                                  msgid_plural=None,
                                  context=None,
                                  sequence=0):
        """Creates a new template message in the database.

        :param msgid_singular: A reference to a singular msgid.
        :param msgid_plural: A reference to a plural msgid.  Can be None
            if the message is not a plural message.
        :param context: A context for the template message differentiating
            it from other template messages with exactly the same `msgid`.
        :param sequence: The sequence number of this POTMsgSet within this
            POTemplate. If 0, it is considered obsolete.
        :return: The newly created message set.
        """

    def createMessageSetFromText(singular_text,
                                 plural_text,
                                 context=None,
                                 sequence=0):
        """Creates a new template message in the database using strings.

        Similar to createMessageSetFromMessageID, but takes text objects
        (unicode or string) along with textual context, rather than a
        message IDs.

        :param singular_text: The string for the singular msgid.
        :param msgid_plural: The string for the plural msgid.  Must be None
            if the message is not a plural message.
        :param context: A context for the template message differentiating
            it from other template messages with exactly the same `msgid`.
        :param sequence: The sequence number of this POTMsgSet within this
            POTemplate. If 0, it is considered obsolete.
        :return: The newly created message set.
        """

    def getOrCreateSharedPOTMsgSet(singular_text,
                                   plural_text,
                                   context=None,
                                   initial_file_references=None,
                                   initial_source_comment=None):
        """Finds an existing shared POTMsgSet to use or creates a new one.

        :param singular_text: string containing singular form.
        :param plural_text: string containing plural form.
        :param context: context to differentiate between two messages with
        same singular_text and plural_text.
        :param initial_file_references: Initializer for file_references if
            a new POTMsgSet needs to be created.  Will not be set on an
            existing POTMsgSet.
        :param initial_source_comment: Initializer for source_comment if
            a new POTMsgSet needs to be created.  Will not be set on an
            existing POTMsgSet.
        :return: existing or new shared POTMsgSet with a sequence of 0
        in this POTemplate.
        """

    def importFromQueue(entry_to_import, logger=None, txn=None):
        """Import given queue entry.

        :param entry_to_import: `TranslationImportQueueEntry` specifying an
            approved import for this `POTemplate`
        :param logger: optional logger to report problems to.
        :param txn: optional transaction manager for intermediate
            commits.  Used to prevent long-running transactions that can
            lead to deadlocks.

        :return: a tuple of the subject line and body for a notification email
            to be sent to the uploader.
        """

    def getTranslationRows():
        """Return the `IVPOTexport` objects for this template."""

    def awardKarma(person, action_name):
        """Award karma for a translation action on this template."""

    def getTranslationPolicy():
        """Return the applicable `ITranslationPolicy` object.
class IBugTracker(Interface):
    """A remote bug system.

    Launchpadlib example: What bug tracker is used for a distro source
    package?

    ::

        product = source_package.upstream_product
        if product:
            tracker = product.bug_tracker
            if not tracker:
                project = product.project_group
                if project:
                    tracker = project.bug_tracker
        if tracker:
            print "%s at %s" %(tracker.bug_tracker_type, tracker.base_url)

    """
    export_as_webservice_entry()

    id = Int(title=_('ID'))
    bugtrackertype = exported(
        Choice(title=_('Bug Tracker Type'),
               vocabulary=BugTrackerType,
               default=BugTrackerType.BUGZILLA),
        exported_as='bug_tracker_type')
    name = exported(
        BugTrackerNameField(
            title=_('Name'),
            constraint=name_validator,
            description=_('A URL-friendly name for the bug tracker, '
                          'such as "mozilla-bugs".')))
    title = exported(
        TextLine(
            title=_('Title'),
            description=_('A descriptive label for this tracker to show '
                          'in listings.')))
    summary = exported(
        Text(
            title=_('Summary'),
            description=_(
                'A brief introduction or overview of this bug '
                'tracker instance.'),
            required=False))
    baseurl = exported(
        BugTrackerURL(
            title=_('Location'),
            allowed_schemes=LOCATION_SCHEMES_ALLOWED,
            description=_(
                'The top-level URL for the bug tracker, or an upstream email '
                'address. This must be accurate so that Launchpad can link '
                'to external bug reports.')),
        exported_as='base_url')
    aliases = exported(
        List(
            title=_('Location aliases'),
            description=_(
                'A list of URLs or email addresses that all lead to the '
                'same bug tracker, or commonly seen typos, separated by '
                'whitespace.'),
            value_type=BugTrackerURL(
                allowed_schemes=LOCATION_SCHEMES_ALLOWED),
            required=False),
        exported_as='base_url_aliases')
    owner = exported(
        Reference(title=_('Owner'), schema=Interface),
        exported_as='registrant')
    contactdetails = exported(
        Text(
            title=_('Contact details'),
            description=_(
                'The contact details for the external bug tracker (so that, '
                'for example, its administrators can be contacted about a '
                'security breach).'),
            required=False),
        exported_as='contact_details')
    watches = doNotSnapshot(
        exported(
            CollectionField(
                title=_('The remote watches on this bug tracker.'),
                value_type=Reference(schema=IObject))))
    has_lp_plugin = exported(
        Bool(
            title=_('This bug tracker has a Launchpad plugin installed.'),
            required=False, default=False))
    products = Attribute('The products that use this bug tracker.')
    latestwatches = Attribute('The last 10 watches created.')
    imported_bug_messages = Attribute(
        'Bug messages that have been imported from this bug tracker.')
    multi_product = Attribute(
        "This bug tracker tracks multiple remote products.")
    active = exported(
        Bool(
            title=_('Updates for this bug tracker are enabled'),
            required=True, default=True))

    watches_ready_to_check = Attribute(
        "The set of bug watches that are scheduled to be checked.")
    watches_with_unpushed_comments = Attribute(
        "The set of bug watches that have unpushed comments.")
    watches_needing_update = Attribute(
        "The set of bug watches that need updating.")

    def getBugFilingAndSearchLinks(remote_product, summary=None,
                                   description=None, remote_component=None):
        """Return the bug filing and search links for the tracker.

        :param remote_product: The name of the product on which the bug
            is to be filed or searched for.
        :param summary: The string with which to pre-filly the summary
            field of the upstream bug tracker's search and bug filing forms.
        :param description: The string with which to pre-filly the description
            field of the upstream bug tracker's bug filing form.
        :param remote_component: The name of the component on which the bug
            is to be filed or search for.
        :return: A dict of the absolute URL of the bug filing form and
            the search form for `remote_product` on the remote tracker,
            in the form {'bug_filing_url': foo, 'search_url': bar}. If
            either or both of the URLs is unavailable for the current
            BugTrackerType the relevant values in the dict will be set
            to None. If the bug tracker requires a `remote_product` but
            None is passed, None will be returned for both values in the
            dict.
        """

    def getBugsWatching(remotebug):
        """Get the bugs watching the given remote bug in this bug tracker."""

    def getLinkedPersonByName(name):
        """Return the `IBugTrackerPerson` for a given name on a bugtracker.

        :param name: The name of the person on the bugtracker in
            `bugtracker`.
        :return: an `IBugTrackerPerson`.
        """

    def linkPersonToSelf(name, person):
        """Link a Person to the BugTracker using a given name.

        :param name: The name used for person on bugtracker.
        :param person: The `IPerson` to link to bugtracker.
        :raise BugTrackerPersonAlreadyExists: If `name` has already been
            used to link a person to `bugtracker`.
        :return: An `IBugTrackerPerson`.
        """

    def ensurePersonForSelf(
        display_name, email, rationale, creation_comment):
        """Return the correct `IPerson` for a given name on a bugtracker.

        :param bugtracker: The `IBugTracker` for which we should have a
            given Person.
        :param display_name: The name of the Person on `bugtracker`.
        :param email: The Person's email address if available. If `email`
            is supplied a Person will be created or retrieved using that
            email address and no `IBugTrackerPerson` records will be created.
        :param rationale: The `PersonCreationRationale` used to create a
            new `IPerson` for this `name` and `bugtracker`, if necessary.
        :param creation_comment: The creation comment for the `IPerson`
            if one is created.
         """

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

    def resetWatches(new_next_check=None):
        """Reset the next_check times of this BugTracker's `BugWatch`es.

        :param new_next_check: If specified, contains the datetime to
            which to set the BugWatches' next_check times.  If not
            specified, the watches' next_check times will be set to a
            point between now and 24 hours hence.
        """

    @operation_parameters(
        component_group_name=TextLine(
            title=u"The name of the remote component group", required=True))
    @operation_returns_entry(Interface)
    @export_write_operation()
    def addRemoteComponentGroup(component_group_name):
        """Adds a new component group to the bug tracker"""

    @export_read_operation()
    @operation_returns_collection_of(Interface)
    def getAllRemoteComponentGroups():
        """Return collection of all component groups for this bug tracker"""

    @operation_parameters(
        component_group_name=TextLine(
            title=u"The name of the remote component group",
            required=True))
    @operation_returns_entry(Interface)
    @export_read_operation()
    def getRemoteComponentGroup(component_group_name):
        """Retrieve a given component group registered with the bug tracker.

        :param component_group_name: Name of the component group to retrieve.
        """

    @operation_parameters(
        distribution=TextLine(
            title=u"The distribution for the source package",
            required=True),
        sourcepackagename=TextLine(
            title=u"The source package name",
            required=True))
    @operation_returns_entry(Interface)
    @export_read_operation()
    @operation_for_version('devel')
    def getRemoteComponentForDistroSourcePackageName(
        distribution, sourcepackagename):
        """Returns the component linked to this source package, if any.

        If no components have been linked, returns value of None.
        """

    def getRelatedPillars(user=None):
        """Returns the `IProduct`s and `IProjectGroup`s that use this tracker.
Exemple #13
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.
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.
class IQuestionTargetPublic(ISearchableByQuestionOwner):
    """Methods that anonymous in user can access."""
    @operation_parameters(question_id=Int(title=_('Question Number'),
                                          required=True))
    @export_read_operation()
    @operation_for_version('devel')
    def getQuestion(question_id):
        """Return the question by its id, if it is applicable to this target.

        :question_id: A question id.

        If there is no such question number for this target, return None
        """

    @operation_parameters(phrase=TextLine(title=_('A phrase'), required=True))
    @operation_returns_collection_of(Interface)
    @export_read_operation()
    @operation_for_version('devel')
    def findSimilarQuestions(phrase):
        """Return questions similar to phrase.

        Return a list of question similar to the provided phrase. These
        questions will be found using a fuzzy search. The list is
        ordered from the most similar question to the least similar question.

        :param phrase: A phrase such as the summary of a question.
        """

    @operation_parameters(language=Reference(ILanguage))
    @operation_returns_collection_of(IPerson)
    @export_read_operation()
    @operation_for_version('devel')
    def getAnswerContactsForLanguage(language):
        """Return the list of Persons that provide support for a language.

        An answer contact supports questions in their preferred languages.
        """

    def getAnswerContactRecipients(language):
        """Return an `INotificationRecipientSet` of answer contacts.

        :language: an ILanguage or None. When language is none, all
                   answer contacts are returned.

        Return an INotificationRecipientSet of the answer contacts and the
        reason they are recipients of an email. The answer contacts are
        selected by their language and the fact that they are answer contacts
        for the QuestionTarget.
        """

    @operation_returns_collection_of(ILanguage)
    @export_read_operation()
    @operation_for_version('devel')
    def getSupportedLanguages():
        """Return a list of languages spoken by at the answer contacts.

        An answer contact is considered to speak a given language if that
        language is listed as one of their preferred languages.
        """

    answer_contacts = List(
        title=_("Answer Contacts"),
        description=_(
            "Persons that are willing to provide support for this target. "
            "They receive email notifications about each new question as "
            "well as for changes to any questions related to this target."),
        value_type=PublicPersonChoice(vocabulary="ValidPersonOrTeam"))

    direct_answer_contacts = List(
        title=_("Direct Answer Contacts"),
        description=_(
            "IPersons that registered as answer contacts explicitely on "
            "this target. (answer_contacts may include answer contacts "
            "inherited from other context.)"),
        value_type=PublicPersonChoice(vocabulary="ValidPersonOrTeam"))

    @operation_parameters(person=PublicPersonChoice(
        title=_('The user or an administered team'),
        required=True,
        vocabulary='ValidPersonOrTeam'))
    @call_with(subscribed_by=REQUEST_USER)
    @export_read_operation()
    @operation_for_version('devel')
    def canUserAlterAnswerContact(person, subscribed_by):
        """Can the user add or remove the answer contact.
class IGitSubscription(Interface):
    """The relationship between a person and a Git repository."""

    # XXX cjwatson 2015-01-19 bug=760849: "beta" is a lie to get WADL
    # generation working.  Individual attributes must set their version to
    # "devel".
    export_as_webservice_entry(as_of="beta")

    id = Int(title=_("ID"), readonly=True, required=True)
    person_id = Int(title=_("Person ID"), required=True, readonly=True)
    person = exported(
        PersonChoice(
            title=_("Person"),
            required=True,
            vocabulary="ValidPersonOrTeam",
            readonly=True,
            description=_(
                'Enter the launchpad id, or email address of the person you '
                'wish to subscribe to this repository. If you are unsure, use '
                'the "Choose..." option to find the person in Launchpad. You '
                'can only subscribe someone who is a registered user of the '
                'system.')))
    repository = exported(
        Reference(title=_("Repository ID"),
                  required=True,
                  readonly=True,
                  schema=IGitRepository))
    notification_level = exported(
        Choice(
            title=_("Notification Level"),
            required=True,
            vocabulary=BranchSubscriptionNotificationLevel,
            default=BranchSubscriptionNotificationLevel.ATTRIBUTEONLY,
            description=_(
                "Attribute notifications are sent when repository details are "
                "changed such as lifecycle status and name.  Revision "
                "notifications are generated when new revisions are found.")))
    max_diff_lines = exported(
        Choice(
            title=_("Generated Diff Size Limit"),
            required=True,
            vocabulary=BranchSubscriptionDiffSize,
            default=BranchSubscriptionDiffSize.ONEKLINES,
            description=_(
                "Diffs greater than the specified number of lines will not "
                "be sent to the subscriber.  The subscriber will still "
                "receive an email with the new revision details even if the "
                "diff is larger than the specified number of lines.")))
    review_level = exported(
        Choice(title=_("Code review Level"),
               required=True,
               vocabulary=CodeReviewNotificationLevel,
               default=CodeReviewNotificationLevel.FULL,
               description=_(
                   "Control the kind of review activity that triggers "
                   "notifications.")))

    subscribed_by = exported(
        PersonChoice(
            title=_("Subscribed by"),
            required=True,
            vocabulary="ValidPersonOrTeam",
            readonly=True,
            description=_("The person who created this subscription.")))

    @call_with(user=REQUEST_USER)
    @export_read_operation()
    @operation_for_version("devel")
    def canBeUnsubscribedByUser(user):
        """Can the user unsubscribe the subscriber from the repository?"""
Exemple #17
0
class IDistroSeriesDifferencePublic(Interface):
    """The public interface for distro series differences."""

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

    derived_series = exported(
        Reference(
            IDistroSeries,
            title=_("Derived series"),
            required=True,
            readonly=True,
            description=_(
                "The distribution series which identifies the derived series "
                "with the difference.")))

    parent_series = exported(
        Reference(
            IDistroSeries,
            title=_("Parent series"),
            required=True,
            readonly=True,
            description=_(
                "The distribution series which identifies the parent series "
                "with the difference.")))

    source_package_name_id = Int(title=u"Source package name id",
                                 required=True,
                                 readonly=True)
    source_package_name = Reference(
        ISourcePackageName,
        title=_("Source package name"),
        required=True,
        readonly=True,
        description=_(
            "The package with a difference between the derived series "
            "and its parent."))

    sourcepackagename = exported(
        TextLine(title=_("Source Package Name"), required=False,
                 readonly=True))

    package_diff = Reference(
        IPackageDiff,
        title=_("Package diff"),
        required=False,
        readonly=True,
        description=_(
            "The most recently generated package diff from the base to the "
            "derived version."))

    package_diff_url = exported(
        TextLine(title=_("Package diff url"),
                 readonly=True,
                 required=False,
                 description=_(
                     "The url for the diff between the base version and the "
                     "derived version.")))

    parent_package_diff = Reference(
        IPackageDiff,
        title=_("Parent package diff"),
        required=False,
        readonly=True,
        description=_(
            "The most recently generated package diff from the base to the "
            "parent version."))

    parent_package_diff_url = exported(
        TextLine(title=_("Parent package diff url"),
                 readonly=True,
                 required=False,
                 description=_(
                     "The url for the diff between the base version and the "
                     "parent version.")))

    package_diff_status = exported(
        Choice(title=_("Package diff status"),
               readonly=True,
               vocabulary=PackageDiffStatus,
               description=_(
                   "The status of the diff between the base version and the "
                   "derived version.")))

    parent_package_diff_status = exported(
        Choice(title=_("Parent package diff status"),
               readonly=True,
               vocabulary=PackageDiffStatus,
               description=_(
                   "The status of the diff between the base version and the "
                   "parent version.")))

    status = exported(
        Choice(title=_('Distro series difference status.'),
               description=_('The current status of this difference.'),
               vocabulary=DistroSeriesDifferenceStatus,
               required=True,
               readonly=True))

    difference_type = Choice(
        title=_('Difference type'),
        description=_('The type of difference for this package.'),
        vocabulary=DistroSeriesDifferenceType,
        required=True,
        readonly=True)

    source_package_release = Reference(
        IDistributionSourcePackageRelease,
        title=_("Derived source pub"),
        readonly=True,
        description=_(
            "The published version in the derived series with version "
            "source_version."))

    parent_source_package_release = Reference(
        IDistributionSourcePackageRelease,
        title=_("Parent source pub"),
        readonly=True,
        description=_(
            "The published version in the derived series with version "
            "parent_source_version."))

    source_pub = Reference(
        ISourcePackagePublishingHistory,
        title=_("Latest derived source pub"),
        readonly=True,
        description=_(
            "The most recent published version in the derived series."))

    source_version = exported(
        TextLine(title=_("Source version"),
                 readonly=True,
                 description=_(
                     "The version of the most recent source publishing in the "
                     "derived series.")))

    parent_source_pub = Reference(
        ISourcePackagePublishingHistory,
        title=_("Latest parent source pub"),
        readonly=True,
        description=_(
            "The most recent published version in the parent series."))

    parent_source_version = exported(
        TextLine(title=_("Parent source version"),
                 readonly=True,
                 description=_(
                     "The version of the most recent source publishing in the "
                     "parent series.")))

    base_version = exported(
        TextLine(
            title=_("Base version"),
            readonly=True,
            description=_(
                "The common base version of the package for differences "
                "with different versions in the parent and derived series.")))

    base_source_pub = Reference(
        ISourcePackagePublishingHistory,
        title=_("Base source pub"),
        readonly=True,
        description=_("The common base version published in the parent or the "
                      "derived series."))

    owner = Reference(
        IPerson,
        title=_("Owning team of the derived series"),
        readonly=True,
        description=_(
            "This attribute mirrors the owner of the derived series."))

    title = TextLine(
        title=_("Title"),
        readonly=True,
        required=False,
        description=_("A human-readable name describing this difference."))

    packagesets = Attribute("The packagesets for this source package in the "
                            "derived series.")

    parent_packagesets = Attribute("The packagesets for this source package "
                                   "in the parent series.")

    base_distro_source_package_release = Attribute(
        "The DistributionSourcePackageRelease object for the source release "
        "in the parent distribution.")

    def update(manual=False):
        """Checks that difference type and status matches current publishings.

        If the record is updated, a relevant comment is added.

        If there is no longer a difference (ie. the versions are
        the same) then the status is updated to RESOLVED.

        :param manual: Boolean, True if this is a user-requested change.
            This overrides auto-blacklisting.
        :return: True if the record was updated, False otherwise.
        """

    latest_comment = Reference(
        Interface,  # IDistroSeriesDifferenceComment
        title=_("The latest comment"),
        readonly=True)

    def getComments():
        """Return a result set of the comments for this difference."""
Exemple #18
0
class IBranchSubscription(Interface):
    """The relationship between a person and a branch."""
    export_as_webservice_entry()

    id = Int(title=_('ID'), readonly=True, required=True)
    personID = Int(title=_('Person ID'), required=True, readonly=True)
    person = exported(
        PersonChoice(
            title=_('Person'),
            required=True,
            vocabulary='ValidPersonOrTeam',
            readonly=True,
            description=_(
                'Enter the launchpad id, or email '
                'address of the person you wish to subscribe to this branch. '
                'If you are unsure, use the "Choose..." option to find the '
                'person in Launchpad. You can only subscribe someone who is '
                'a registered user of the system.')))
    branch = exported(
        Reference(title=_('Branch ID'),
                  required=True,
                  readonly=True,
                  schema=IBranch))
    notification_level = exported(
        Choice(
            title=_('Notification Level'),
            required=True,
            vocabulary=BranchSubscriptionNotificationLevel,
            default=BranchSubscriptionNotificationLevel.ATTRIBUTEONLY,
            description=_(
                'Attribute notifications are sent when branch details are '
                'changed such as lifecycle status and name.  Revision '
                'notifications are generated when new branch revisions are '
                'found due to the branch being updated through either pushes '
                'to the hosted branches or the mirrored branches being '
                'updated.')))
    max_diff_lines = exported(
        Choice(
            title=_('Generated Diff Size Limit'),
            required=True,
            vocabulary=BranchSubscriptionDiffSize,
            default=BranchSubscriptionDiffSize.ONEKLINES,
            description=_(
                'Diffs greater than the specified number of lines will not '
                'be sent to the subscriber.  The subscriber will still '
                'receive an email with the new revision details even if the '
                'diff is larger than the specified number of lines.')))
    review_level = exported(
        Choice(title=_('Code review Level'),
               required=True,
               vocabulary=CodeReviewNotificationLevel,
               default=CodeReviewNotificationLevel.FULL,
               description=_(
                   'Control the kind of review activity that triggers '
                   'notifications.')))

    subscribed_by = exported(
        PersonChoice(
            title=_('Subscribed by'),
            required=True,
            vocabulary='ValidPersonOrTeam',
            readonly=True,
            description=_("The person who created this subscription.")))

    @call_with(user=REQUEST_USER)
    @export_read_operation()
    def canBeUnsubscribedByUser(user):
        """Can the user unsubscribe the subscriber from the branch?"""
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.
Exemple #20
0
class ITranslationImportQueueEntry(Interface):
    """An entry of the Translation Import Queue."""
    export_as_webservice_entry(
        singular_name='translation_import_queue_entry',
        plural_name='translation_import_queue_entries')

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

    path = exported(
        TextLine(
            title=_("Path"),
            description=_(
                "The path to this file inside the source tree. Includes the"
                " filename."),
            required=True))

    importer = exported(
        PersonChoice(
            title=_("Uploader"),
            required=True,
            readonly=True,
            description=_(
                "The person that uploaded this file to Launchpad."),
            vocabulary="ValidOwner"),
        exported_as="uploader")

    dateimported = exported(
        Datetime(
            title=_("The timestamp when this queue entry was created."),
            required=True,
            readonly=True),
        exported_as="date_created")

    productseries = exported(
        Reference(
            title=_("Series"),
            required=False,
            readonly=True,
            schema=IProductSeries))

    distroseries = exported(
        Reference(
            title=_("Series"),
            required=False,
            readonly=True,
            schema=IDistroSeries))

    sourcepackagename = Choice(
        title=_("Source Package Name"),
        description=_(
            "The source package from where this entry comes."),
        required=False,
        vocabulary="SourcePackageName")

    by_maintainer = Bool(
        title=_(
            "This upload was done by the maintainer "
            "of the project or package."),
        description=_(
            "If checked, the translations in this import will be marked "
            "as is_current_upstream."),
        required=True,
        default=False)

    content = Attribute(
        "An ILibraryFileAlias reference with the file content. Must not be"
        " None.")

    format = exported(
        Choice(
            title=_('The file format of the import.'),
            vocabulary=TranslationFileFormat,
            required=True,
            readonly=True))

    status = exported(
        Choice(
            title=_("The status of the import."),
            vocabulary=RosettaImportStatus,
            required=True,
            readonly=True))

    date_status_changed = exported(
        Datetime(
            title=_("The timestamp when the status was changed."),
            required=True))

    is_targeted_to_ubuntu = Attribute(
        "True if this entry is to be imported into the Ubuntu distribution.")

    sourcepackage = exported(
        Reference(
            schema=ISourcePackage,
            title=_("The sourcepackage associated with this entry."),
            readonly=True))

    guessed_potemplate = Attribute(
        "The IPOTemplate that we can guess this entry could be imported into."
        " None if we cannot guess it.")

    import_into = Attribute("The Object where this entry will be imported. Is"
        " None if we don't know where to import it.")

    pofile = Field(
        title=_("The IPOfile where this entry should be imported."),
        required=False)

    potemplate = Field(
        title=_("The IPOTemplate associated with this entry."),
        description=_("The IPOTemplate associated with this entry. If path"
        " notes a .pot file, it should be used as the place where this entry"
        " will be imported, if it's a .po file, it indicates the template"
        " associated with tha translation."),
        required=False)

    error_output = exported(
        Text(
            title=_("Error output"),
            description=_("Output from most recent import attempt."),
            required=False,
            readonly=True))

    def canAdmin(roles):
        """Check if the user can administer this entry."""

    def canEdit(roles):
        """Check if the user can edit this entry."""

    def canSetStatus(new_status, user):
        """Check if the user can set this new status."""

    @call_with(user=REQUEST_USER)
    @operation_parameters(new_status=copy_field(status))
    @export_write_operation()
    def setStatus(new_status, user):
        """Transition to a new status if possible.

        :param new_status: Status to transition to.
        :param user: The user that is doing the transition.
        """

    def setErrorOutput(output):
        """Set `error_output` string."""

    def addWarningOutput(output):
        """Optionally add warning output to `error_output`.

        This may not do everything you expect of it.  Read the code if
        you need certainty.
        """

    def getGuessedPOFile():
        """Return an IPOFile that we think this entry should be imported into.

        Return None if we cannot guess it."""

    def getFileContent():
        """Return the imported file content as a stream."""

    def getTemplatesOnSameDirectory():
        """Return import queue entries stored on the same directory as self.

        The returned entries will be only .pot entries.
        """

    def getElapsedTimeText():
        """Return a string representing elapsed time since we got the file.
Exemple #21
0
class ISharingService(IService):

    # XXX 2012-02-24 wallyworld bug 939910
    # Need to export for version 'beta' even though we only want to use it in
    # version 'devel'
    export_as_webservice_entry(publish_web_link=False, as_of='beta')

    def checkPillarAccess(pillars, information_type, person):
        """Check the person's access to the given pillars and information type.

        :return: True if the user has been granted SharingPermission.ALL on
            *any* of the specified pillars.
        """

    def getAccessPolicyGrantCounts(pillar):
        """Return the number of grantees who have policy grants of each type.

        Returns a resultset of (InformationType, count) tuples, where count is
        the number of grantees who have an access policy grant for the
        information type.
        """

    @export_read_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(person=Reference(IPerson,
                                           title=_('Person'),
                                           required=True))
    @operation_returns_collection_of(IProduct)
    @operation_for_version('devel')
    def getSharedProjects(person, user):
        """Find projects for which person has one or more access policy grants.

        :param user: the user making the request. If the user is an admin, then
            all projects are returned, else only those for which the user is a
            maintainer or driver.
        :return: a collection of projects
        """

    @export_read_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(person=Reference(IPerson,
                                           title=_('Person'),
                                           required=True))
    @operation_returns_collection_of(IDistribution)
    @operation_for_version('devel')
    def getSharedDistributions(person, user):
        """Find distributions for which person has one or more access policy
           grants.

        :param user: the user making the request. If the user is an admin, then
            all distributions are returned, else only those for which the user
            is a maintainer or driver.
        :return: a collection of distributions
        """

    @export_read_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(pillar=Reference(IPillar,
                                           title=_('Pillar'),
                                           required=True),
                          person=Reference(IPerson,
                                           title=_('Person'),
                                           required=True))
    @operation_for_version('devel')
    def getSharedArtifacts(pillar, person, user):
        """Return the artifacts shared between the pillar and person.

        The result includes bugtasks rather than bugs since this is what the
        pillar filtering is applied to and is what the calling code uses.
        The shared bug can be obtained simply by reading the bugtask.bug
        attribute.

        :param user: the user making the request. Only artifacts visible to the
             user will be included in the result.
        :return: a (bugtasks, branches, specifications) tuple
        """

    def checkPillarArtifactAccess(pillar, user):
        """Return True if user has any grants on pillar else return False."""

    @export_read_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(pillar=Reference(IPillar,
                                           title=_('Pillar'),
                                           required=True),
                          person=Reference(IPerson,
                                           title=_('Person'),
                                           required=True))
    @operation_returns_collection_of(IBug)
    @operation_for_version('devel')
    def getSharedBugs(pillar, person, user):
        """Return the bugs shared between the pillar and person.

        The result includes bugtasks rather than bugs since this is what the
        pillar filtering is applied to. The shared bug can be obtained simply
        by reading the bugtask.bug attribute.

        :param user: the user making the request. Only bugs visible to the
             user will be included in the result.
        :return: a collection of bug tasks.
        """

    @export_read_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(pillar=Reference(IPillar,
                                           title=_('Pillar'),
                                           required=True),
                          person=Reference(IPerson,
                                           title=_('Person'),
                                           required=True))
    @operation_returns_collection_of(IBranch)
    @operation_for_version('devel')
    def getSharedBranches(pillar, person, user):
        """Return the branches shared between the pillar and person.

        :param user: the user making the request. Only branches visible to the
             user will be included in the result.
        :return: a collection of branches
        """

    @export_read_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(pillar=Reference(IPillar,
                                           title=_('Pillar'),
                                           required=True),
                          person=Reference(IPerson,
                                           title=_('Person'),
                                           required=True))
    @operation_returns_collection_of(ISpecification)
    @operation_for_version('devel')
    def getSharedSpecifications(pillar, person, user):
        """Return the specifications shared between the pillar and person.

        :param user: the user making the request. Only branches visible to the
             user will be included in the result.
        :return: a collection of specifications.
        """

    def getVisibleArtifacts(person, branches=None, bugs=None):
        """Return the artifacts shared with person.

        Given lists of artifacts, return those a person has access to either
        via a policy grant or artifact grant.

        :param person: the person whose access is being checked.
        :param branches: the branches to check for which a person has access.
        :param bugs: the bugs to check for which a person has access.
        :return: a collection of artifacts the person can see.
        """

    def getInvisibleArtifacts(person, branches=None, bugs=None):
        """Return the artifacts which are not shared with person.

        Given lists of artifacts, return those a person does not have access to
        either via a policy grant or artifact grant.
        * Do not export this method to the API since it could be used to gain
          access to private information. Internal use only. *

        :param person: the person whose access is being checked.
        :param branches: the branches to check for which a person has access.
        :param bugs: the bugs to check for which a person has access.
        :return: a collection of artifacts the person can not see.
        """

    def getPeopleWithoutAccess(concrete_artifact, people):
        """Return the people who cannot access an artifact.

        Given a list of people, return those who do not have access to the
        specified bug or branch.

        :param concrete_artifact: the bug or branch whose access is being
            checked.
        :param people: the people whose access is being checked.
        :return: a collection of people without access to the artifact.
        """

    def getAllowedInformationTypes(pillar):
        """Return the allowed private information types for the given pillar.

        The allowed information types are those for which bugs and branches
        may be created. This does not mean that there will necessarily be bugs
        and branches of these types; the result is used to populate the allowed
        choices in the grantee sharing pillar and other similar things.

        The allowed information types are determined by the pillar's bug and
        branch sharing policies. It is possible that there are bugs or branches
        of a given information type which is now nominally not allowed with a
        change in policy. Such information types are also included in the
        result.
        """

    def getBugSharingPolicies(pillar):
        """Return the allowed bug sharing policies for the given pillar."""

    def getBranchSharingPolicies(pillar):
        """Return the allowed branch sharing policies for the given pillar."""

    def getSpecificationSharingPolicies(pillar):
        """Return specification sharing policies for a given pillar."""

    def getSharingPermissions():
        """Return the information sharing permissions."""

    def getPillarGrantees(pillar):
        """Return people/teams who can see pillar artifacts."""

    @export_read_operation()
    @operation_parameters(pillar=Reference(IPillar,
                                           title=_('Pillar'),
                                           required=True))
    @operation_for_version('devel')
    def getPillarGranteeData(pillar):
        """Return people/teams who can see pillar artifacts.

        The result records are json data which includes:
            - person name
            - permissions they have for each information type.
        """

    def jsonGranteeData(grant_permissions):
        """Return people/teams who can see pillar artifacts.

        :param grant_permissions: a list of (grantee, accesspolicy, permission)
            tuples.

        The result records are json data which includes:
            - person name
            - permissions they have for each information type.
        """

    @export_write_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(pillar=Reference(IPillar,
                                           title=_('Pillar'),
                                           required=True),
                          grantee=Reference(IPerson,
                                            title=_('Grantee'),
                                            required=True),
                          permissions=Dict(
                              key_type=Choice(vocabulary=InformationType),
                              value_type=Choice(vocabulary=SharingPermission)))
    @operation_for_version('devel')
    def sharePillarInformation(pillar, grantee, user, permissions):
        """Ensure grantee has the grants for information types on a pillar.

        :param pillar: the pillar for which to grant access
        :param grantee: the person or team to grant
        :param user: the user making the request
        :param permissions: a dict of {InformationType: SharingPermission}
            if SharingPermission is ALL, then create an access policy grant
            if SharingPermission is SOME, then remove any access policy grants
            if SharingPermission is NONE, then remove all grants for the access
            policy
        """

    @export_write_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(pillar=Reference(IPillar,
                                           title=_('Pillar'),
                                           required=True),
                          grantee=Reference(IPerson,
                                            title=_('Grantee'),
                                            required=True),
                          information_types=List(
                              Choice(vocabulary=InformationType),
                              required=False))
    @operation_for_version('devel')
    def deletePillarGrantee(pillar, grantee, user, information_types):
        """Remove a grantee from a pillar.

        :param pillar: the pillar from which to remove access
        :param grantee: the person or team to remove
        :param user: the user making the request
        :param information_types: if None, remove all access, otherwise just
                                   remove the specified access_policies
        """

    @export_write_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(pillar=Reference(IPillar,
                                           title=_('Pillar'),
                                           required=True),
                          grantee=Reference(IPerson,
                                            title=_('Grantee'),
                                            required=True),
                          bugs=List(Reference(schema=IBug),
                                    title=_('Bugs'),
                                    required=False),
                          branches=List(Reference(schema=IBranch),
                                        title=_('Branches'),
                                        required=False),
                          specifications=List(Reference(schema=ISpecification),
                                              title=_('Specifications'),
                                              required=False))
    @operation_for_version('devel')
    def revokeAccessGrants(pillar,
                           grantee,
                           user,
                           branches=None,
                           bugs=None,
                           specifications=None):
        """Remove a grantee's access to the specified artifacts.

        :param pillar: the pillar from which to remove access
        :param grantee: the person or team for whom to revoke access
        :param user: the user making the request
        :param bugs: the bugs for which to revoke access
        :param branches: the branches for which to revoke access
        :param specifications: the specifications for which to revoke access
        """

    @export_write_operation()
    @call_with(user=REQUEST_USER)
    @operation_parameters(grantees=List(
        Reference(IPerson, title=_('Grantee'), required=True)),
                          bugs=List(Reference(schema=IBug),
                                    title=_('Bugs'),
                                    required=False),
                          branches=List(Reference(schema=IBranch),
                                        title=_('Branches'),
                                        required=False))
    @operation_for_version('devel')
    def ensureAccessGrants(grantees,
                           user,
                           branches=None,
                           bugs=None,
                           specifications=None):
        """Ensure a grantee has an access grant to the specified artifacts.

        :param grantees: the people or teams for whom to grant access
        :param user: the user making the request
        :param bugs: the bugs for which to grant access
        :param branches: the branches for which to grant access
        :param specifications: the specifications for which to grant access
        """

    @export_write_operation()
    @operation_parameters(
        pillar=Reference(IPillar, title=_('Pillar'), required=True),
        branch_sharing_policy=Choice(vocabulary=BranchSharingPolicy),
        bug_sharing_policy=Choice(vocabulary=BugSharingPolicy),
        specification_sharing_policy=Choice(
            vocabulary=SpecificationSharingPolicy))
    @operation_for_version('devel')
    def updatePillarSharingPolicies(pillar,
                                    branch_sharing_policy=None,
                                    bug_sharing_policy=None,
                                    specification_sharing_policy=None):
        """Update the sharing policies for a pillar.
Exemple #22
0
class ITranslationImportQueue(Interface):
    """A set of files to be imported into Rosetta."""
    export_as_webservice_collection(ITranslationImportQueueEntry)

    def __iter__():
        """Iterate over all entries in the queue."""

    def __getitem__(id):
        """Return the ITranslationImportQueueEntry with the given id.

        If there is not entries with that id, the NotFoundError exception is
        raised.
        """

    def countEntries():
        """Return the number of `TranslationImportQueueEntry` records."""

    def addOrUpdateEntry(path, content, by_maintainer, importer,
        sourcepackagename=None, distroseries=None, productseries=None,
        potemplate=None, pofile=None, format=None):
        """Return a new or updated entry of the import queue.

        :arg path: is the path, with the filename, of the uploaded file.
        :arg content: is the file content.
        :arg by_maintainer: indicates if the file was uploaded by the
            maintainer of the project or package.
        :arg importer: is the person that did the import.
        :arg sourcepackagename: is the link of this import with source
            package.
        :arg distroseries: is the link of this import with a distribution.
        :arg productseries: is the link of this import with a product branch.
        :arg potemplate: is the link of this import with an IPOTemplate.
        :arg pofile: is the link of this import with an IPOFile.
        :arg format: a TranslationFileFormat.
        :return: the entry, or None if processing failed.

        The entry is either for a sourcepackage or a productseries, so
        only one of them can be specified.
        """

    def addOrUpdateEntriesFromTarball(content, by_maintainer, importer,
        sourcepackagename=None, distroseries=None, productseries=None,
        potemplate=None, filename_filter=None, approver_factory=None,
        only_templates=False):
        """Add all .po or .pot files from the tarball at :content:.

        :arg content: is a tarball stream.
        :arg by_maintainer: indicates if the file was uploaded by the
            maintainer of the project or package.
        :arg importer: is the person that did the import.
        :arg sourcepackagename: is the link of this import with source
            package.
        :arg distroseries: is the link of this import with a distribution.
        :arg productseries: is the link of this import with a product branch.
        :arg potemplate: is the link of this import with an IPOTemplate.
        :arg approver_factory: is a factory that can be called to create an
            approver.  The method invokes the approver on any queue entries
            that it creates. If this is None, no approval is performed.
        :arg only_templates: Flag to indicate that only translation templates
            in the tarball should be used.
        :return: A tuple of the number of successfully processed files and a
            list of those filenames that could not be processed correctly.

        The entries are either for a sourcepackage or a productseries, so
        only one of them can be specified.
        """

    def get(id):
        """Return the ITranslationImportQueueEntry with the given id or None.
        """

    @collection_default_content()
    @operation_parameters(
        import_status=copy_field(ITranslationImportQueueEntry['status']))
    @operation_returns_collection_of(ITranslationImportQueueEntry)
    @export_read_operation()
    def getAllEntries(target=None, import_status=None, file_extensions=None):
        """Return all entries this import queue has.

        :arg target: IPerson, IProduct, IProductSeries, IDistribution,
            IDistroSeries or ISourcePackage the import entries are attached to
            or None to get all entries available.
        :arg import_status: RosettaImportStatus entry.
        :arg file_extensions: Sequence of filename suffixes to match, usually
            'po' or 'pot'.

        If any of target, status or file_extension are given, the returned
        entries are filtered based on those values.
        """

    @export_read_operation()
    @operation_parameters(target=Reference(schema=IHasTranslationImports))
    @operation_returns_entry(ITranslationImportQueueEntry)
    def getFirstEntryToImport(target=None):
        """Return the first entry of the queue ready to be imported.

        :param target: IPerson, IProduct, IProductSeries, IDistribution,
            IDistroSeries or ISourcePackage the import entries are attached to
            or None to get all entries available.
        """

    @export_read_operation()
    @operation_parameters(
        status=copy_field(ITranslationImportQueueEntry['status']))
    @operation_returns_collection_of(IHasTranslationImports)
    @call_with(user=REQUEST_USER)
    def getRequestTargets(user,  status=None):
        """List `Product`s and `DistroSeries` with pending imports.

        :arg status: Filter by `RosettaImportStatus`.

        All returned items will implement `IHasTranslationImports`.
        """

    def executeOptimisticApprovals(txn=None):
        """Try to approve Needs-Review entries.

        :arg txn: Optional transaction manager.  If given, will be
            committed regularly.

        This method moves all entries that we know where should they be
        imported from the Needs Review status to the Accepted one.
        """

    def executeOptimisticBlock(txn=None):
        """Try to move entries from the Needs Review status to Blocked one.

        :arg txn: Optional transaction manager.  If given, will be
            committed regularly.

        This method moves uploaded translations for Blocked templates to
        the Blocked status as well.  This lets you block a template plus
        all its present or future translations in one go.

        :return: The number of items blocked.
        """

    def cleanUpQueue():
        """Remove old entries in terminal states.

        This "garbage-collects" entries from the queue based on their
        status (e.g. Deleted and Imported ones) and how long they have
        been in that status.

        :return: The number of entries deleted.
        """

    def remove(entry):
        """Remove the given :entry: from the queue."""
Exemple #23
0
class IConversation(Interface):
    """A conversation has a number of comments."""

    comments = CollectionField(value_type=Reference(schema=IComment),
                               title=_('The comments in the conversation'))
Exemple #24
0
class IBuilderSet(IBuilderSetAdmin):
    """Collections of builders.

    IBuilderSet provides access to all Builders in the system,
    and also acts as a Factory to allow the creation of new Builders.
    Methods on this interface should deal with the set of Builders:
    methods that affect a single Builder should be on IBuilder.
    """
    export_as_webservice_collection(IBuilder)
    title = Attribute('Title')

    def __iter__():
        """Iterate over builders."""

    def __getitem__(name):
        """Retrieve a builder by name"""

    @operation_parameters(name=TextLine(title=_("Builder name"),
                                        required=True))
    @operation_returns_entry(IBuilder)
    @export_read_operation()
    def getByName(name):
        """Retrieve a builder by name"""

    def count():
        """Return the number of builders in the system."""

    def get(builder_id):
        """Return the IBuilder with the given builderid."""

    @collection_default_content()
    def getBuilders():
        """Return all active configured builders."""

    @export_read_operation()
    @operation_for_version('devel')
    def getBuildQueueSizes():
        """Return the number of pending builds for each processor.

        :return: a dict of tuples with the queue size and duration for
            each processor and virtualisation. For example::

                {
                    'virt': {
                                '386': (1, datetime.timedelta(0, 60)),
                                'amd64': (2, datetime.timedelta(0, 30)),
                            },
                    'nonvirt':...
                }

            The tuple contains the size of the queue, as an integer,
            and the sum of the jobs 'estimated_duration' in queue,
            as a timedelta or None for empty queues.
        """

    @operation_parameters(processor=Reference(title=_("Processor"),
                                              required=True,
                                              schema=IProcessor),
                          virtualized=Bool(title=_("Virtualized"),
                                           required=False,
                                           default=True))
    @operation_returns_collection_of(IBuilder)
    @export_read_operation()
    @operation_for_version('devel')
    def getBuildersForQueue(processor, virtualized):
        """Return all builders for given processor/virtualization setting."""
Exemple #25
0
class ISourcePackagePublishingHistoryPublic(IPublishingView):
    """A source package publishing history record."""
    id = Int(
            title=_('ID'), required=True, readonly=True,
            )
    sourcepackagenameID = Int(
        title=_('The DB id for the sourcepackagename.'),
        required=False, readonly=False)
    sourcepackagename = Attribute('The source package name being published')
    sourcepackagereleaseID = Int(
        title=_('The DB id for the sourcepackagerelease.'),
        required=False, readonly=False)
    sourcepackagerelease = Attribute(
        'The source package release being published')
    status = exported(
        Choice(
            title=_('Package Publishing Status'),
            description=_('The status of this publishing record'),
            vocabulary=PackagePublishingStatus,
            required=False, readonly=False,
            ))
    distroseriesID = Attribute("DB ID for distroseries.")
    distroseries = exported(
        Reference(
            IDistroSeries,
            title=_('The distro series being published into'),
            required=False, readonly=False,
            ),
        exported_as="distro_series")
    component = Int(
            title=_('The component being published into'),
            required=False, readonly=False,
            )
    sectionID = Attribute("DB ID for the section")
    section = Int(
            title=_('The section being published into'),
            required=False, readonly=False,
            )
    datepublished = exported(
        Datetime(
            title=_('The date on which this record was published'),
            required=False, readonly=False,
            ),
        exported_as="date_published")
    scheduleddeletiondate = exported(
        Datetime(
            title=_('The date on which this record is scheduled for '
                    'deletion'),
            required=False, readonly=False,
            ),
        exported_as="scheduled_deletion_date")
    pocket = exported(
        Choice(
            title=_('Pocket'),
            description=_('The pocket into which this entry is published'),
            vocabulary=PackagePublishingPocket,
            required=True, readonly=True,
            ))
    archive = exported(
        Reference(
            # Really IArchive (fixed in _schema_circular_imports.py).
            Interface,
            title=_('Archive ID'), required=True, readonly=True,
            ))
    supersededby = Int(
            title=_('The sourcepackagerelease which superseded this one'),
            required=False, readonly=False,
            )
    datesuperseded = exported(
        Datetime(
            title=_('The date on which this record was marked superseded'),
            required=False, readonly=False,
            ),
        exported_as="date_superseded")
    datecreated = exported(
        Datetime(
            title=_('The date on which this record was created'),
            required=True, readonly=False,
            ),
        exported_as="date_created")
    datemadepending = exported(
        Datetime(
            title=_('The date on which this record was set as pending '
                    'removal'),
            required=False, readonly=False,
            ),
        exported_as="date_made_pending")
    dateremoved = exported(
        Datetime(
            title=_('The date on which this record was removed from the '
                    'published set'),
            required=False, readonly=False,
            ),
        exported_as="date_removed")
    removed_byID = Attribute("DB ID for removed_by.")
    removed_by = exported(
        Reference(
            IPerson,
            title=_('The IPerson responsible for the removal'),
            required=False, readonly=False,
            ))
    removal_comment = exported(
        Text(
            title=_('Reason why this publication is going to be removed.'),
            required=False, readonly=False,
        ))

    meta_sourcepackage = Attribute(
        "Return an ISourcePackage meta object correspondent to the "
        "sourcepackagerelease attribute inside a specific distroseries")
    meta_distributionsourcepackagerelease = Attribute(
        "Return an IDistributionSourcePackageRelease meta object "
        "correspondent to the sourcepackagerelease attribute inside "
        "this distribution")

    source_package_name = exported(
        TextLine(
            title=_("Source Package Name"),
            required=False, readonly=True))
    source_package_version = exported(
        TextLine(
            title=_("Source Package Version"),
            required=False, readonly=True))

    package_creator = exported(
        Reference(
            IPerson,
            title=_('Package Creator'),
            description=_('The IPerson who created the source package.'),
            required=False, readonly=True,
        ))
    package_maintainer = exported(
        Reference(
            IPerson,
            title=_('Package Maintainer'),
            description=_('The IPerson who maintains the source package.'),
            required=False, readonly=True,
        ))
    package_signer = exported(
        Reference(
            IPerson,
            title=_('Package Signer'),
            description=_('The IPerson who signed the source package.'),
            required=False, readonly=True,
        ))

    newer_distroseries_version = Attribute(
        "An `IDistroSeriosSourcePackageRelease` with a newer version of this "
        "package that has been published in the main distribution series, "
        "if one exists, or None.")

    ancestor = Reference(
         # Really ISourcePackagePublishingHistory (fixed in
         # _schema_circular_imports.py).
        Interface,
        title=_('Ancestor'),
        description=_('The previous release of this source package.'),
        required=False, readonly=True)

    creatorID = Attribute("DB ID for creator.")
    creator = exported(
        Reference(
            IPerson,
            title=_('Publication Creator'),
            description=_('The IPerson who created this publication.'),
            required=False, readonly=True
        ))

    sponsorID = Attribute("DB ID for sponsor.")
    sponsor = exported(
        Reference(
            IPerson,
            title=_('Publication sponsor'),
            description=_('The IPerson who sponsored the creation of '
                'this publication.'),
            required=False, readonly=True
        ))

    packageupload = exported(
        Reference(
            # Really IPackageUpload, fixed in _schema_circular_imports.
            Interface,
            title=_('Package upload'),
            description=_('The Package Upload that caused the creation of '
                'this publication.'),
            required=False, readonly=True
        ))

    # Really IBinaryPackagePublishingHistory, see below.
    @operation_returns_collection_of(Interface)
    @export_read_operation()
    def getPublishedBinaries():
        """Return all resulted `IBinaryPackagePublishingHistory`.

        Follow the build record and return every PUBLISHED or PENDING
        binary publishing record for any `DistroArchSeries` in this
        `DistroSeries` and in the same `IArchive` and Pocket, ordered
        by architecture tag.

        :return: a list with all corresponding publishing records.
        """

    def getBuiltBinaries():
        """Return all unique binary publications built by this source.

        Follow the build record and return every unique binary publishing
        record in the context `DistroSeries` and in the same `IArchive`
        and Pocket.

        There will be only one entry for architecture independent binary
        publications.

        :return: a list containing all unique
            `IBinaryPackagePublishingHistory`.
        """

    # Really IBuild (fixed in _schema_circular_imports.py)
    @operation_returns_collection_of(Interface)
    @export_read_operation()
    def getBuilds():
        """Return a list of `IBuild` objects in this publishing context.

        The builds are ordered by `DistroArchSeries.architecturetag`.

        :return: a list of `IBuilds`.
        """

    def getFileByName(name):
        """Return the file with the specified name.

        Only supports 'changelog' at present.
        """

    @export_read_operation()
    def changesFileUrl():
        """The .changes file URL for this source publication.

        :return: the .changes file URL for this source (a string).
        """

    @export_read_operation()
    @operation_for_version('devel')
    def changelogUrl():
        """The URL for this source package release's changelog.

        :return: the changelog file URL for this source (a string).
        """

    def createMissingBuilds(architectures_available=None, logger=None):
        """Create missing Build records for a published source.

        P-a-s should be used when accepting sources to the PRIMARY archive
        (in drescher). It explicitly ignores given P-a-s for sources
        targeted to PPAs.

        :param architectures_available: options list of `DistroArchSeries`
            that should be considered for build creation; if not given
            it will be calculated in place, all architectures for the
            context distroseries with available chroot.
        :param logger: optional context Logger object (used on DEBUG level).

        :return: a list of `Builds` created for this source publication.
        """

    def getSourceAndBinaryLibraryFiles():
        """Return a list of `LibraryFileAlias` for all source and binaries.

        All the source files and all binary files ever published to the
        same archive context are returned as a list of LibraryFileAlias
        records.

        :return: a list of `ILibraryFileAlias`.
        """

    def supersede(dominant=None, logger=None):
        """Supersede this publication.

        :param dominant: optional `ISourcePackagePublishingHistory` which is
            triggering the domination.
        :param logger: optional object to which debug information will be
            logged.
        """

    def copyTo(distroseries, pocket, archive, overrides=None, creator=None):
        """Copy this publication to another location.

        :param distroseries: The `IDistroSeries` to copy the source
            publication into.
        :param pocket: The `PackagePublishingPocket` to copy into.
        :param archive: The `IArchive` to copy the source publication into.
        :param overrides: A tuple of override data as returned from a
            `IOverridePolicy`.
        :param creator: the `IPerson` to use as the creator for the copied
            publication.
        :param packageupload: The `IPackageUpload` that caused this
            publication to be created.

        :return: a `ISourcePackagePublishingHistory` record representing the
            source in the destination location.
        """

    def getStatusSummaryForBuilds():
        """Return a summary of the build status for the related builds.

        This method augments IBuildSet.getBuildStatusSummaryForBuilds() by
        additionally checking to see if all the builds have been published
        before returning the fully-built status.

        :return: A dict consisting of the build status summary for the
            related builds. For example:
                {
                    'status': PackagePublishingStatus.PENDING,
                    'builds': [build1, build2]
                }
        """

    @export_read_operation()
    @operation_parameters(
        include_meta=Bool(title=_("Include Metadata"), required=False))
    def sourceFileUrls(include_meta=False):
        """URLs for this source publication's uploaded source files.

        :param include_meta: Return a list of dicts with keys url, size, and
            sha256 for each URL instead of a simple list.
        :return: A collection of URLs for this source.
        """

    @export_read_operation()
    def binaryFileUrls():
        """URLs for this source publication's binary files.

        :return: A collection of URLs for this source.
        """

    @export_read_operation()
    @operation_parameters(
        to_version=TextLine(title=_("To Version"), required=True))
    def packageDiffUrl(to_version):
        """URL of the debdiff file between this and the supplied version.
Exemple #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.
Exemple #27
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"""
Exemple #28
0
class ISourcePackageRelease(Interface):
    """A source package release, e.g. apache-utils 2.0.48-3"""

    id = Attribute("SourcePackageRelease identifier")
    creatorID = Attribute("DB ID of creator")
    creator = Attribute("Person that created this release")
    maintainerID = Attribute("DB ID of the maintainer")
    maintainer = Attribute("The person in general responsible for this "
        "release")
    version = Attribute("A version string")
    dateuploaded = Attribute("Date of Upload")
    urgency = Attribute("Source Package Urgency")
    signing_key_owner = Attribute("Signing key owner")
    signing_key_fingerprint = Attribute("Signing key fingerprint")
    component = Attribute("Source Package Component")
    format = Attribute("The Source Package Format")
    changelog = Attribute("LibraryFileAlias containing debian/changelog.")
    changelog_entry = Attribute("Source Package Change Log Entry")
    change_summary = Attribute(
        "The message on the latest change in this release. This is usually "
        "a snippet from the changelog")
    buildinfo = Attribute(
        "LibraryFileAlias containing build information for this source "
        "upload, if any.")
    builddepends = TextLine(
        title=_("DSC build depends"),
        description=_("A comma-separated list of packages on which this "
                      "package depends to build"),
        required=False)
    builddependsindep = TextLine(
        title=_("DSC arch-independent build depends"),
        description=_("Same as builddepends, but the list is of "
                      "arch-independent packages"),
        required=False)
    build_conflicts = TextLine(
        title=_("DSC build conflicts"),
        description=_("Binaries that will conflict when building this "
                      "source."),
        required=False)
    build_conflicts_indep = TextLine(
        title=_("DSC arch-independent build conflicts"),
        description=_("Same as build-conflicts but only lists "
                      "arch-independent binaries."),
        required=False)
    architecturehintlist = TextLine(
        title=_("Architecture Hint List"),
        description=_(
        "Architectures where this packages is supposed to be built"),
        required=True)
    dsc_maintainer_rfc822 = TextLine(
        title=_("DSC maintainers identification in RFC-822"),
        description=_(
        "Original maintainer line contained in the DSC file."),
        required=True)
    dsc_standards_version = TextLine(
        title=_("DSC Standards version"),
        description=_(
        "DSC standards version used to build this source."),
        required=True)
    dsc_format = TextLine(
        title=_("DSC format"),
        description=_(
        "DSC file format used to upload this source"),
        required=True)
    dsc_binaries = TextLine(
        title=_("DSC proposed binaries"),
        description=_(
        "Binaries claimed to be generated by this source."),
        required=True)
    dsc = Attribute("The DSC file for this SourcePackageRelease")
    copyright = Attribute(
        "Copyright information for this SourcePackageRelease, if available.")
    section = Attribute("Section this Source Package Release belongs to")
    builds = Attribute("Builds for this sourcepackagerelease excluding PPA "
        "archives.")
    files = Attribute("IBinaryPackageFile entries for this "
        "sourcepackagerelease")
    sourcepackagename = Attribute("SourcePackageName table reference")
    sourcepackagenameID = Attribute("SourcePackageName id.")
    upload_distroseries = Attribute("The distroseries in which this package "
        "was first uploaded in Launchpad")
    publishings = Attribute("MultipleJoin on SourcepackagePublishing")

    user_defined_fields = List(
        title=_("Sequence of user-defined fields as key-value pairs."))

    homepage = TextLine(
        title=_("Homepage"),
        description=_(
        "Upstream project homepage as set in the package. This URL is not "
        "sanitized."),
        required=False)

    # read-only properties
    name = Attribute('The sourcepackagename for this release, as text')
    title = Attribute('The title of this sourcepackagerelease')
    age = Attribute('Time passed since the source package release '
                    'is present in Launchpad')
    failed_builds = Attribute("A (potentially empty) list of build "
        "failures that happened for this source package " "release, or None")
    needs_building = Attribute(
        "A boolean that indicates whether this package still needs to be "
        "built (on any architecture)")

    published_archives = Attribute("A set of all the archives that this "
        "source package is published in.")
    upload_archive = Attribute(
        "The archive for which this package was first uploaded in Launchpad")

    upload_changesfile = Attribute(
        "The `LibraryFileAlias` object containing the changes file which "
        "was originally uploaded with this source package release. It's "
        "'None' if it is a source imported by Gina.")

    package_upload = Attribute(
        "The `PackageUpload` record corresponding to original upload of "
        "this source package release. It's 'None' if it is a source "
        "imported by Gina.")
    uploader = Attribute(
        "The user who uploaded the package.")

    # Really ISourcePackageRecipeBuild -- see _schema_circular_imports.
    source_package_recipe_build = Reference(
        schema=Interface,
        description=_("The `SourcePackageRecipeBuild` which produced this "
            "source package release, or None if it was created from a "
            "traditional upload."),
        title=_("Source package recipe build"),
        required=False, readonly=True)

    def getUserDefinedField(name):
        """Case-insensitively get a user-defined field."""

    def addFile(file, filetype=None):
        """Add the provided library file alias (file) to the list of files
        in this package.
        """

    def getFileByName(filename):
        """Return the corresponding `ILibraryFileAlias` in this context.

        The following file types (and extension) can be looked up in the
        SourcePackageRelease context:

         * Source files: '.orig.tar.gz', 'tar.gz', '.diff.gz' and '.dsc'.

        :param filename: the exact filename to be looked up.

        :raises NotFoundError if no file could be found.

        :return the corresponding `ILibraryFileAlias` if the file was found.
        """

    def override(component=None, section=None, urgency=None):
        """Uniform method to override sourcepackagerelease attribute.

        All arguments are optional and can be set individually. A non-passed
        argument remains untouched.
        """

    package_diffs = Attribute(
        "All `IPackageDiff` generated from this context.")

    def getDiffTo(to_sourcepackagerelease):
        """Return an `IPackageDiff` to a given `ISourcePackageRelease`.

        Return None if it was not yet requested.
        """

    def requestDiffTo(requester, to_sourcepackagerelease):
        """Request a package diff from the context source to a given source.

        :param: requester: it's the diff requester, any valid `IPerson`;
        :param: to_source: it's the `ISourcePackageRelease` to diff against.
        :raise `PackageDiffAlreadyRequested`: when there is already a
            `PackageDiff` record matching the request being made.

        :return: the corresponding `IPackageDiff` record.
        """

    def getPackageSize():
        """Get the size total (in KB) of files comprising this package.

        Please note: empty packages (i.e. ones with no files or with
        files that are all empty) have a size of zero.

        :return: total size (in KB) of this package
        """

    def aggregate_changelog(since_version):
        """Get all the changelogs since the version specified.
class IThing(Interface):
    target = Reference(schema=Interface)
Exemple #30
0
class IWebhook(Interface):

    export_as_webservice_entry(as_of='beta')

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

    target = exported(
        Reference(
            title=_("Target"),
            schema=Interface,  # Actually IWebhookTarget.
            required=True,
            readonly=True,
            description=_(
                "The object for which this webhook receives events.")))
    event_types = exported(
        List(Choice(vocabulary='ValidWebhookEventType'),
             title=_("Event types"),
             required=True,
             readonly=False))
    registrant = exported(
        Reference(title=_("Registrant"),
                  schema=IPerson,
                  required=True,
                  readonly=True,
                  description=_("The person who created this webhook.")))
    registrant_id = Int(title=_("Registrant ID"))
    date_created = exported(
        Datetime(title=_("Date created"), required=True, readonly=True))
    date_last_modified = exported(
        Datetime(title=_("Date last modified"), required=True, readonly=True))

    delivery_url = exported(
        URIField(title=_("Delivery URL"),
                 allowed_schemes=['http', 'https'],
                 required=True,
                 readonly=False))
    active = exported(
        Bool(title=_("Active"),
             description=_("Deliver details of subscribed events."),
             required=True,
             readonly=False))

    # Do not export this.
    secret = TextLine(
        title=_("Secret"),
        required=False,
        description=_(
            "An optional string used to sign delivery bodies with HMAC-SHA1 "
            "in the X-Hub-Signature header. This must be less than 200 bytes "
            "long."),
        max_length=200)

    deliveries = exported(
        doNotSnapshot(
            CollectionField(title=_("Recent deliveries for this webhook."),
                            value_type=Reference(schema=Interface),
                            readonly=True)))

    def getDelivery(id):
        """Retrieve a delivery by ID, or None if it doesn't exist."""

    @export_factory_operation(Interface, [])  # Actually IWebhookDelivery.
    @operation_for_version('devel')
    def ping():
        """Send a test event."""

    @export_destructor_operation()
    @operation_for_version('devel')
    def destroySelf():
        """Delete this webhook."""

    @export_write_operation()
    @operation_parameters(secret=copy_field(secret))
    @operation_for_version('devel')
    def setSecret(secret):
        """Set the secret used to sign deliveries."""
class ITeamMembership(Interface):
    """TeamMembership for Users.

    This table includes *direct* team members only.  Indirect memberships are
    handled by the TeamParticipation table.
    """
    export_as_webservice_entry()

    id = Int(title=_('ID'), required=True, readonly=True)
    team = exported(
        Reference(title=_("Team"),
                  required=True,
                  readonly=True,
                  schema=Interface))  # Specified in interfaces/person.py.
    person = exported(
        Reference(title=_("Member"),
                  required=True,
                  readonly=True,
                  schema=Interface),  # Specified in interfaces/person.py.
        exported_as='member')
    proposed_by = Attribute(_('Proponent'))
    reviewed_by = Attribute(
        _("The team admin who approved/rejected the member."))
    acknowledged_by = Attribute(
        _('The person (usually the member or someone acting on his behalf) '
          'that acknowledged (accepted/declined) a membership invitation.'))
    last_changed_by = exported(
        Reference(title=_('Last person who change this'),
                  required=False,
                  readonly=True,
                  schema=Interface))  # Specified in interfaces/person.py.

    datejoined = exported(Datetime(
        title=_("Date joined"),
        required=False,
        readonly=True,
        description=_("The date in which this membership was made "
                      "active for the first time.")),
                          exported_as='date_joined')
    dateexpires = exported(Datetime(title=_("Date expires"),
                                    required=False,
                                    readonly=True),
                           exported_as='date_expires')
    date_created = Datetime(
        title=_("Date created"),
        required=False,
        readonly=True,
        description=_("The date in which this membership was created."))
    date_proposed = Datetime(
        title=_("Date proposed"),
        required=False,
        readonly=True,
        description=_("The date in which this membership was proposed."))
    date_acknowledged = Datetime(
        title=_("Date acknowledged"),
        required=False,
        readonly=True,
        description=_("The date in which this membership was acknowledged by "
                      "the member (or someone acting on their behalf)."))
    date_reviewed = Datetime(
        title=_("Date reviewed"),
        required=False,
        readonly=True,
        description=_("The date in which this membership was approved/"
                      "rejected by one of the team's admins."))
    date_last_changed = Datetime(
        title=_("Date last changed"),
        required=False,
        readonly=True,
        description=_("The date in which this membership was last changed."))

    last_change_comment = exported(
        Text(title=_("Comment on the last change"),
             required=False,
             readonly=True))
    proponent_comment = Text(title=_("Proponent comment"),
                             required=False,
                             readonly=True)
    acknowledger_comment = Text(title=_("Acknowledger comment"),
                                required=False,
                                readonly=True)
    reviewer_comment = Text(title=_("Reviewer comment"),
                            required=False,
                            readonly=True)
    status = exported(
        Choice(title=_("The state of this membership"),
               required=True,
               readonly=True,
               vocabulary=TeamMembershipStatus))

    def isExpired():
        """Return True if this membership's status is EXPIRED."""

    def canChangeExpirationDate(person):
        """Can the given person change this membership's expiration date?

        A membership's expiration date can be changed by the team owner, by a
        Launchpad admin or by a team admin. In the latter case, though, the
        expiration date can only be changed if the admin is not changing his
        own membership.
        """

    @call_with(user=REQUEST_USER)
    @operation_parameters(date=copy_field(dateexpires))
    @export_write_operation()
    def setExpirationDate(date, user):
        """Set this membership's expiration date.

        The given date must be None or in the future and the given user must
        be allowed to change this membership's expiration date as per the
        rules defined in canChangeExpirationDate().
        """

    def canBeRenewedByMember():
        """Can this membership be renewed by the member himself?

        A membership can be renewed if the team's renewal policy is ONDEMAND,
        the membership itself is active (status = [ADMIN|APPROVED]) and it's
        set to expire in less than DAYS_BEFORE_EXPIRATION_WARNING_IS_SENT
        days.
        """

    def sendSelfRenewalNotification():
        """Send an email to the team admins notifying that this membership
        has been renewed by the member himself.

        This method must not be called if the team's renewal policy is not
        ONDEMAND.
        """

    def sendExpirationWarningEmail():
        """Send the member an email warning that the membership will expire.

        This method cannot be called for memberships without an expiration
        date. Emails are not sent to members if their membership has already
        expired or if the member is no longer active.

        :raises AssertionError: if the member has no expiration date of the
            team or if the TeamMembershipRenewalPolicy is AUTOMATIC.
        """

    @call_with(user=REQUEST_USER)
    @operation_parameters(status=copy_field(status),
                          comment=copy_field(reviewer_comment),
                          silent=Bool(title=_(
                              "Do not send notifications of status change.  "
                              "For use by Launchpad administrators only."),
                                      required=False,
                                      default=False))
    @export_write_operation()
    def setStatus(status, user, comment=None, silent=False):
        """Set the status of this membership.
Exemple #32
0
class IWebhookDeliveryJob(IRunnableJob):
    """A Job that delivers an event to a webhook consumer."""

    export_as_webservice_entry('webhook_delivery', as_of='beta')

    webhook = exported(
        Reference(title=_("Webhook"),
                  description=_("The webhook that this delivery is for."),
                  schema=IWebhook,
                  required=True,
                  readonly=True))

    pending = exported(
        Bool(title=_("Pending"),
             description=_("Whether a delivery attempt is in progress."),
             required=True,
             readonly=True))

    successful = exported(
        Bool(
            title=_("Successful"),
            description=_(
                "Whether the most recent delivery attempt succeeded, or null if "
                "no attempts have been made yet."),
            required=False,
            readonly=True))

    error_message = exported(
        TextLine(
            title=_("Error message"),
            description=_(
                "Details of the error encountered by the most recent delivery "
                "attempt."),
            required=False,
            readonly=True))

    date_created = exported(
        Datetime(title=_("Date created"), required=True, readonly=True))

    date_scheduled = exported(
        Datetime(title=_("Date scheduled"),
                 description=_("Timestamp of the next delivery attempt."),
                 required=False,
                 readonly=True))

    date_first_sent = exported(
        Datetime(title=_("Date first sent"),
                 description=_("Timestamp of the first delivery attempt."),
                 required=False,
                 readonly=True))

    date_sent = exported(
        Datetime(title=_("Date sent"),
                 description=_("Timestamp of the last delivery attempt."),
                 required=False,
                 readonly=True))

    event_type = exported(
        TextLine(title=_('Event type'), required=True, readonly=True))

    payload = exported(
        Dict(title=_('Event payload'),
             key_type=TextLine(),
             required=True,
             readonly=True))

    @export_write_operation()
    @operation_parameters(reset=Bool(
        title=_("Reset automatic retries"),
        description=_(
            "Restart the 24 hour automatic retry window as well as trying "
            "again now.")))
    @operation_for_version("devel")
    def retry(reset=False):
        """Attempt to deliver the event again.