class _DependencyConnector(Item):
    """
    I am a connector between installed items and their targets.
    """
    installee = reference(doc="The item installed.")
    target = reference(doc="The item installed upon.")
    explicitlyInstalled = boolean(doc="Whether this item was installed"
                                  "explicitly (and thus whether or not it"
                                  "should be automatically uninstalled when"
                                  "nothing depends on it)")
Example #2
0
class _PowerupConnector(Item):
    """
    I am a connector between the store and a powerup.
    """
    typeName = 'axiom_powerup_connector'

    powerup = reference()
    item = reference()
    interface = text()
    priority = integer()
Example #3
0
class LoginMethod(Item):
    typeName = 'login_method'
    schemaVersion = 2

    localpart = text(doc="""
    A local-part of my user's identifier.
    """, indexed=True, allowNone=False)

    domain = text(doc="""
    The domain part of my user's identifier. [XXX See TODO below]
    May be None (generally for "system" users).
    """, indexed=True)

    internal = boolean(doc="""
    Flag indicating whether this is a method maintained by this server, or if
    it represents an external contact mechanism (such as a third-party email
    provider)
    """, allowNone=False)

    protocol = text(indexed=True, allowNone=False)
    account = reference(doc="""
    A reference to the LoginAccount for which this is a login method.
    """, allowNone=False)

    verified = boolean(indexed=True, allowNone=False)
Example #4
0
class TimedEventFailureLog(Item):
    typeName = 'timed_event_failure_log'
    schemaVersion = 1

    desiredTime = timestamp()
    actualTime = timestamp()

    runnable = reference()
    traceback = bytes()
Example #5
0
class SubStoreStartupService(Item, service.Service):
    """
    This class no longer exists.  It is here simply to trigger an upgrade which
    deletes it.  Ignore it, please.
    """
    installedOn = reference()
    parent = inmemory()
    running = inmemory()
    name = inmemory()

    schemaVersion = 2
Example #6
0
class TimedEvent(Item):
    typeName = 'timed_event'
    schemaVersion = 1

    time = timestamp(indexed=True)
    runnable = reference()

    def _rescheduleFromRun(self, newTime):
        """
        Schedule this event to be run at the indicated time, or if the
        indicated time is None, delete this event.
        """
        if newTime is None:
            self.deleteFromStore()
        else:
            self.time = newTime

    def invokeRunnable(self):
        """
        Run my runnable, and reschedule or delete myself based on its result.
        Must be run in a transaction.
        """
        runnable = self.runnable
        if runnable is None:
            self.deleteFromStore()
        else:
            self._rescheduleFromRun(runnable.run())

    def handleError(self, now, failureObj):
        """ An error occurred running my runnable.  Check my runnable for an
        error-handling method called 'timedEventErrorHandler' that will take
        the given failure as an argument, and execute that if available:
        otherwise, create a TimedEventFailureLog with information about what
        happened to this event.

        Must be run in a transaction.
        """
        errorHandler = getattr(self.runnable, 'timedEventErrorHandler', None)
        if errorHandler is not None:
            self._rescheduleFromRun(errorHandler(self, failureObj))
        else:
            self._defaultErrorHandler(now, failureObj)

    def _defaultErrorHandler(self, now, failureObj):
        tefl = TimedEventFailureLog(store=self.store,
                                    desiredTime=self.time,
                                    actualTime=now,
                                    runnable=self.runnable,
                                    traceback=failureObj.getTraceback())
        self.deleteFromStore()
Example #7
0
class Tag(Item):
    typeName = 'tag'
    schemaVersion = 1

    name = text(doc="""
    The short string which is being applied as a tag to an Item.
    """)

    created = timestamp(doc="""
    When this tag was applied to the Item to which it applies.
    """)

    object = reference(doc="""
    The Item to which this tag applies.
    """)

    catalog = reference(doc="""
    The L{Catalog} item in which this tag was created.
    """)

    tagger = reference(doc="""
    An optional reference to the Item which is responsible for this tag's
    existence.
    """)
Example #8
0
class _TagName(Item):
    """
    Helper class to make Catalog.tagNames very fast.  One of these is created
    for each distinct tag name that is created.  _TagName Items are never
    deleted from the database.
    """
    typeName = 'tagname'

    name = text(doc="""
    The short string which uniquely represents this tag.
    """,
                indexed=True)

    catalog = reference(doc="""
    The L{Catalog} item in which this tag exists.
    """)
Example #9
0
class _SubSchedulerParentHook(Item):
    schemaVersion = 2
    typeName = 'axiom_subscheduler_parent_hook'

    loginAccount = reference()
    scheduledAt = timestamp(default=None)

    scheduler = dependsOn(Scheduler)

    def run(self):
        self.scheduledAt = None
        IScheduler(self.loginAccount).tick()

    def _schedule(self, when):
        if self.scheduledAt is not None:
            if when < self.scheduledAt:
                self.scheduler.reschedule(self, self.scheduledAt, when)
                self.scheduledAt = when
        else:
            self.scheduler.schedule(self, when)
            self.scheduledAt = when
def dependsOn(itemType, itemCustomizer=None, doc='',
              indexed=True, whenDeleted=reference.NULLIFY):
    """
    This function behaves like L{axiom.attributes.reference} but with
    an extra behaviour: when this item is installed (via
    L{axiom.dependency.installOn} on a target item, the
    type named here will be instantiated and installed on the target
    as well.
    
    For example::

      class Foo(Item):
          counter = integer()
          thingIDependOn = dependsOn(Baz, lambda baz: baz.setup())

    @param itemType: The Item class to instantiate and install.
    @param itemCustomizer: A callable that accepts the item installed
    as a dependency as its first argument. It will be called only if
    an item is created to satisfy this dependency.

    @return: An L{axiom.attributes.reference} instance.
    """

    frame = sys._getframe(1)
    locals = frame.f_locals

    # Try to make sure we were called from a class def.
    if (locals is frame.f_globals) or ('__module__' not in locals):
        raise TypeError("dependsOn can be used only from a class definition.")
    ref = reference(reftype=itemType, doc=doc, indexed=indexed, allowNone=True,
                    whenDeleted=whenDeleted)
    if "__dependsOn_advice_data__" not in locals:
        addClassAdvisor(_dependsOn_advice)
    locals.setdefault('__dependsOn_advice_data__', []).append(
    (itemType, itemCustomizer, ref))
    return ref
Example #11
0
class LoginAccount(Item):
    """
    I am an entry in a LoginBase.

    @ivar avatars: An Item which is adaptable to various cred client
    interfaces.  Plural because it represents a collection of potentially
    disparate implementors, such as an IResource for web access and an IContact
    for SIP access.

    @ivar disabled: This account has been disabled.  It is still
    database-resident but the user should not be allowed to log in.

    """
    typeName = 'login'
    schemaVersion = 2

    password = text()
    avatars = reference()       # reference to a thing which can be adapted to
                                # implementations for application-level
                                # protocols.  In general this is a reference to
                                # a SubStore because this is optimized for
                                # applications where per-user data is a
                                # substantial portion of the cost.
    disabled = integer()


    def __conform__(self, interface):
        """
        For convenience, forward adaptation to my 'avatars' attribute.
        """
        ifa = interface(self.avatars, None)
        return ifa

    def migrateDown(self):
        """
        Assuming that self.avatars is a SubStore which should contain *only*
        the LoginAccount for the user I represent, remove all LoginAccounts and
        LoginMethods from that store and copy all methods from the site store
        down into it.
        """
        ss = self.avatars.open()
        def _():
            oldAccounts = ss.query(LoginAccount)
            oldMethods = ss.query(LoginMethod)
            for x in list(oldAccounts) + list(oldMethods):
                x.deleteFromStore()
            self.cloneInto(ss, ss)
            sched = IScheduler(ss, None)
            if sched is not None:
                sched.migrateDown()
        ss.transact(_)

    def migrateUp(self):
        """
        Copy this LoginAccount and all associated LoginMethods from my store
        (which is assumed to be a SubStore, most likely a user store) into the
        site store which contains it.
        """
        siteStore = self.store.parent
        def _():
            # No convenience method for the following because needing to do it is
            # *rare*.  It *should* be ugly; 99% of the time if you need to do this
            # you're making a mistake. -glyph
            siteStoreSubRef = siteStore.getItemByID(self.store.idInParent)
            self.cloneInto(siteStore, siteStoreSubRef)
            sched = IScheduler(self.store, None)
            if sched is not None:
                sched.migrateUp()
        siteStore.transact(_)

    def cloneInto(self, newStore, avatars):
        """
        Create a copy of this LoginAccount and all associated LoginMethods in a different Store.

        Return the copied LoginAccount.
        """
        la = LoginAccount(store=newStore,
                          password=self.password,
                          avatars=avatars,
                          disabled=self.disabled)
        for siteMethod in self.store.query(LoginMethod,
                                           LoginMethod.account == self):
            lm = LoginMethod(store=newStore,
                             localpart=siteMethod.localpart,
                             domain=siteMethod.domain,
                             internal=siteMethod.internal,
                             protocol=siteMethod.protocol,
                             verified=siteMethod.verified,
                             account=la)
        return la

    def deleteLoginMethods(self):
        self.store.query(LoginMethod, LoginMethod.account == self).deleteFromStore()


    def addLoginMethod(self, localpart, domain, protocol=ANY_PROTOCOL, verified=False, internal=False):
        """
        Add a login method to this account, propogating up or down as necessary
        to site store or user store to maintain consistency.
        """
        # Out takes you west or something
        if self.store.parent is None:
            # West takes you in
            otherStore = self.avatars.open()
            peer = otherStore.findUnique(LoginAccount)
        else:
            # In takes you east
            otherStore = self.store.parent
            subStoreItem = self.store.parent.getItemByID(self.store.idInParent)
            peer = otherStore.findUnique(LoginAccount,
                                         LoginAccount.avatars == subStoreItem)

        # Up and down take you home
        for store, account in [(otherStore, peer), (self.store, self)]:
            store.findOrCreate(LoginMethod,
                               account=account,
                               localpart=localpart,
                               domain=domain,
                               protocol=protocol,
                               verified=verified,
                               internal=internal)