class Author(sqlobject.SQLObject): name = sqlobject.StringCol(alternateID=True, length=50) urls = sqlobject.MultipleJoin('URL') comments = sqlobject.MultipleJoin('Comments') points_new = sqlobject.IntCol(default=0) points_old = sqlobject.IntCol(default=0) points_credit = sqlobject.IntCol(default=0)
class Supername(Place): """ Global level place, which can have continents. Taken from 'Supername' title for the world, in Twitter API. """ _inheritable = False # Get Continent objects belong to the Supername. Defaults to null list. hasContinents = so.MultipleJoin("Continent")
class URL(sqlobject.SQLObject): class sqlmeta: table = 'url' url = sqlobject.StringCol() clean = sqlobject.StringCol() author = sqlobject.ForeignKey('Author') channel = sqlobject.ForeignKey('Channel') citations = sqlobject.IntCol(default=0) posted = sqlobject.DateTimeCol(default=datetime.now) comments = sqlobject.MultipleJoin('Comments')
class Continent(Place): """ A continent, which can have countries. """ _inheritable = False # Supername which this Continent belongs to. supername = so.ForeignKey("Supername") # Get Country objects belonging to the Continent. Defaults to null list. hasCountries = so.MultipleJoin("Country")
class Board(SO.SQLObject): chunk_size = SO.IntCol() chunk_mines = SO.IntCol() chunks = SO.MultipleJoin('Chunk') def get_chunk(self, i, k): chunk = Chunk.selectBy(i=i, k=k, board=self) if chunk.count(): return chunk.getOne() chunk = Chunk(i=i, k=k, board=self) chunk.generate_mines() return chunk
class Country(Place): """ Place which is a Country in Twitter API. """ _inheritable = False # Continent which this Country belongs to. continent = so.ForeignKey("Continent", default=None) # Get Town objects belonging to the Country. Defaults to null list. hasTowns = so.MultipleJoin("Town") # Two-character string as the country's code. countryCode = so.StringCol(length=2, default=None)
class Flow(orm.SQLObject): """The class generates a Flow table containing information about threads and their types (chat, channel, group). Args: flowId (int, required): timeCreated (int, optional): flowType (str, optional): title (str, optional): info (str, optional): Returns: None """ flowId = orm.IntCol(alternateID=True, unique=True, notNone=True) timeCreated = orm.IntCol(default=None) flowType = orm.StringCol(default=None) title = orm.StringCol(default=None) info = orm.StringCol(default=None) # Connection to the Message table message = orm.MultipleJoin('Message')
class Filedata(sqlobject.SQLObject): class sqlmeta(myMeta): pass basename = sqlobject.StringCol() full_path = sqlobject.StringCol(alternateID=True) dt_needed = sqlobject.RelatedJoin('Soname', joinColumn='filedata_id', otherColumn='soname_id', intermediateTable='dt_needed_list', addRemoveName='DtNeeded') soname = sqlobject.RelatedJoin('Soname', joinColumn='filedata_id', otherColumn='soname_id', intermediateTable='soname_list', addRemoveName='Soname') license = sqlobject.RelatedJoin('License', joinColumn='filedata_id', otherColumn='license_id', intermediateTable='filedata_license', addRemoveName='License') tags = sqlobject.MultipleJoin('Tag')
class Domain(so.SQLObject): """ Model a website domain. TODO: Add columns for metadata including title, keywords, image and icon. """ class sqlmeta: defaultOrder = 'value' # Full hostname or domain of the website. value = so.UnicodeCol(alternateID=True, validator=URL) # The date and time when the record was created. Defaults to the # current time. datetime_created = so.DateTimeCol(notNull=True, default=so.DateTimeCol.now) # Link to Page objects which have paths relative to the Domain name. pages = so.SQLMultipleJoin('Page') # Get Page objects for the domain as a list. This is less efficient # for filtering, but slightly more convenient for development. pages_list = so.MultipleJoin('Page')
class UserConfig(orm.SQLObject): """The class generates a table containing data about the user and his settings. Args: uuid (int, required): login (str, required): password (str, required): hash_password (str, optional) username (str, optional): isBot (bool, optional): default False authId (str, optional): email (str, optional): avatar (str, optional): bio (str, optional): salt (str, optional): key (str, optional): Returns: None """ # added alternateID for added class method @byUUID # which will return that object uuid = orm.IntCol(alternateID=True, unique=True, notNone=True) login = orm.StringCol() password = orm.StringCol() hashPassword = orm.StringCol(default=None) username = orm.StringCol(default=None) isBot = orm.BoolCol(default=False) authId = orm.StringCol(default=None) email = orm.StringCol(default=None) avatar = orm.BLOBCol(default=None) bio = orm.StringCol(default=None) salt = orm.BLOBCol(default=None) key = orm.BLOBCol(default=None) # Connection to the Message table message = orm.MultipleJoin('Message')
class Srv4FileStats(sqlobject.SQLObject): """Represents a srv4 file. It focuses on the stats, but it can as well represent just a srv4 file. """ arch = sqlobject.ForeignKey('Architecture', notNone=True) basename = sqlobject.UnicodeCol(notNone=True) catalogname = sqlobject.UnicodeCol(notNone=True) # The data structure can be missing - necessary for fake SUNW # packages. data_obj = sqlobject.ForeignKey('Srv4FileStatsBlob', notNone=False) filename_arch = sqlobject.ForeignKey('Architecture', notNone=True) latest = sqlobject.BoolCol(notNone=True) maintainer = sqlobject.ForeignKey('Maintainer', notNone=False) md5_sum = sqlobject.UnicodeCol(notNone=True, unique=True, length=32) size = sqlobject.IntCol() mtime = sqlobject.DateTimeCol(notNone=False) os_rel = sqlobject.ForeignKey('OsRelease', notNone=True) pkginst = sqlobject.ForeignKey('Pkginst', notNone=True) registered = sqlobject.BoolCol(notNone=True) use_to_generate_catalogs = sqlobject.BoolCol(notNone=True) rev = sqlobject.UnicodeCol(notNone=False) stats_version = sqlobject.IntCol(notNone=True) version_string = sqlobject.UnicodeCol(notNone=True) in_catalogs = sqlobject.MultipleJoin('Srv4FileInCatalog', joinColumn='srv4file_id') files = sqlobject.MultipleJoin('CswFile', joinColumn='id') def __init__(self, *args, **kwargs): super(Srv4FileStats, self).__init__(*args, **kwargs) self._cached_pkgstats = None def DeleteAllDependentObjects(self): data_obj = self.data_obj self.data_obj = None if data_obj: # It could be already missing data_obj.destroySelf() self.RemoveAllCswFiles() self.RemoveAllCheckpkgResults() self.RemoveOverrides() def RemoveAllCswFiles(self): # Removing existing files, using sqlbuilder to use sql-level # mechanisms without interacting with Python. # http://www.mail-archive.com/[email protected]/msg00520.html sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete(CswFile.sqlmeta.table, CswFile.q.srv4_file == self))) def GetOverridesResult(self): return CheckpkgOverride.select(CheckpkgOverride.q.srv4_file == self) def GetErrorTagsResult(self, os_rel, arch, catrel): assert arch.name != 'all', ( "Asked for the 'all' architecture, this is not valid " "for GetErrorTagsResult().") return CheckpkgErrorTag.select( sqlobject.AND(CheckpkgErrorTag.q.srv4_file == self, CheckpkgErrorTag.q.os_rel == os_rel, CheckpkgErrorTag.q.arch == arch, CheckpkgErrorTag.q.catrel == catrel)) def RemoveCheckpkgResults(self, os_rel, arch, catrel): logging.debug("%s: RemoveCheckpkgResults(%s, %s, %s)", self, os_rel, arch, catrel) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete( CheckpkgErrorTag.sqlmeta.table, sqlobject.AND(CheckpkgErrorTag.q.srv4_file == self, CheckpkgErrorTag.q.os_rel == os_rel, CheckpkgErrorTag.q.arch == arch, CheckpkgErrorTag.q.catrel == catrel)))) def RemoveAllCheckpkgResults(self): logging.debug("%s: RemoveAllCheckpkgResults()", self) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete(CheckpkgErrorTag.sqlmeta.table, CheckpkgErrorTag.q.srv4_file == self))) def RemoveOverrides(self): logging.debug("%s: RemoveOverrides()", self) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete(CheckpkgOverride.sqlmeta.table, CheckpkgOverride.q.srv4_file == self))) def __unicode__(self): return (u"Package: %s-%s, %s" % (self.catalogname, self.version_string, self.arch.name)) def GetUnicodeOrNone(self, s): """Tries to decode UTF-8. If the object does not decode as UTF-8, it's forced to do so, while ignoring any potential errors. Returns: a unicode object or a None type. """ if s is None: return None if type(s) != unicode: try: s = unicode(s, 'utf-8') except UnicodeDecodeError, e: s = s.decode("utf-8", "ignore") s = s + u" (bad unicode detected)" return s
class Chunk(SO.SQLObject): i = SO.IntCol() k = SO.IntCol() board = SO.ForeignKey('Board') mines = SO.MultipleJoin('Mine') def generate_mines(self): size = self.board.chunk_size #generate square list squares = set() while len(squares) < self.board.chunk_mines: x = random.randrange(size) y = random.randrange(size) squares.add((x, y)) #create mines in the squares for square in squares: Mine(x=square[0], y=square[1], chunk=self) def get_display(self): size = self.board.chunk_size #generate display grid display = [] for y in range(size): display.append([]) for x in range(size): display[y].append({ 'is_mine': False, 'count': 0, 'is_hidden': True, 'flag': False }) #check self mines for mine in self.mines: display[mine.y][mine.x]['is_mine'] = True for x in range(mine.x - 1, mine.x + 2): for y in range(mine.y - 1, mine.y + 2): if x >= 0 and x < size and y >= 0 and y < size: display[y][x]['count'] += 1 #check left mines chunk = self.board.get_chunk(i=self.i - 1, k=self.k) mines = Mine.selectBy(chunk=chunk, x=size - 1) for mine in mines: for y in range(mine.y - 1, mine.y + 2): if y >= 0 and y < size: display[y][0]['count'] += 1 #check right mines chunk = self.board.get_chunk(i=self.i + 1, k=self.k) mines = Mine.selectBy(chunk=chunk, x=0) for mine in mines: for y in range(mine.y - 1, mine.y + 2): if y >= 0 and y < size: display[y][size - 1]['count'] += 1 #check up mines chunk = self.board.get_chunk(i=self.i, k=self.k - 1) mines = Mine.selectBy(chunk=chunk, y=size - 1) for mine in mines: for x in range(mine.x - 1, mine.x + 2): if x >= 0 and x < size: display[0][x]['count'] += 1 #check down mines chunk = self.board.get_chunk(i=self.i, k=self.k + 1) mines = Mine.selectBy(chunk=chunk, y=0) for mine in mines: for x in range(mine.x - 1, mine.x + 2): if x >= 0 and x < size: display[size - 1][x]['count'] += 1 #check left_up mines chunk = self.board.get_chunk(i=self.i - 1, k=self.k - 1) mine = Mine.selectBy(chunk=chunk, x=size - 1, y=size - 1) if mine.count(): display[0][0]['count'] += 1 #check right_up mines chunk = self.board.get_chunk(i=self.i + 1, k=self.k - 1) mine = Mine.selectBy(chunk=chunk, x=0, y=size - 1) if mine.count(): display[0][size - 1]['count'] += 1 #check left_down mines chunk = self.board.get_chunk(i=self.i - 1, k=self.k + 1) mine = Mine.selectBy(chunk=chunk, x=size - 1, y=0) if mine.count(): display[size - 1][0]['count'] += 1 #check right_down mines chunk = self.board.get_chunk(i=self.i + 1, k=self.k + 1) mine = Mine.selectBy(chunk=chunk, x=0, y=0) if mine.count(): display[size - 1][size - 1]['count'] += 1 #return display return display def update_display(self, display, max_action): #set non hidden mines actions = Action.select( SO.AND(Action.q.chunk == self, Action.q.id <= max_action)) for action in actions: if action.action == 'DIG': display[action.y][action.x]['is_hidden'] = False else: display[action.y][ action.x]['flag'] = not display[action.y][action.x]['flag'] return display
class post(so.SQLObject): ctime = so.DateTimeCol(notNone=1,default=so.DateTimeCol.now) title = so.StringCol(length=128, notNone=1,default='') body = so.StringCol(notNone=1,default='') comments = so.MultipleJoin('comment')
class Student(sqlobject.SQLObject): _connection = conn name = sqlobject.StringCol(length=255) backlog = sqlobject.IntCol(name=None) subjects = sqlobject.MultipleJoin('Subjects')
class Place(InheritableSQLObject): """ A place in the world. This is created from the Yahoo Where On Earth locations as returned by Twitter API. This table has childName to indicate which table the object is in and therefore the parent Place's location type. Name is *not* an alternateID, since place names can be duplicated around the world e.g. Barcelona in Venezuela and Spain. Therefore `.byName` is not available, but we can do a `.selectBy` with both town name and the country's ID set in the where clause, to ensure we get one result. Default order by ID is omitted as it causes ambiguity issues on some selects. And timestamp is not recognised as a column on the subclasses so cannot be used either. """ _connection = conn # WOEID integer value from Yahoo system. # Note that `.byWoeid` can be used on Place class, but cannot be used # on any subclasses. This is because of the `id` in the order by statement # having ambiguous meaning in `where (Place.id = {subclass}.id)`. woeid = so.IntCol(alternateID=True) # Name of the place. name = so.StringCol(length=64, default=None) nameIdx = so.DatabaseIndex(name) # Date and time when record was created. timestamp = so.DateTimeCol(default=so.DateTimeCol.now) timestampIdx = so.DatabaseIndex(timestamp) # Get all the trend records relating to this Place. hasTrends = so.MultipleJoin("Trend") @classmethod def getColumnNames(cls): """ Return a list of column names for the class, as strings. This is created from a dictionary, so the order is not guaranteed. """ return list(cls.sqlmeta.columns.keys()) def getData(self, quiet=True): """ Output the current record with key:value pairs for column name and value. Note that this is not suitable to be converted directly to JSON because of the data types of some values. TODO: Ensure that attributes of the parent and child are all accessed, to get more use out of this. """ data = {col: getattr(self, col) for col in self.getColumnNames()} if not quiet: for k, v in data.items(): print(f"{k:>15} : {v}") return data
class UserObj(sqlobject.SQLObject): name = sqlobject.StringCol(length=40, unique=True) contact = sqlobject.MultipleJoin('ContactObj', joinColumn='user')
class Package(threading.Thread, sqlobject.SQLObject): """ check package with pkgname, pkgver, reponame, action, hashsum action will be ['commit', 'release', 'candidate', 'rebuild', ...] """ pkgname = sqlobject.StringCol() pkgver = sqlobject.StringCol() reponame = sqlobject.StringCol(default="default") action = sqlobject.StringCol(default="commit") build_args = sqlobject.StringCol(default=None) hashsum = sqlobject.StringCol(default=None) expired = sqlobject.DateTimeCol(default=sqlobject.DateTimeCol.now) priority = sqlobject.StringCol(default=None) jobs = sqlobject.MultipleJoin('Job', joinColumn='package_id') triggered = sqlobject.IntCol(default=1) upload_status = sqlobject.IntCol(default=UploadStatus.UNKNOWN) status_changed = sqlobject.DateTimeCol(default=sqlobject.DateTimeCol.now) deps = sqlobject.RelatedJoin('Package', joinColumn='pkga', otherColumn='pkgb') notify = None def __init__(self, *args, **kwargs): sqlobject.SQLObject.__init__(self, *args, **kwargs) threading.Thread.__init__(self) self.do_quit = threading.Event() self.status_lock = status_lock def __setattr__(self, name, value): if name == "upload_status": self.status_changed = sqlobject.DateTimeCol.now() sqlobject.SQLObject.__setattr__(self, name, value) def dict(self): result = { "id": self.id, "pkgname": self.pkgname, "pkgver": self.pkgver, "reponame": self.reponame, "action": self.action, "hashsum": self.hashsum, "expired": try_strftime(self.expired, default='never'), "priority": self.priority, "triggered": self.triggered, "build_args": self.build_args.split('|') if self.build_args else [], "upload_status": UploadStatus.whatis(self.upload_status), "status_changed": try_strftime(self.status_changed) } return result @staticmethod def version_compare(a, b): if version.parse(a.pkgver) >= version.parse(b.pkgver): return True return False def giveup(self): self.upload_status = UploadStatus.UPLOAD_GIVEUP for job in self.jobs: if job.status == JobStatus.WAIT: job.status = JobStatus.GIVEUP def is_allowed_to_build(self): for dep in Package.selectBy(id=self)[0].deps: if Package.selectBy( id=dep)[0].upload_status != UploadStatus.UPLOAD_OK: if self.is_maybe_giveup(): self.giveup() return False return True def is_maybe_giveup(self): for dep in Package.selectBy(id=self)[0].deps: for job in Package.selectBy(id=dep)[0].jobs: if Job.selectBy(id=job)[0].status in JobFailedStatus: return True return False def add_dep(self, dep): for exist_dep in self.deps: if exist_dep.id == dep.id: return self.addPackage(dep) def add_deps(self, deps): for dep in deps: self.add_dep(dep)
class Pkginst(sqlobject.SQLObject): pkgname = sqlobject.UnicodeCol(length=250, unique=True, notNone=True) catalogname = sqlobject.UnicodeCol(default=None, length=250) pkg_desc = sqlobject.UnicodeCol(default=None, length=250) srv4_files = sqlobject.MultipleJoin('Srv4FileStats')
class Artist(sqlobject.SQLObject): _connection = conn artist_id = sqlobject.IntCol(length=14, unique=True) name = sqlobject.UnicodeCol(length=255) lyrics = sqlobject.MultipleJoin('Lyric', joinColumn='artist_id')
class Srv4FileStats(sqlobject.SQLObject): """Represents a srv4 file. It focuses on the stats, but it can as well represent just a srv4 file. """ arch = sqlobject.ForeignKey('Architecture', notNone=True) basename = sqlobject.UnicodeCol(notNone=True) catalogname = sqlobject.UnicodeCol(notNone=True) # The data structure can be missing - necessary for fake SUNW # packages. data_obj = sqlobject.ForeignKey('Srv4FileStatsBlob', notNone=False) filename_arch = sqlobject.ForeignKey('Architecture', notNone=True) latest = sqlobject.BoolCol(notNone=True) maintainer = sqlobject.ForeignKey('Maintainer', notNone=False) md5_sum = sqlobject.UnicodeCol(notNone=True, unique=True, length=32) size = sqlobject.IntCol() mtime = sqlobject.DateTimeCol(notNone=False) os_rel = sqlobject.ForeignKey('OsRelease', notNone=True) pkginst = sqlobject.ForeignKey('Pkginst', notNone=True) registered = sqlobject.BoolCol(notNone=True) use_to_generate_catalogs = sqlobject.BoolCol(notNone=True) rev = sqlobject.UnicodeCol(notNone=False) stats_version = sqlobject.IntCol(notNone=True) version_string = sqlobject.UnicodeCol(notNone=True) in_catalogs = sqlobject.MultipleJoin('Srv4FileInCatalog', joinColumn='srv4file_id') files = sqlobject.MultipleJoin('CswFile', joinColumn='id') def __init__(self, *args, **kwargs): super(Srv4FileStats, self).__init__(*args, **kwargs) self._cached_pkgstats = None def DeleteAllDependentObjects(self): data_obj = self.data_obj self.data_obj = None if data_obj: # It could be already missing data_obj.destroySelf() self.RemoveAllCswFiles() self.RemoveAllCheckpkgResults() self.RemoveOverrides() def RemoveAllCswFiles(self): # Removing existing files, using sqlbuilder to use sql-level # mechanisms without interacting with Python. # http://www.mail-archive.com/[email protected]/msg00520.html sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete(CswFile.sqlmeta.table, CswFile.q.srv4_file == self))) def GetOverridesResult(self): return CheckpkgOverride.select(CheckpkgOverride.q.srv4_file == self) def GetErrorTagsResult(self, os_rel, arch, catrel): assert arch.name != 'all', ( "Asked for the 'all' architecture, this is not valid " "for GetErrorTagsResult().") return CheckpkgErrorTag.select( sqlobject.AND(CheckpkgErrorTag.q.srv4_file == self, CheckpkgErrorTag.q.os_rel == os_rel, CheckpkgErrorTag.q.arch == arch, CheckpkgErrorTag.q.catrel == catrel)) def RemoveCheckpkgResults(self, os_rel, arch, catrel): logging.debug("%s: RemoveCheckpkgResults(%s, %s, %s)", self, os_rel, arch, catrel) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete( CheckpkgErrorTag.sqlmeta.table, sqlobject.AND(CheckpkgErrorTag.q.srv4_file == self, CheckpkgErrorTag.q.os_rel == os_rel, CheckpkgErrorTag.q.arch == arch, CheckpkgErrorTag.q.catrel == catrel)))) def RemoveAllCheckpkgResults(self): logging.debug("%s: RemoveAllCheckpkgResults()", self) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete(CheckpkgErrorTag.sqlmeta.table, CheckpkgErrorTag.q.srv4_file == self))) def RemoveOverrides(self): logging.debug("%s: RemoveOverrides()", self) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete(CheckpkgOverride.sqlmeta.table, CheckpkgOverride.q.srv4_file == self))) def __unicode__(self): return (u"Package: %s-%s, %s" % (self.catalogname, self.version_string, self.arch.name)) def GetStatsStruct(self): if not self._cached_pkgstats: self._cached_pkgstats = cPickle.loads(str(self.data_obj.pickle)) return self._cached_pkgstats def _GetBuildSource(self): data = self.GetStatsStruct() build_src = None if "OPENCSW_REPOSITORY" in data["pkginfo"]: build_src = data["pkginfo"]["OPENCSW_REPOSITORY"] return build_src def GetSvnUrl(self): build_src = self._GetBuildSource() svn_url = None if build_src: svn_url = re.sub(r'([^@]*).*', r'\1/Makefile', build_src) return svn_url def GetTracUrl(self): build_src = self._GetBuildSource() trac_url = None if build_src: trac_url = re.sub( r'https://gar.svn.(sf|sourceforge).net/svnroot/gar/([^@]+)@(.*)', r'http://sourceforge.net/apps/trac/gar/browser/\2/Makefile?rev=\3', build_src) return trac_url def GetVendorUrl(self): data = self.GetStatsStruct() vendor_url = None if "VENDOR" in data["pkginfo"]: vendor_url = re.split(r"\s+", data["pkginfo"]["VENDOR"])[0] return vendor_url def GetRestRepr(self): mimetype = "application/x-vnd.opencsw.pkg;type=srv4-detail" data = { 'arch': self.arch.name, 'basename': self.basename, # For compatibility with the catalog parser from catalog.py 'file_basename': self.basename, 'catalogname': self.catalogname, 'filename_arch': self.filename_arch.name, 'maintainer_email': self.maintainer.email, 'maintainer_full_name': self.maintainer.full_name, 'md5_sum': self.md5_sum, 'mtime': unicode(self.mtime), 'osrel': self.os_rel.short_name, 'pkgname': self.pkginst.pkgname, 'rev': self.rev, 'size': self.size, 'version_string': self.version_string, # For compatibility with the catalog parser from catalog.py 'version': self.version_string, # 'in_catalogs': unicode([unicode(x) for x in self.in_catalogs]), 'vendor_url': self.GetVendorUrl(), 'repository_url': self.GetSvnUrl(), } return mimetype, data
class Profile(so.SQLObject): """ Models a user profile on Twitter. Note that URL columns are named as 'Url', since SQLOlbject converts 'imageURL' to db column named 'image_ur_l'. Twitter screen name and username rules: https://help.twitter.com/en/managing-your-account/twitter-username-rules We use slightly higher values than the ones there, to be safe. Notes on screen name: - This should not have unique restriction as users can edit their screen name so others can take an older screen name. Or someone could delete and recreate their account. - Twitter itself enforces uniqueness across case. """ # Profile's ID (integer), as assigned by Twitter when the Profile was # created. This is a global ID, rather than an ID specific to our local db. guid = so.IntCol(alternateID=True) # Profile screen name. screenName = so.StringCol(notNull=True, length=30) # Profile display Name. name = so.StringCol(notNull=True, length=60) # Description, as set in profile's bio. description = so.StringCol(default=None) # Location, as set in profile's bio. location = so.StringCol(default=None) # Link to the profile's image online. This will only be thumbnail size. imageUrl = so.StringCol(default=None, validator=URL) # Count of profile's followers. followersCount = so.IntCol(notNull=True) # Count of profile's statuses (tweets) posted by this profile. statusesCount = so.IntCol(notNull=True) # Profile's verified status. verified = so.BoolCol(notNull=True, default=False) # Join the Profile with its created tweets in the Tweet table. tweets = so.MultipleJoin("Tweet") # Date and time when follower and status counts were last updated. modified = so.DateTimeCol(notNull=True, default=so.DateTimeCol.now) modifiedIdx = so.DatabaseIndex(modified) # Get Category objects which this Profile has been assigned to, if any. categories = so.SQLRelatedJoin("Category", intermediateTable="profile_category", createRelatedTable=False) def set(self, **kwargs): """ Override the update hook to update the modified field if necessary. """ if ("followersCount" in kwargs or "statusesCount" in kwargs) and "modified" not in kwargs: kwargs["modified"] = so.DateTimeCol.now() super(Profile, self).set(**kwargs) def getFlatDescription(self): """ Return the description with newline characters replaced with spaces. """ if self.description is not None: return lib.text_handling.flattenText(self.description) return None def getProfileUrl(self): """ Get link to the profile's page online. :return: Twitter profile's URL, as a string. """ return "https://twitter.com/{0}".format(self.screenName) def getLargeImageUrl(self): """ Get link to a large version profile's image, based on thumbnail URL. The image URL comes from the API as '..._normal.jpeg', but from API calls on loading a twitter.com page, it is possible to see that the image media server allows variations of the last part, to return a large image. Such as - '..._bigger.jpeg' (which is not much bigger than the normal thumbnail) - '..._400x400.jpeg' (which is much bigger). :return: image URL using 400x400 size parameter, or None if value was not set. """ if self.imageUrl: return self.imageUrl.replace("_normal", "_400x400") return None def prettyPrint(self): """ Method to print the attributes of the Profile instance neatly. :return: dictionary of data which was printed. """ output = """\ Screen name : @{screenName} Name : {name} Verified : {verified} Followers : {followers:,d} Statuses : {statuses:,d} DB tweets : {tweetCount} Description : {description} Profile URL : {url} Image URL : {imageUrl} Stats modified : {statsModified} """ data = dict( screenName=self.screenName, name=self.name, verified=self.verified, followers=self.followersCount, statuses=self.statusesCount, tweetCount=len(self.tweets), description=self.getFlatDescription(), url=self.getProfileUrl(), imageUrl=self.getLargeImageUrl(), statsModified=self.modified, ) print(output.format(**data)) return data
class Channel(sqlobject.SQLObject): name = sqlobject.StringCol(alternateID=True, length=50) urls = sqlobject.MultipleJoin('URL')
class Srv4FileStats(sqlobject.SQLObject): """Represents a srv4 file. It focuses on the stats, but it can as well represent just a srv4 file. """ arch = sqlobject.ForeignKey('Architecture', notNone=True) basename = sqlobject.UnicodeCol(notNone=True, length=250) catalogname = sqlobject.UnicodeCol(notNone=True, length=250) filename_arch = sqlobject.ForeignKey('Architecture', notNone=True) maintainer = sqlobject.ForeignKey('Maintainer', notNone=False) md5_sum = sqlobject.UnicodeCol(notNone=True, unique=True, length=32) size = sqlobject.IntCol() mtime = sqlobject.DateTimeCol(notNone=False) os_rel = sqlobject.ForeignKey('OsRelease', notNone=True) osrel_str = sqlobject.UnicodeCol(notNone=True, length=9) # "SunOS5.10" pkginst = sqlobject.ForeignKey('Pkginst', notNone=True) pkginst_str = sqlobject.UnicodeCol(notNone=True, length=255) registered_level_one = sqlobject.BoolCol(notNone=True) registered_level_two = sqlobject.BoolCol(notNone=True) use_to_generate_catalogs = sqlobject.BoolCol(notNone=True) rev = sqlobject.UnicodeCol(notNone=False, length=250) stats_version = sqlobject.IntCol(notNone=True) version_string = sqlobject.UnicodeCol(notNone=True, length=250) bundle = sqlobject.UnicodeCol(length=250) in_catalogs = sqlobject.MultipleJoin( 'Srv4FileInCatalog', joinColumn='srv4file_id') files = sqlobject.MultipleJoin('CswFile', joinColumn='id') catalog_idx = sqlobject.DatabaseIndex('catalogname') basename_idx = sqlobject.DatabaseIndex('basename') pkginst_idx = sqlobject.DatabaseIndex('pkginst') def __init__(self, *args, **kwargs): super(Srv4FileStats, self).__init__(*args, **kwargs) def __unicode__(self): return u'%s/%s, %s' % (self.pkginst.pkgname, self.catalogname, self.md5_sum) def __str__(self): return str(unicode(self)) def DeleteAllDependentObjects(self): """Prepares the object to be deleted. Use this function with caution. """ self.DeleteDependentObjectsPopulatedFromPackageItself() logger.debug('Removing all dependent objects from %s; it will cause the ' 'package to be removed from all catalogs.', self) self.RemoveCatalogAssignments() self.RemoveAllCheckpkgResults() def DeleteDependentObjectsPopulatedFromPackageItself(self): """Removing all the objects that only depend on the package contents. It doesn't touch rows that are created for other reasons, e.g. assignments of packages to catalogs. """ logger.debug('%s - Deleting objects that only depend on the package ' 'contents', self) self.RemoveAllCswFiles() self.RemoveOverrides() self.RemoveDepends() self.RemoveIncompatibles() def RemoveAllCswFiles(self): # Removing existing files, using sqlbuilder to use sql-level # mechanisms without interacting with Python. # http://www.mail-archive.com/[email protected]/msg00520.html sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr(sqlbuilder.Delete( CswFile.sqlmeta.table, CswFile.q.srv4_file==self))) def RemoveDepends(self): sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr(sqlbuilder.Delete( Srv4DependsOn.sqlmeta.table, Srv4DependsOn.q.srv4_file==self))) def RemoveIncompatibles(self): sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr(sqlbuilder.Delete( Srv4IncompatibleWith.sqlmeta.table, Srv4IncompatibleWith.q.srv4_file==self))) def RemoveCatalogAssignments(self): sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr(sqlbuilder.Delete( Srv4FileInCatalog.sqlmeta.table, Srv4FileInCatalog.q.srv4file==self))) def GetOverridesResult(self): return CheckpkgOverride.select(CheckpkgOverride.q.srv4_file==self) def GetErrorTagsResult(self, os_rel, arch, catrel): assert arch.name != 'all', ( "Asked for the 'all' architecture, this is not valid " "for GetErrorTagsResult().") return CheckpkgErrorTag.select( sqlobject.AND( CheckpkgErrorTag.q.srv4_file==self, CheckpkgErrorTag.q.os_rel==os_rel, CheckpkgErrorTag.q.arch==arch, CheckpkgErrorTag.q.catrel==catrel)) def RemoveCheckpkgResults(self, os_rel, arch, catrel): logger.debug("%s: RemoveCheckpkgResults(%s, %s, %s)", self, os_rel, arch, catrel) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr(sqlbuilder.Delete( CheckpkgErrorTag.sqlmeta.table, sqlobject.AND( CheckpkgErrorTag.q.srv4_file==self, CheckpkgErrorTag.q.os_rel==os_rel, CheckpkgErrorTag.q.arch==arch, CheckpkgErrorTag.q.catrel==catrel)))) def RemoveAllCheckpkgResults(self): logger.debug("%s: RemoveAllCheckpkgResults()", self) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr(sqlbuilder.Delete( CheckpkgErrorTag.sqlmeta.table, CheckpkgErrorTag.q.srv4_file==self))) def RemoveOverrides(self): logger.debug("%s: RemoveOverrides()", self) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr(sqlbuilder.Delete( CheckpkgOverride.sqlmeta.table, CheckpkgOverride.q.srv4_file==self))) def GetUnicodeOrNone(self, s): """Tries to decode UTF-8. If the object does not decode as UTF-8, it's forced to do so, while ignoring any potential errors. Returns: a unicode object or a None type. """ if s is None: return None if type(s) != unicode: try: s = unicode(s, 'utf-8') except UnicodeDecodeError, e: s = s.decode("utf-8", "ignore") s = s + u" (bad unicode detected)" return s
class Srv4FileStats(sqlobject.SQLObject): """Represents a srv4 file. It focuses on the stats, but it can as well represent just a srv4 file. """ arch = sqlobject.ForeignKey('Architecture', notNone=True) basename = sqlobject.UnicodeCol(notNone=True) catalogname = sqlobject.UnicodeCol(notNone=True) # The data structure can be missing - necessary for fake SUNW # packages. data_obj = sqlobject.ForeignKey('Srv4FileStatsBlob', notNone=False) filename_arch = sqlobject.ForeignKey('Architecture', notNone=True) latest = sqlobject.BoolCol(notNone=True) maintainer = sqlobject.ForeignKey('Maintainer', notNone=False) md5_sum = sqlobject.UnicodeCol(notNone=True, unique=True, length=32) size = sqlobject.IntCol() mtime = sqlobject.DateTimeCol(notNone=False) os_rel = sqlobject.ForeignKey('OsRelease', notNone=True) pkginst = sqlobject.ForeignKey('Pkginst', notNone=True) registered = sqlobject.BoolCol(notNone=True) use_to_generate_catalogs = sqlobject.BoolCol(notNone=True) rev = sqlobject.UnicodeCol(notNone=False) stats_version = sqlobject.IntCol(notNone=True) version_string = sqlobject.UnicodeCol(notNone=True) in_catalogs = sqlobject.MultipleJoin('Srv4FileInCatalog', joinColumn='srv4file_id') files = sqlobject.MultipleJoin('CswFile', joinColumn='id') def DeleteAllDependentObjects(self): data_obj = self.data_obj self.data_obj = None if data_obj: # It could be already missing data_obj.destroySelf() self.RemoveAllCswFiles() self.RemoveAllCheckpkgResults() self.RemoveOverrides() def RemoveAllCswFiles(self): # Removing existing files, using sqlbuilder to use sql-level # mechanisms without interacting with Python. # http://www.mail-archive.com/[email protected]/msg00520.html sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete(CswFile.sqlmeta.table, CswFile.q.srv4_file == self))) def GetOverridesResult(self): return CheckpkgOverride.select(CheckpkgOverride.q.srv4_file == self) def GetErrorTagsResult(self, os_rel, arch, catrel): assert arch.name != 'all', ( "Asked for the 'all' architecture, this is not valid " "for GetErrorTagsResult().") return CheckpkgErrorTag.select( sqlobject.AND(CheckpkgErrorTag.q.srv4_file == self, CheckpkgErrorTag.q.os_rel == os_rel, CheckpkgErrorTag.q.arch == arch, CheckpkgErrorTag.q.catrel == catrel)) def RemoveCheckpkgResults(self, os_rel, arch, catrel): logging.debug("%s: RemoveCheckpkgResults(%s, %s, %s)", self, os_rel, arch, catrel) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete( CheckpkgErrorTag.sqlmeta.table, sqlobject.AND(CheckpkgErrorTag.q.srv4_file == self, CheckpkgErrorTag.q.os_rel == os_rel, CheckpkgErrorTag.q.arch == arch, CheckpkgErrorTag.q.catrel == catrel)))) def RemoveAllCheckpkgResults(self): logging.debug("%s: RemoveAllCheckpkgResults()", self) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete(CheckpkgErrorTag.sqlmeta.table, CheckpkgErrorTag.q.srv4_file == self))) def RemoveOverrides(self): logging.debug("%s: RemoveOverrides()", self) sqlobject.sqlhub.processConnection.query( sqlobject.sqlhub.processConnection.sqlrepr( sqlbuilder.Delete(CheckpkgOverride.sqlmeta.table, CheckpkgOverride.q.srv4_file == self))) def __unicode__(self): return (u"Package: %s-%s, %s" % (self.catalogname, self.version_string, self.arch.name)) def GetStatsStruct(self): return cPickle.loads(str(self.data_obj.pickle)) def GetRestRepr(self): mimetype = "application/x-vnd.opencsw.pkg;type=srv4-detail" data = { 'arch': self.arch.name, 'basename': self.basename, # For compatibility with the catalog parser from catalog.py 'file_basename': self.basename, 'catalogname': self.catalogname, 'filename_arch': self.filename_arch.name, 'maintainer_email': self.maintainer.email, 'maintainer_full_name': self.maintainer.full_name, 'md5_sum': self.md5_sum, 'mtime': unicode(self.mtime), 'osrel': self.os_rel.short_name, 'pkgname': self.pkginst.pkgname, 'rev': self.rev, 'size': self.size, 'version_string': self.version_string, # For compatibility with the catalog parser from catalog.py 'version': self.version_string, # 'in_catalogs': unicode([unicode(x) for x in self.in_catalogs]), } return mimetype, data