Beispiel #1
0
class AddressJoiner3(SQLObject):

    zip = StringCol(length=5)
    personJoiner3 = ForeignKey('PersonJoiner3')

    def _get_personJoiner3(self):
        value = self._SO_get_personJoiner3()
        _personJoiner3_getters.append((self, value))
        return value

    def _set_personJoiner3(self, value):
        self._SO_set_personJoiner3(value)
        _personJoiner3_setters.append((self, value))
class _CodeImportEventData(SQLBase):
    """Additional data associated to a CodeImportEvent.

    This class is for internal use only. This data should be created by
    CodeImportEventSet event creation methods, and should be accessed by
    CodeImport methods.
    """

    _table = 'CodeImportEventData'

    event = ForeignKey(dbName='event', foreignKey='CodeImportEvent')
    data_type = EnumCol(enum=CodeImportEventDataType, notNull=True)
    data_value = StringCol()
Beispiel #3
0
class LogStat(ICTVObject):
    logger_name = StringCol(notNone=True, alternateID=True, length=50)
    last_debug = DateTimeCol(default=None)
    last_info = DateTimeCol(default=None)
    last_warning = DateTimeCol(default=None)
    last_error = DateTimeCol(default=None)
    n_entries = IntCol(notNone=True, default=0)

    @property
    def last_activity(self):
        infos = [
            i for i in [
                self.last_debug, self.last_info, self.last_warning,
                self.last_error
            ] if i is not None
        ]
        return max(infos) if infos else None

    @classmethod
    def dump_log_stats(cls, log_stats):
        for name, stats in log_stats.items():
            try:
                log_stat = LogStat.byLogger_name(name)
            except SQLObjectNotFound:
                log_stat = LogStat(logger_name=name)
            for attr_name, stat_name in [("last_debug", "DEBUG"),
                                         ("last_info", "INFO"),
                                         ("last_warning", "WARNING"),
                                         ("last_error", "ERROR"),
                                         ("n_entries", "n_entries")]:
                try:
                    setattr(log_stat, attr_name, stats[stat_name])
                except KeyError:
                    setattr(log_stat, attr_name,
                            None if attr_name != "n_entries" else 0)

    @classmethod
    def load_log_stats(cls):
        result = {}
        for log_stat in LogStat.select():
            result[log_stat.logger_name] = {}
            for attr_name, stat_name in [("last_debug", "DEBUG"),
                                         ("last_info", "INFO"),
                                         ("last_warning", "WARNING"),
                                         ("last_error", "ERROR"),
                                         ("last_activity", "last_activity"),
                                         ("n_entries", "n_entries")]:
                if getattr(log_stat, attr_name) is not None:
                    result[log_stat.logger_name][stat_name] = getattr(
                        log_stat, attr_name)
        return result
Beispiel #4
0
class BugAttachment(SQLBase):
    """A bug attachment."""

    _table = 'BugAttachment'

    bug = ForeignKey(
        foreignKey='Bug', dbName='bug', notNull=True)
    type = EnumCol(
        schema=BugAttachmentType, notNull=True,
        default=IBugAttachment['type'].default)
    title = StringCol(notNull=True)
    libraryfile = ForeignKey(
        foreignKey='LibraryFileAlias', dbName='libraryfile', notNull=True)
    data = ForeignKey(
        foreignKey='LibraryFileAlias', dbName='libraryfile', notNull=True)
    _message = ForeignKey(
        foreignKey='Message', dbName='message', notNull=True)

    @cachedproperty
    def message(self):
        """This is a cachedproperty to allow message to be an IIndexedMessage.

        This is needed for the bug/attachments API call which needs to index
        an IIndexedMessage rather than a simple DB model IMessage. See
        Bug.attachments where the injection occurs.
        """
        return self._message

    @property
    def is_patch(self):
        """See IBugAttachment."""
        return self.type == BugAttachmentType.PATCH

    def removeFromBug(self, user):
        """See IBugAttachment."""
        notify(ObjectDeletedEvent(self, user))
        self.destroySelf()

    def destroySelf(self):
        """See IBugAttachment."""
        # Delete the reference to the LibraryFileContent record right now,
        # in order to avoid problems with not deleted files as described
        # in bug 387188.
        self.libraryfile.content = None
        super(BugAttachment, self).destroySelf()

    def getFileByName(self, filename):
        """See IBugAttachment."""
        if filename == self.libraryfile.filename:
            return self.libraryfile
        raise NotFoundError(filename)
class PersonNotification(SQLBase):
    """See `IPersonNotification`."""

    person = ForeignKey(dbName='person', notNull=True, foreignKey='Person')
    date_created = UtcDateTimeCol(notNull=True, default=UTC_NOW)
    date_emailed = UtcDateTimeCol(notNull=False)
    body = StringCol(notNull=True)
    subject = StringCol(notNull=True)

    @cachedproperty
    def to_addresses(self):
        """See `IPersonNotification`."""
        if self.person.is_team:
            return self.person.getTeamAdminsEmailAddresses()
        elif self.person.preferredemail is None:
            return []
        else:
            return [
                format_address(self.person.displayname,
                               self.person.preferredemail.email)
            ]

    @property
    def can_send(self):
        """See `IPersonNotification`."""
        return len(self.to_addresses) > 0

    def send(self, logger=None):
        """See `IPersonNotification`."""
        if not self.can_send:
            raise AssertionError(
                "Can't send a notification to a person without an email.")
        to_addresses = self.to_addresses
        if logger:
            logger.info("Sending notification to %r." % to_addresses)
        from_addr = config.canonical.bounce_address
        simple_sendmail(from_addr, to_addresses, self.subject, self.body)
        self.date_emailed = datetime.now(pytz.timezone('UTC'))
Beispiel #6
0
class RevisionAuthor(SQLBase):

    _table = 'RevisionAuthor'

    name = StringCol(notNull=True, alternateID=True)

    @property
    def name_without_email(self):
        """Return the name of the revision author without the email address.

        If there is no name information (i.e. when the revision author only
        supplied their email address), return None.
        """
        if '@' not in self.name:
            return self.name
        return email.utils.parseaddr(self.name)[0]

    email = StringCol(notNull=False, default=None)
    person = ForeignKey(dbName='person',
                        foreignKey='Person',
                        notNull=False,
                        storm_validator=validate_public_person,
                        default=None)

    def linkToLaunchpadPerson(self):
        """See `IRevisionAuthor`."""
        if self.person is not None or self.email is None:
            return False
        lp_email = getUtility(IEmailAddressSet).getByEmail(self.email)
        # If not found, we didn't link this person.
        if lp_email is None:
            return False
        # Only accept an email address that is validated.
        if lp_email.status != EmailAddressStatus.NEW:
            self.personID = lp_email.personID
            return True
        else:
            return False
Beispiel #7
0
class BinaryPackageName(SQLBase):

    implements(IBinaryPackageName)
    _table = 'BinaryPackageName'
    name = StringCol(dbName='name',
                     notNull=True,
                     unique=True,
                     alternateID=True)

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return "<BinaryPackageName at %X name=%r>" % (id(self), self.name)
Beispiel #8
0
class Processor(SQLBase):
    _table = 'Processor'

    name = StringCol(dbName='name', notNull=True)
    title = StringCol(dbName='title', notNull=True)
    description = StringCol(dbName='description', notNull=True)
    restricted = Bool(allow_none=False, default=False)

    # When setting this to true you may want to add missing
    # ArchiveArches.
    build_by_default = Bool(allow_none=False, default=False)

    # This controls build creation, so you may want to create or cancel
    # some builds after changing it on an existing processor.
    supports_virtualized = Bool(allow_none=False, default=False)

    # Queued and failed builds' BuildQueue.virtualized and
    # BinaryPackageBuild.virtualized may need tweaking if this is
    # changed on an existing processor.
    supports_nonvirtualized = Bool(allow_none=False, default=True)

    def __repr__(self):
        return "<Processor %r>" % self.title
Beispiel #9
0
class MirrorCDImageDistroSeries(SQLBase):
    """See IMirrorCDImageDistroSeries"""

    implements(IMirrorCDImageDistroSeries)
    _table = 'MirrorCDImageDistroSeries'
    _defaultOrder = 'id'

    distribution_mirror = ForeignKey(dbName='distribution_mirror',
                                     foreignKey='DistributionMirror',
                                     notNull=True)
    distroseries = ForeignKey(dbName='distroseries',
                              foreignKey='DistroSeries',
                              notNull=True)
    flavour = StringCol(notNull=True)
Beispiel #10
0
class Country(SQLBase):
    """A country."""

    implements(ICountry)

    _table = 'Country'

    # default to listing newest first
    _defaultOrder = 'name'

    # db field names
    name = StringCol(dbName='name', unique=True, notNull=True)
    iso3166code2 = StringCol(dbName='iso3166code2', unique=True, notNull=True)
    iso3166code3 = StringCol(dbName='iso3166code3', unique=True, notNull=True)
    title = StringCol(dbName='title', notNull=False, default=DEFAULT)
    description = StringCol(dbName='description')
    continent = ForeignKey(dbName='continent',
                           foreignKey='Continent',
                           default=None)
    languages = SQLRelatedJoin('Language',
                               joinColumn='country',
                               otherColumn='language',
                               intermediateTable='SpokenIn')
Beispiel #11
0
class Key(SQLObject):
    name = UnicodeCol(unique=True)
    bits = IntCol()
    pubkey = StringCol(unique=True)
    revoked = BoolCol(default=False)
    exported = BoolCol(default=False)
    certs = MultipleJoin("Cert", joinColumn="key_id")
    ca = ForeignKey("CA", default=None)
    is_ca = BoolCol(default=False)

    def delete_key(self):
        for cert in self.certs:
            cert.delete_cert()
        self.delete(self.id)
Beispiel #12
0
class TemporaryBlobStorage(SQLBase):
    """A temporary BLOB stored in Launchpad."""

    implements(ITemporaryBlobStorage)

    _table = 'TemporaryBlobStorage'

    uuid = StringCol(notNull=True, alternateID=True)
    file_alias = ForeignKey(dbName='file_alias',
                            foreignKey='LibraryFileAlias',
                            notNull=True,
                            alternateID=True)
    date_created = UtcDateTimeCol(notNull=True, default=DEFAULT)

    @property
    def blob(self):
        self.file_alias.open()
        try:
            return self.file_alias.read()
        finally:
            self.file_alias.close()

    @property
    def _apport_job(self):
        # Imported here to avoid circular imports
        from lp.bugs.interfaces.apportjob import IProcessApportBlobJobSource
        try:
            job_for_blob = getUtility(
                IProcessApportBlobJobSource).getByBlobUUID(self.uuid)
        except SQLObjectNotFound:
            return None

        return job_for_blob

    def hasBeenProcessed(self):
        """See `ITemporaryBlobStorage`."""
        job_for_blob = self._apport_job
        if not job_for_blob:
            return False
        return (job_for_blob.job.status == JobStatus.COMPLETED)

    def getProcessedData(self):
        """See `ITemporaryBlobStorage`."""
        job_for_blob = self._apport_job
        if not job_for_blob:
            return None
        if 'processed_data' not in job_for_blob.metadata:
            return {}

        return job_for_blob.metadata['processed_data']
Beispiel #13
0
class Log(SQLObject):
    """ The log object
        Stores a list of word id's
    """
    entry      = StringCol()
    lex        = ForeignKey('Lex')
    entry_date = DateTimeCol(default=sqlbuilder.func.NOW())

    class sqlmeta:
        defaultOrder = 'entry_date'

    def wordList(self):
        """Return a list of word_ids for this log"""
        return self.entry.split('|')
Beispiel #14
0
class CodeImportJob(SQLBase):
    """See `ICodeImportJob`."""

    implements(ICodeImportJob)

    date_created = UtcDateTimeCol(notNull=True, default=UTC_NOW)

    code_import = ForeignKey(
        dbName='code_import', foreignKey='CodeImport', notNull=True)

    machine = ForeignKey(
        dbName='machine', foreignKey='CodeImportMachine',
        notNull=False, default=None)

    date_due = UtcDateTimeCol(notNull=True)

    state = EnumCol(
        enum=CodeImportJobState, notNull=True,
        default=CodeImportJobState.PENDING)

    requesting_user = ForeignKey(
        dbName='requesting_user', foreignKey='Person',
        storm_validator=validate_public_person,
        notNull=False, default=None)

    ordering = IntCol(notNull=False, default=None)

    heartbeat = UtcDateTimeCol(notNull=False, default=None)

    logtail = StringCol(notNull=False, default=None)

    date_started = UtcDateTimeCol(notNull=False, default=None)

    def isOverdue(self):
        """See `ICodeImportJob`."""
        # SQLObject offers no easy way to compare a timestamp to UTC_NOW, so
        # we must use trickery here.

        # First we flush any pending update to self to ensure that the
        # following database query will give the correct result even if
        # date_due was modified in this transaction.
        self.syncUpdate()

        # Then, we try to find a CodeImportJob object with the id of self, and
        # a date_due of now or past. If we find one, this means self is
        # overdue.
        import_job = CodeImportJob.selectOne(
            "id = %s AND date_due <= %s" % sqlvalues(self.id, UTC_NOW))
        return import_job is not None
Beispiel #15
0
class Asset(ICTVObject):
    """ Represents the metadata of a file stored by the StorageManager. """
    plugin_channel = ForeignKey('PluginChannel', notNone=True, cascade=True)
    user = ForeignKey('User')  # The user who uploaded the file, if known
    filename = StringCol(
        default=None
    )  # The original filename of the asset, beginning with a period
    mime_type = StringCol(
        default=None)  # The MIME type associated with the file
    extension = StringCol(default=None)
    file_size = BigIntCol(default=None)  # File size in kilobytes
    created = DateTimeCol(default=DateTimeCol.now)
    last_reference = DateTimeCol(default=DateTimeCol.now)
    in_flight = BoolCol(
        default=False)  # Is this asset being cached at the moment
    is_cached = BoolCol(
        default=False)  # Is this asset a cached asset from CacheManager

    def _get_path(self, force=False):
        """ Returns the path to the asset on the filesystem or None if the asset file is being cached. """
        self.last_reference = datetime.now()
        if not force and self.in_flight:
            return None
        elif force:
            self.in_flight = False  # Prevent failures in the caching process to block asset in flight mode
        return os.path.join(
            'static', 'storage', str(self.plugin_channel.id),
            str(self.id) +
            (self.extension if self.extension is not None else ''))

    def write_to_asset_file(self, content):
        """ Writes the content to the asset file. """
        asset_path = os.path.join(get_root_path(), self.path)
        os.makedirs(os.path.dirname(asset_path), exist_ok=True)
        with open(asset_path, 'wb') as f:
            f.write(content)
Beispiel #16
0
class Vote(SQLBase):
    """See IVote."""
    _table = 'Vote'
    _defaultOrder = ['preference', 'id']

    person = ForeignKey(dbName='person',
                        foreignKey='Person',
                        storm_validator=validate_public_person)

    poll = ForeignKey(dbName='poll', foreignKey='Poll', notNull=True)

    option = ForeignKey(dbName='option', foreignKey='PollOption')

    preference = IntCol(dbName='preference')

    token = StringCol(dbName='token', notNull=True, unique=True)
Beispiel #17
0
class TG_Visit(SQLObject):

    class sqlmeta:
        table = "tg_visit"

    visit_key = StringCol(length=40, alternateID=True,
            alternateMethodName="by_visit_key")
    created = DateTimeCol(default=datetime.now)
    expiry = DateTimeCol()

    @classmethod
    def lookup_visit(cls, visit_key):
        try:
            return cls.by_visit_key(visit_key)
        except SQLObjectNotFound:
            return None
class POTranslation(SQLBase):
    implements(IPOTranslation)

    _table = 'POTranslation'

    # alternateID=False because we have to select by hash in order to do
    # index lookups.
    translation = StringCol(dbName='translation',
                            notNull=True,
                            unique=True,
                            alternateID=False)

    def byTranslation(cls, key):
        """Return a POTranslation object for the given translation."""

        # We can't search directly on msgid, because this database column
        # contains values too large to index. Instead we search on its
        # hash, which *is* indexed
        r = cls.selectOne('sha1(translation) = sha1(%s)' % quote(key))

        if r is not None:
            return r
        else:
            # To be 100% compatible with the alternateID behaviour, we should
            # raise SQLObjectNotFound instead of KeyError
            raise SQLObjectNotFound(key)

    byTranslation = classmethod(byTranslation)

    def getOrCreateTranslation(cls, key):
        """Return a POTranslation object for the given translation, or create
        it if it doesn't exist.
        """
        if isinstance(key, str):
            # If this is not a unicode object, it had better be ASCII or
            # UTF-8.
            # XXX: JeroenVermeulen 2008-06-06 bug=237868: non-ascii str
            # strings should be contained in the parser or the browser
            # code.
            key = key.decode('UTF-8')

        try:
            return cls.byTranslation(key)
        except SQLObjectNotFound:
            return cls(translation=key)

    getOrCreateTranslation = classmethod(getOrCreateTranslation)
Beispiel #19
0
class PersonLocation(SQLBase):
    """A person's location."""

    _defaultOrder = ['id']

    date_created = UtcDateTimeCol(notNull=True, default=UTC_NOW)
    person = ForeignKey(
        dbName='person', foreignKey='Person',
        storm_validator=validate_public_person, notNull=True, unique=True)
    latitude = FloatCol(notNull=False)
    longitude = FloatCol(notNull=False)
    time_zone = StringCol(notNull=True)
    last_modified_by = ForeignKey(
        dbName='last_modified_by', foreignKey='Person',
        storm_validator=validate_public_person, notNull=True)
    date_last_modified = UtcDateTimeCol(notNull=True, default=UTC_NOW)
    visible = BoolCol(notNull=True, default=True)
Beispiel #20
0
class OAuthNonce(OAuthBase, StormBase):
    """See `IOAuthNonce`."""
    implements(IOAuthNonce)

    __storm_table__ = 'OAuthNonce'
    __storm_primary__ = 'access_token_id', 'request_timestamp', 'nonce'

    access_token_id = Int(name='access_token')
    access_token = Reference(access_token_id, OAuthAccessToken.id)
    request_timestamp = UtcDateTimeCol(default=UTC_NOW, notNull=True)
    nonce = StringCol(notNull=True)

    def __init__(self, access_token, request_timestamp, nonce):
        super(OAuthNonce, self).__init__()
        self.access_token = access_token
        self.request_timestamp = request_timestamp
        self.nonce = nonce
Beispiel #21
0
class EmailAddress(SQLBase, HasOwnerMixin):
    implements(IEmailAddress)

    _table = 'EmailAddress'
    _defaultOrder = ['email']

    email = StringCol(dbName='email',
                      notNull=True,
                      unique=True,
                      alternateID=True)
    status = EnumCol(dbName='status', schema=EmailAddressStatus, notNull=True)
    person = ForeignKey(dbName='person', foreignKey='Person', notNull=False)

    def __repr__(self):
        return '<EmailAddress at 0x%x <%s> [%s]>' % (id(self), self.email,
                                                     self.status)

    def destroySelf(self):
        """See `IEmailAddress`."""
        # Import this here to avoid circular references.
        from lp.registry.interfaces.mailinglist import MailingListStatus
        from lp.registry.model.mailinglist import (MailingListSubscription)

        if self.status == EmailAddressStatus.PREFERRED:
            raise UndeletableEmailAddress(
                "This is a person's preferred email, so it can't be deleted.")
        mailing_list = self.person and self.person.mailing_list
        if (mailing_list is not None
                and mailing_list.status != MailingListStatus.PURGED
                and mailing_list.address == self.email):
            raise UndeletableEmailAddress(
                "This is the email address of a team's mailing list, so it "
                "can't be deleted.")

        # XXX 2009-05-04 jamesh bug=371567: This function should not
        # be responsible for removing subscriptions, since the SSO
        # server can't write to that table.
        for subscription in MailingListSubscription.selectBy(
                email_address=self):
            subscription.destroySelf()
        super(EmailAddress, self).destroySelf()

    @property
    def rdf_sha1(self):
        """See `IEmailAddress`."""
        return hashlib.sha1('mailto:' + self.email).hexdigest().upper()
Beispiel #22
0
class SprintSpecification(SQLBase):
    """A link between a sprint and a specification."""

    _table = 'SprintSpecification'

    sprint = ForeignKey(dbName='sprint', foreignKey='Sprint', notNull=True)
    specification = ForeignKey(dbName='specification',
                               foreignKey='Specification',
                               notNull=True)
    status = EnumCol(schema=SprintSpecificationStatus,
                     notNull=True,
                     default=SprintSpecificationStatus.PROPOSED)
    whiteboard = StringCol(notNull=False, default=None)
    registrant = ForeignKey(dbName='registrant',
                            foreignKey='Person',
                            storm_validator=validate_public_person,
                            notNull=True)
    date_created = UtcDateTimeCol(notNull=True, default=DEFAULT)
    decider = ForeignKey(dbName='decider',
                         foreignKey='Person',
                         storm_validator=validate_public_person,
                         notNull=False,
                         default=None)
    date_decided = UtcDateTimeCol(notNull=False, default=None)

    @property
    def is_confirmed(self):
        """See ISprintSpecification."""
        return self.status == SprintSpecificationStatus.ACCEPTED

    @property
    def is_decided(self):
        """See ISprintSpecification."""
        return self.status != SprintSpecificationStatus.PROPOSED

    def acceptBy(self, decider):
        """See ISprintSpecification."""
        self.status = SprintSpecificationStatus.ACCEPTED
        self.decider = decider
        self.date_decided = UTC_NOW

    def declineBy(self, decider):
        """See ISprintSpecification."""
        self.status = SprintSpecificationStatus.DECLINED
        self.decider = decider
        self.date_decided = UTC_NOW
Beispiel #23
0
class BranchJob(SQLBase):
    """Base class for jobs related to branches."""

    implements(IBranchJob)

    _table = 'BranchJob'

    job = ForeignKey(foreignKey='Job', notNull=True)

    branch = ForeignKey(foreignKey='Branch')

    job_type = EnumCol(enum=BranchJobType, notNull=True)

    _json_data = StringCol(dbName='json_data')

    @property
    def metadata(self):
        return simplejson.loads(self._json_data)

    def __init__(self, branch, job_type, metadata, **job_args):
        """Constructor.

        Extra keyword parameters are used to construct the underlying Job
        object.

        :param branch: The database branch this job relates to.
        :param job_type: The BranchJobType of this job.
        :param metadata: The type-specific variables, as a JSON-compatible
            dict.
        """
        json_data = simplejson.dumps(metadata)
        SQLBase.__init__(self,
                         job=Job(**job_args),
                         branch=branch,
                         job_type=job_type,
                         _json_data=json_data)

    def destroySelf(self):
        """See `IBranchJob`."""
        SQLBase.destroySelf(self)
        self.job.destroySelf()

    def makeDerived(self):
        return BranchJobDerived.makeSubclass(self)
Beispiel #24
0
class Translator(SQLBase):
    """A Translator in a TranslationGroup."""

    # default to listing newest first
    _defaultOrder = '-id'

    # db field names
    translationgroup = ForeignKey(dbName='translationgroup',
                                  foreignKey='TranslationGroup',
                                  notNull=True)
    language = ForeignKey(dbName='language',
                          foreignKey='Language',
                          notNull=True)
    translator = ForeignKey(dbName='translator',
                            foreignKey='Person',
                            storm_validator=validate_public_person,
                            notNull=True)
    datecreated = UtcDateTimeCol(notNull=True, default=DEFAULT)
    style_guide_url = StringCol(notNull=False, default=None)
Beispiel #25
0
class Visit(SQLObject):
    """
    A visit to your site
    """
    class sqlmeta:
        table = 'visit'

    visit_key = StringCol(length=40,
                          alternateID=True,
                          alternateMethodName='by_visit_key')
    created = DateTimeCol(default=datetime.now)
    expiry = DateTimeCol()

    def lookup_visit(cls, visit_key):
        try:
            return cls.by_visit_key(visit_key)
        except SQLObjectNotFound:
            return None

    lookup_visit = classmethod(lookup_visit)
Beispiel #26
0
class SeriesMixin(HasDriversMixin):
    """See `ISeriesMixin`."""

    summary = StringCol(notNull=True)

    @property
    def active(self):
        return self.status in ACTIVE_STATUSES

    @property
    def bug_supervisor(self):
        """See `ISeriesMixin`."""
        return self.parent.bug_supervisor

    @property
    def drivers(self):
        """See `IHasDrivers`."""
        drivers = set()
        drivers.add(self.driver)
        drivers = drivers.union(self.parent.drivers)
        drivers.discard(None)
        return sorted(drivers, key=attrgetter('displayname'))
Beispiel #27
0
class POMsgID(SQLBase):
    implements(IPOMsgID)

    _table = 'POMsgID'

    # alternateID is technically true, but we don't use it because this
    # column is too large to be indexed.
    msgid = StringCol(dbName='msgid', notNull=True, unique=True,
        alternateID=False)

    def byMsgid(cls, key):
        """Return a POMsgID object for the given msgid."""

        # We can't search directly on msgid, because this database column
        # contains values too large to index. Instead we search on its
        # hash, which *is* indexed
        r = POMsgID.selectOne('sha1(msgid) = sha1(%s)' % quote(key))
        if r is None:
            # To be 100% compatible with the alternateID behaviour, we should
            # raise SQLObjectNotFound instead of KeyError
            raise SQLObjectNotFound(key)
        return r
    byMsgid = classmethod(byMsgid)
class CodeImportResult(SQLBase):
    """See `ICodeImportResult`."""

    date_created = UtcDateTimeCol(notNull=True, default=UTC_NOW)

    code_import = ForeignKey(dbName='code_import',
                             foreignKey='CodeImport',
                             notNull=True)

    machine = ForeignKey(dbName='machine',
                         foreignKey='CodeImportMachine',
                         notNull=True)

    requesting_user = ForeignKey(dbName='requesting_user',
                                 foreignKey='Person',
                                 storm_validator=validate_public_person,
                                 default=None)

    log_excerpt = StringCol(default=None)

    log_file = ForeignKey(dbName='log_file',
                          foreignKey='LibraryFileAlias',
                          default=None)

    status = EnumCol(enum=CodeImportResultStatus, notNull=True)

    date_job_started = UtcDateTimeCol(notNull=True)

    @property
    def date_job_finished(self):
        """See `ICodeImportResult`."""
        return self.date_created

    @property
    def job_duration(self):
        return self.date_job_finished - self.date_job_started
class PluginParamAccessRights(ICTVObject):
    plugin = ForeignKey('Plugin', cascade=True)
    name = StringCol(notNone=True)
    channel_contributor_read = BoolCol(default=False)
    channel_contributor_write = BoolCol(default=False)
    channel_administrator_read = BoolCol(default=True)
    channel_administrator_write = BoolCol(default=False)
    administrator_read = BoolCol(default=True)
    administrator_write = BoolCol(default=True)

    def get_access_rights_for(self, permission_level):
        """
            Returns a tuple of booleans (read_access, write_access) indicating which type of rights
            this permission level gives on this.
        """
        if permission_level is UserPermissions.super_administrator:
            return True, True
        if permission_level is UserPermissions.administrator:
            return self.administrator_read, self.administrator_write
        if permission_level is UserPermissions.channel_administrator:
            return self.channel_administrator_read, self.channel_administrator_write
        if permission_level is UserPermissions.channel_contributor:
            return self.channel_contributor_read, self.channel_contributor_write
        return False, False
class SourcePackageName(SQLBase):
    implements(ISourcePackageName)
    _table = 'SourcePackageName'

    name = StringCol(dbName='name', notNull=True, unique=True,
        alternateID=True)

    potemplates = SQLMultipleJoin(
        'POTemplate', joinColumn='sourcepackagename')
    packagings = SQLMultipleJoin(
        'Packaging', joinColumn='sourcepackagename', orderBy='Packaging.id')

    def __unicode__(self):
        return self.name

    def __repr__(self):
        return "<%s '%s'>" % (self.__class__.__name__, self.name)

    def ensure(klass, name):
        try:
            return klass.byName(name)
        except SQLObjectNotFound:
            return klass(name=name)
    ensure = classmethod(ensure)