from itertools import chain
from twisted.python.reflect import namedAny, qual
from twisted.python.components import registerAdapter
from axiom.item import Item
from axiom.attributes import textlist, integer, boolean
from axiom.dependency import installOn, uninstallFrom, installedRequirements
from nevow import athena, tags
from nevow.page import renderer
from xmantissa.suspension import unsuspendTabProviders
from xmantissa.ixmantissa import INavigableElement, INavigableFragment
from xmantissa import liveform
from xmantissa.offering import getInstalledOfferings
from xmantissa.webnav import Tab
from zope.interface import implements
class Product(Item):
"""
I represent a collection of powerups to install on a user store. When a
user is to be endowed with the functionality described here, an
Installation is created in its store based on me.
"""
types = textlist()
def installProductOn(self, userstore):
"""
Creates an Installation in this user store for our collection
of powerups, and then install those powerups on the user's
store.
"""
def install():
i = Installation(store=userstore)
i.types = self.types
i.install()
userstore.transact(install)
def removeProductFrom(self, userstore):
"""
Uninstall all the powerups this product references and remove
the Installation item from the user's store. Doesn't remove
the actual powerups currently, but /should/ reactivate them if
this product is reinstalled.
"""
def uninstall():
#this is probably highly insufficient, but i don't know the
#requirements
i = userstore.findFirst(Installation,
Installation.types == self.types)
i.uninstall()
i.deleteFromStore()
userstore.transact(uninstall)
def installOrResume(self, userstore):
"""
Install this product on a user store. If this product has been
installed on the user store already and the installation is suspended,
it will be resumed. If it exists and is not suspended, an error will be
raised.
"""
for i in userstore.query(Installation, Installation.types == self.types):
if i.suspended:
unsuspendTabProviders(i)
return
else:
raise RuntimeError("installOrResume called for an"
" installation that isn't suspended")
else:
self.installProductOn(userstore)
class Installation(Item):
"""
I represent a collection of functionality installed on a user store. I
reference a collection of powerups, probably designated by a Product.
"""
types = textlist()
_items = textlist()
suspended = boolean(default=False)
def items(self):
"""
Loads the items this Installation refers to.
"""
for id in self._items:
yield self.store.getItemByID(int(id))
items = property(items)
def allPowerups(self):
return set(chain(self.items, *[installedRequirements(self.store, i) for
i in self.items]))
allPowerups = property(allPowerups)
def install(self):
"""
Called when installed on the user store. Installs my powerups.
"""
items = []
for typeName in self.types:
it = self.store.findOrCreate(namedAny(typeName))
installOn(it, self.store)
items.append(str(it.storeID).decode('ascii'))
self._items = items
def uninstall(self):
"""
Called when uninstalled from the user store. Uninstalls all my
powerups.
"""
for item in self.items:
uninstallFrom(item, self.store)
self._items = []
class ProductConfiguration(Item):
implements(INavigableElement)
attribute = integer(doc="It is an attribute")
powerupInterfaces = (INavigableElement,)
def getTabs(self):
return [Tab('Admin', self.storeID, 0.5,
[Tab('Products', self.storeID, 0.6)],
authoritative=False)]
def createProduct(self, powerups):
types = [qual(powerup).decode('ascii')
for powerup in powerups]
for p in self.store.parent.query(Product):
for t in types:
if t in p.types:
raise ValueError("%s is already included in a Product" % (t,))
Product(store=self.store.parent,
types=types)
return u'Created.'
class ProductFragment(athena.LiveElement):
fragmentName = 'product-configuration'
live = 'athena'
def __init__(self, configger):
athena.LiveElement.__init__(self)
self.original = configger
def head(self):
#XXX put this in its own CSS file?
return tags.style(type='text/css')['''
input[name=linktext], input[name=subject], textarea[name=blurb] { width: 40em }
''']
def getInstallablePowerups(self):
for installedOffering in getInstalledOfferings(self.original.store.parent).itervalues():
for p in installedOffering.installablePowerups:
yield p
def coerceProduct(self, **kw):
return self.original.createProduct(filter(None, kw.values()))
def makePowerupCoercer(self, powerup):
def powerupCoercer(selectedPowerup):
if selectedPowerup:
return powerup
else:
return None
return powerupCoercer
def makePowerupSelector(self, desc):
return liveform.Parameter('selectedPowerup',
liveform.CHECKBOX_INPUT,
bool, desc)
def powerupConfigurationParameter(self, (name, desc, p)):
return liveform.Parameter(
name,
liveform.FORM_INPUT,
liveform.LiveForm(self.makePowerupCoercer(p),
[self.makePowerupSelector(desc)],
name))
def productConfigurationForm(self, request, tag):
productList = liveform.LiveForm(self.coerceProduct,
[self.powerupConfigurationParameter(pi)
for pi in self.getInstallablePowerups()],
u"Installable Powerups")
productList.setFragmentParent(self)
return productList
renderer(productConfigurationForm)
def configuredProducts(self, request, tag):
for prod in self.original.store.parent.query(Product):
yield repr(prod.types)
renderer(configuredProducts)
registerAdapter(ProductFragment, ProductConfiguration, INavigableFragment)
syntax highlighted by Code2HTML, v. 0.9.1