2
# This module is part of the Quotient project and is Copyright 2003 Divmod:
3
# http://www.divmod.org/. This is free software. You can redistribute it
4
# and/or modify it under the terms of version 2.1 of the GNU Lesser General
5
# Public License as published by the Free Software Foundation.
7
from twisted.python.components import Interface, registerAdapter
8
from quotient.util import ItemForwardingComponent
10
class NotEnoughFuel(Exception):
11
"""I could not perform the task you asked for!
15
"""I am a tanker full of fuel.
17
# TODO: overdraft mode?
22
def addTanks(self, newTanks):
23
"""Add a dict of new 'full tank' values to this tanker.
25
self.tankSizes.update(newTanks)
26
self.fuel.update(newTanks)
29
"""This should be called during the monthly provision update tick.
33
self.fuel.update(self.tankSizes)
35
def deplete(self, tankName, amount, dontRaise=False):
36
val = self.fuel[tankName] - amount
43
self.fuel[tankName] = val
49
administrativeSuspension = 0
55
for k in self.permissions.keys():
56
self.permissions[k] -= 1
57
if not self.permissions[k]:
58
del self.permissions[k]
60
def check(self, permissionName, dontRaise=False):
61
if self.permissions.get(permissionName) and not self.administrativeSuspension:
67
def addPermission(self, newPermission, months):
68
if self.permissions.has_key(newPermission):
69
self.permissions[newPermission] += months
71
self.permissions[newPermission] = months + self.gracePeriod
74
"""I am a collection of services that have been pre-paid over some amount of time.
76
def __init__(self, months):
81
def addFeature(self, name, amount=0.):
82
self.permissions.append(name)
84
self.fueltanks[name] = amount
86
def grantTo(self, prov):
87
"""Grant this feature package to a provisioner.
89
for permission in self.permissions:
90
prov.permissioner.addPermission(permission, self.months)
91
prov.fueltanker.addTanks(self.fueltanks)
93
class IProvisionable(Interface):
94
property("tankID", doc="""
95
Return an identifier for the tank which this object consumes from.
98
property("startCost", doc="""
99
Return the amount of fuel consumed from the tank identified by tankID
100
before this provisionable will allow itself to be run, instantiated,
104
class IProvisioner(Interface):
105
"""Interface spec for Provisioner class.
108
class Provisioner(Powerup):
109
"""I am a collection of knowledge about what services the user has paid
112
TODO: alert the user when things are about to run out.
115
__implements__ = IProvisioner
117
def __init__(self, store):
118
self.permissioner = Permissioner()
119
self.fueltanker = FuelTanker()
120
Powerup.__init__(self, store)
122
def setUpPools(self, avatar):
123
avatar.setComponent(IProvisioner, FwdProvisioner(self.referenceTo()))
125
def check(self, featureName, dontRaise=False):
127
return self.permissioner.check(featureName, dontRaise)
129
def deplete(self, featureName, amount, dontRaise=False):
131
if self.check(featureName, dontRaise):
132
return self.fueltanker.deplete(featureName, amount, dontRaise)
135
raise NotEnoughFuel()
138
"""This should be called once per month.
141
self.fueltanker.refuel()
142
self.permissioner.tick()
144
def provision(self, provisionable):
146
return self.deplete(provisionable.tankID, provisionable.startCost, False)
148
class FwdProvisioner(ItemForwardingComponent):
149
__implements__ = IProvisioner
151
# Some canonical names.
154
"""Collection of names of permissions (features which are set on an on/off
158
IMAP4_LOGIN = "imap4-login"
159
POP3_LOGIN = "pop3-login"
160
WEB_LOGIN = "web-login"
161
CALENDAR = "calendar"
162
ADDRESSBOOK = "addressbook"
163
SMTP_SEND = "smtp-send"
165
TELEPHONY_SEND = "outgoing-calls"
166
TELEPHONY_RECEIVE = "incoming-calls"
169
"""Collection of names of tanks (features which have a certain amount of
173
EXTRACTION = "extraction"
174
CLASSIFICATION = "classification"
175
INDEXING = "indexing"
178
oneYearService = FeaturePackage(12)
179
for permissionFeature in (EPermission.WEB_LOGIN,
180
EPermission.IMAP4_LOGIN,
181
EPermission.POP3_LOGIN,
182
EPermission.ADDRESSBOOK,
183
EPermission.SMTP_SEND):
184
oneYearService.addFeature(permissionFeature)
186
for tankFeature in (ETank.EXTRACTION,
187
ETank.CLASSIFICATION,
189
# 20 CPU minutes per month for each feature
190
oneYearService.addFeature(tankFeature, 20. * 60.)
192
# 50 MB plaintext storage per user per month - this is what SMTP should use (it
194
oneYearService.addFeature(ETank.QUOTA, 1024 * 1024 * 50)
196
# 100 outgoing calls, unlimited incoming calls
197
oneYearService.addFeature(ETank.QUOTA, 100)
200
class ProvisionedPowerup(Powerup):
201
dependencies = [Provisioner]
202
def setUpPools(self, avatar):
203
prov = IProvisioner(avatar)