~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# Copyright 2009 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

# pylint: disable-msg=E0211,E0213

"""ArchiveSubscriber interface."""

__metaclass__ = type

__all__ = [
    'ArchiveSubscriptionError',
    'IArchiveSubscriber',
    'IArchiveSubscriberSet',
    'IPersonalArchiveSubscription',
    ]

from lazr.restful.declarations import (
    export_as_webservice_entry,
    exported,
    )
from lazr.restful.fields import Reference
from zope.interface import (
    Attribute,
    Interface,
    )
from zope.schema import (
    Choice,
    Datetime,
    Int,
    Text,
    TextLine,
    )

from canonical.launchpad import _
from lp.registry.interfaces.person import IPerson
from lp.services.fields import PersonChoice
from lp.soyuz.enums import ArchiveSubscriberStatus
from lp.soyuz.interfaces.archive import IArchive


class ArchiveSubscriptionError(Exception):
    """Raised for various errors when creating and activating subscriptions.
    """


class IArchiveSubscriberView(Interface):
    """An interface for launchpad.View ops on archive subscribers."""

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

    archive = exported(Reference(
        IArchive, title=_("Archive"), required=True, readonly=True,
        description=_("The archive for this subscription.")))

    registrant = exported(Reference(
        IPerson, title=_("Registrant"), required=True, readonly=True,
        description=_("The person who registered this subscription.")))

    date_created = exported(Datetime(
        title=_("Date Created"), required=True, readonly=True,
        description=_("The timestamp when the subscription was created.")))

    subscriber = exported(PersonChoice(
        title=_("Subscriber"), required=True, readonly=True,
        vocabulary='ValidPersonOrTeam',
        description=_("The person who is subscribed.")))
    subscriber_id = Attribute('database ID of the subscriber.')

    date_expires = exported(Datetime(
        title=_("Date of Expiration"), required=False,
        description=_("The timestamp when the subscription will expire.")))

    status = exported(Choice(
        title=_("Status"), required=True,
        vocabulary=ArchiveSubscriberStatus,
        description=_("The status of this subscription.")))

    description = exported(Text(
        title=_("Description"), required=False,
        description=_("Free text describing this subscription.")))

    date_cancelled = Datetime(
        title=_("Date of Cancellation"), required=False,
        description=_("The timestamp when the subscription was cancelled."))

    cancelled_by = Reference(
        IPerson, title=_("Cancelled By"), required=False,
        description=_("The person who cancelled the subscription."))

    displayname = TextLine(title=_("Subscription displayname"),
        required=False)

    def getNonActiveSubscribers():
        """Return the people included in this subscription.

        :return: a storm `ResultSet` of all the people and their preferred
            email address who are included in this subscription who do not
            yet have an active token for the corresponding archive.

            Persons with no preferred email addresses are not included.
        :rtype: `storm.store.ResultSet`
        """


class IArchiveSubscriberEdit(Interface):
    """An interface for launchpad.Edit ops on archive subscribers."""

    def cancel(cancelled_by):
        """Cancel a subscription.

        :param cancelled_by: An `IPerson` who is cancelling the subscription.

        Sets cancelled_by to the supplied person and date_cancelled to
        the current date/time.
        """


class IArchiveSubscriber(IArchiveSubscriberView, IArchiveSubscriberEdit):
    """An interface for archive subscribers."""
    export_as_webservice_entry()


class IArchiveSubscriberSet(Interface):
    """An interface for the set of all archive subscribers."""

    def getBySubscriber(subscriber, archive=None, current_only=True):
        """Return all the subscriptions for a person.

        :param subscriber: An `IPerson` for whom to return all
            `ArchiveSubscriber` records.
        :param archive: An optional `IArchive` which restricts
            the results to that particular archive.
        :param current_only: Whether the result should only include current
            subscriptions (which is the default).
        """

    def getBySubscriberWithActiveToken(subscriber, archive=None):
        """Return all the subscriptions for a person with the correspending
        token for each subscription.

        :param subscriber: An `IPerson` for whom to return all
            `ArchiveSubscriber` records.
        :param archive: An optional `IArchive` which restricts
            the results to that particular archive.
        :return: a storm `ResultSet` of
            (`IArchiveSubscriber`, `IArchiveAuthToken` or None) tuples.
        """

    def getByArchive(archive, current_only=True):
        """Return all the subscripions for an archive.

        :param archive: An `IArchive` for which to return all
            `ArchiveSubscriber` records.
        :param current_only: Whether the result should only include current
            subscriptions (which is the default).
        """


class IPersonalArchiveSubscription(Interface):
    """An abstract interface representing a subscription for an individual.

    An individual may be subscribed via a team, but should only ever be
    able to navigate and activate one token for their individual person.
    This non-db class allows a traversal for an individual's subscription
    to a p3a, irrespective of whether the ArchiveSubscriber records linking
    this individual to the archive are for teams or individuals.
    """
    subscriber = Reference(
        IPerson, title=_("Person"), required=True, readonly=True,
        description=_("The person for this individual subscription."))

    archive = Reference(
        IArchive, title=_("Archive"), required=True,
        description=_("The archive for this subscription."))

    displayname = TextLine(title=_("Subscription displayname"),
        required=False)

    title = TextLine(title=_("Subscription title"),
        required=False)