def list_privmsgs(handle=None): """ Return all private messages for given user handle. """ db_priv = DBProxy(PRIVDB) if handle: return db_priv.get(handle, set()) # flatten list of [set(1, 2), set(3, 4)] to set(1, 2, 3, 4) return set([_idx for indices in db_priv.values() for _idx in indices])
def queue_for_network(self): """ Queue message for networks, hosting or sending. """ log = logging.getLogger(__name__) # check all tags of message; if they match a message network, # either record for hosting servers, or schedule for delivery. for tag in self.tags: # server networks offered by this server, # message is for a network we host if tag in get_ini(section='msg', key='server_tags', split=True): with DBProxy('{0}trans'.format(tag)) as transdb: self.body = u''.join((self.body, format_origin_line())) self.save() transdb[self.idx] = self.idx log.info( '[{tag}] Stored for network (msgid {self.idx}).'.format( tag=tag, self=self)) # server networks this server is a member of, # message is for a another network, queue for delivery elif tag in get_ini(section='msg', key='network_tags', split=True): with DBProxy('{0}queues'.format(tag)) as queuedb: queuedb[self.idx] = tag log.info('[{tag}] Message (msgid {self.idx}) queued ' 'for delivery'.format(tag=tag, self=self))
def get(self, key, default=None): # pylint: disable=C0111, # Missing docstring from x84.bbs import ini log = logging.getLogger(__name__) adb = DBProxy(USERDB, 'attrs') if self.handle not in adb: if ini.CFG.getboolean('session', 'tap_db'): log.debug( 'User({!r}).get(key={!r}) returns default={!r}'.format( self.handle, key, default)) return default attrs = adb.get(self.handle, {}) if key not in attrs: if ini.CFG.getboolean('session', 'tap_db'): log.debug( 'User({!r}.get(key={!r}) returns default={!r}'.format( self.handle, key, default)) return default if ini.CFG.getboolean('session', 'tap_db'): log.debug('User({!r}.get(key={!r}) returns value.'.format( self.handle, key)) return attrs[key]
def delete(self): """ Delete group record, enforces referential integrity with Users. """ udb = DBProxy(USERDB) for chk_user in self.members: user = udb[chk_user] if self.name in user.groups: user.group_del(self.name) user.save() del DBProxy(GROUPDB)[self.name]
def list_msgs(tags=None): """ Return set of indices matching ``tags``, or all by default. """ if tags is not None and 0 != len(tags): msgs = set() db_tag = DBProxy(TAGDB) for tag in (_tag for _tag in tags if _tag in db_tag): msgs.update(db_tag[tag]) return msgs return set(int(key) for key in DBProxy(MSGDB).keys())
def delete(self): """ Delete group record from database, and from .groups of any users. """ udb = DBProxy(USERDB) for chk_user in self.members: user = udb[chk_user] if self.name in user.groups: user.group_del(self.name) user.save() del DBProxy(GROUPDB)[self.name]
def __delitem__(self, key): # pylint: disable=C0111, # Missing docstring uadb = DBProxy(USERDB, 'attrs') uadb.acquire() attrs = uadb[self.handle] if key in attrs: attrs.__delitem__(key) uadb[self.handle] = attrs uadb.release() logger.info("del attr %r for user '%s'.", key, self.handle)
def list_msgs(tags=None): """ Return set of Msg keys matching 1 or more ``tags``, or all. """ if tags is not None and 0 != len(tags): msgs = set() db_tag = DBProxy(TAGDB) for tag in (_tag for _tag in tags if _tag in db_tag): msgs.update(db_tag[tag]) return msgs return set([int(key) for key in DBProxy(MSGDB).keys()])
def delete(self): """ Remove user record from database, and as a member of any groups. """ gdb = DBProxy(GROUPDB) for gname in self._groups: group = gdb[gname] if self.handle in group.members: group.remove(self.handle) group.save() del DBProxy(USERDB)[self.handle] logger.info("deleted user '%s'.", self.handle)
def delete(self): """ Remove user from user and group databases. """ log = logging.getLogger(__name__) gdb = DBProxy(GROUPDB) with gdb: for gname in self._groups: group = gdb[gname] if self.handle in group.members: group.remove(self.handle) group.save() udb = DBProxy(USERDB) with udb: del udb[self.handle] log.info("deleted user '%s'.", self.handle)
def __delitem__(self, key): # pylint: disable=C0111, # Missing docstring log = logging.getLogger(__name__) uadb = DBProxy(USERDB, 'attrs') with uadb: # retrieve attributes from uadb, attrs = uadb.get(self.handle, {}) # delete attribute if exists if key in attrs: attrs.__delitem__(key) uadb[self.handle] = attrs log.info("User({!r}) delete attr {!r}." .format(self.handle, key))
def __delitem__(self, key): # pylint: disable=C0111, # Missing docstring log = logging.getLogger(__name__) uadb = DBProxy(USERDB, 'attrs') with uadb: # retrieve attributes from uadb, attrs = uadb.get(self.handle, {}) # delete attribute if exists if key in attrs: attrs.__delitem__(key) uadb[self.handle] = attrs log.info("User({!r}) delete attr {!r}.".format( self.handle, key))
def __setitem__(self, key, value): # pylint: disable=C0111, # Missing docstring if self.handle == 'anonymous': logger.debug("set attr %r not possible for 'anonymous'", key) return adb = DBProxy(USERDB, 'attrs') adb.acquire() if not self.handle in adb: adb[self.handle] = dict([(key, value), ]) else: attrs = adb[self.handle] attrs.__setitem__(key, value) adb[self.handle] = attrs adb.release() logger.info("set attr %r for user '%s'.", key, self.handle)
def find_user(handle): """ Given handle, discover and return matching database key case insensitively. The returned value may not be equal to the argument, or None if not found. """ for key in DBProxy(USERDB).keys(): if handle.lower() == key.decode('utf8').lower(): return key
def list_users(): """ Returns all user handles. :rtype: list :returns list of user handles. """ return [handle.decode('utf8') for handle in DBProxy(USERDB).keys()]
def get_user(handle): """ Returns User record by handle. :rtype: User :returns: instance of :class:`User` """ return DBProxy(USERDB)[handle]
def _apply_groups(self): """ Enforce referential integrity of user's groups. """ log = logging.getLogger(__name__) gdb = DBProxy(GROUPDB) with gdb: for chk_grp in self._groups: if chk_grp not in gdb: gdb[chk_grp] = Group(chk_grp, set([self.handle])) log.info("created group {!r} for user {!r}.".format( chk_grp, self.handle)) # ensure membership in existing groups group = gdb[chk_grp] if self.handle not in group.members: group.add(self.handle) group.save() for gname, group in gdb.items(): if gname not in self._groups and self.handle in group.members: group.remove(self.handle) group.save()
def find_user(handle): """ Discover and return matching user by ``handle``, case-insensitive. :returns: matching handle as str, or None if not found. :rtype: None or str. """ for key in DBProxy(USERDB).keys(): if handle.lower() == key.decode('utf8').lower(): return key
def _apply_groups(self): """ Enforce referential integrity of user's groups. """ log = logging.getLogger(__name__) gdb = DBProxy(GROUPDB) with gdb: for chk_grp in self._groups: if chk_grp not in gdb: gdb[chk_grp] = Group(chk_grp, set([self.handle])) log.info("created group {!r} for user {!r}." .format(chk_grp, self.handle)) # ensure membership in existing groups group = gdb[chk_grp] if self.handle not in group.members: group.add(self.handle) group.save() for gname, group in gdb.items(): if gname not in self._groups and self.handle in group.members: group.remove(self.handle) group.save()
def save(self): """ Save user record to database. """ log = logging.getLogger(__name__) assert isinstance(self._handle, unicode), ('handle must be unicode') assert len(self._handle) > 0, ('handle must be non-zero length') assert (None, None) != self._password, ('password must be set') assert self._handle != u'anonymous', ('anonymous may not be saved.') udb = DBProxy(USERDB) with udb: if 0 == len(udb) and self.is_sysop is False: log.warn('{!r}: First new user becomes sysop.'.format( self.handle)) self.group_add(u'sysop') is_new = self.handle not in udb udb[self.handle] = self if is_new: log.info("saved new user '%s'.", self.handle) adb = DBProxy(USERDB, 'attrs') with adb: if self.handle not in adb: adb[self.handle] = dict() self._apply_groups()
def save(self): """ (re-)Save user record to database. Changes to user record to not automatically persist. A call to the .save() method must be done. """ log = logging.getLogger(__name__) assert type(self._handle) is unicode, ('handle must be unicode') assert len(self._handle) > 0, ('handle must be non-zero length') assert (None, None) != self._password, ('password must be set') assert self._handle != u'anonymous', ('anonymous may not be saved.') udb = DBProxy(USERDB) with udb: if 0 == len(udb) and self.is_sysop is False: log.warn('{!r}: First new user becomes sysop.'.format( self.handle)) self.group_add(u'sysop') udb[self.handle] = self adb = DBProxy(USERDB, 'attrs') with adb: if self.handle not in adb: adb[self.handle] = dict() self._apply_groups() log.info("saved user '%s'.", self.handle)
def get(self, key, default=None): # pylint: disable=C0111, # Missing docstring adb = DBProxy(USERDB, 'attrs') adb.acquire() if not self.handle in adb: logger.debug( '%r GET %r: default; missing attrs.', self.handle, key) val = default else: attrs = adb[self.handle] if not key in attrs: logger.debug('%r GET %r: default', self.handle, key) val = default else: logger.debug('%r GET %r%s.' % ( self.handle, key, ' (size: %d)' % (len(attrs[key]),) if hasattr(attrs[key], '__len__') else '(1)')) val = attrs[key] adb.release() return val
def get(self, key, default=None): # pylint: disable=C0111, # Missing docstring from x84.bbs import ini log = logging.getLogger(__name__) adb = DBProxy(USERDB, 'attrs') if self.handle not in adb: if ini.CFG.getboolean('session', 'tap_db'): log.debug('User({!r}).get(key={!r}) returns default={!r}' .format(self.handle, key, default)) return default attrs = adb.get(self.handle, {}) if key not in attrs: if ini.CFG.getboolean('session', 'tap_db'): log.debug('User({!r}.get(key={!r}) returns default={!r}' .format(self.handle, key, default)) return default if ini.CFG.getboolean('session', 'tap_db'): log.debug('User({!r}.get(key={!r}) returns value.' .format(self.handle, key)) return attrs[key]
def save(self): """ (re-)Save user record to databases. Changes to user record to not automaticly persist. a call to the .save method must be done. """ assert type(self._handle) is unicode, ('handle must be unicode') assert len(self._handle) > 0, ('handle must be non-zero length') assert (None, None) != self._password, ('password must be set') assert self._handle != u'anonymous', ( 'anonymous user my not be saved.') udb = DBProxy(USERDB) udb.acquire() if 0 == len(udb) and self.is_sysop is False: logger.warn('%s: First new user becomes sysop.', self.handle) self.group_add(u'sysop') udb[self.handle] = self adb = DBProxy(USERDB, 'attrs') adb.acquire() if not self.handle in adb: adb[self.handle] = dict() adb.release() self._apply_groups(DBProxy(GROUPDB)) udb.release() logger.info("saved user '%s'.", self.handle)
def __setitem__(self, key, value): # pylint: disable=C0111, # Missing docstring log = logging.getLogger(__name__) adb = DBProxy(USERDB, 'attrs') if self.handle == 'anonymous': log.debug("set attr {!r} not possible for 'anonymous'".format(key)) return with adb: if self.handle not in adb: adb[self.handle] = dict([ (key, value), ]) else: attrs = adb[self.handle] attrs.__setitem__(key, value) adb[self.handle] = attrs log.debug("set attr {!r} for user {!r}.".format(key, self.handle))
def __setitem__(self, key, value): # pylint: disable=C0111, # Missing docstring if self.handle == 'anonymous': logger.debug("set attr %r not possible for 'anonymous'", key) return adb = DBProxy(USERDB, 'attrs') adb.acquire() if not self.handle in adb: adb[self.handle] = dict([ (key, value), ]) else: attrs = adb[self.handle] attrs.__setitem__(key, value) adb[self.handle] = attrs adb.release() logger.info("set attr %r for user '%s'.", key, self.handle)
def get(self, key, default=None): # pylint: disable=C0111, # Missing docstring adb = DBProxy(USERDB, 'attrs') adb.acquire() if not self.handle in adb: logger.debug('%r GET %r: default; missing attrs.', self.handle, key) val = default else: attrs = adb[self.handle] if not key in attrs: logger.debug('%r GET %r: default', self.handle, key) val = default else: logger.debug('%r GET %r%s.' % (self.handle, key, ' (size: %d)' % (len(attrs[key]), ) if hasattr( attrs[key], '__len__') else '(1)')) val = attrs[key] adb.release() return val
def save(self): """ Save group record to database. """ DBProxy(GROUPDB)[self.name] = self
def save(self): """ (re-)Save user record to databases. Changes to user record to not automaticly persist. a call to the .save method must be done. """ assert type(self._handle) is unicode, ('handle must be unicode') assert len(self._handle) > 0, ('handle must be non-zero length') assert (None, None) != self._password, ('password must be set') assert self._handle != u'anonymous', ( 'anonymous user may not be saved.') udb = DBProxy(USERDB) udb.acquire() if 0 == len(udb) and self.is_sysop is False: logger.warn('%s: First new user becomes sysop.', self.handle) self.group_add(u'sysop') udb[self.handle] = self adb = DBProxy(USERDB, 'attrs') adb.acquire() if not self.handle in adb: adb[self.handle] = dict() adb.release() self._apply_groups(DBProxy(GROUPDB)) udb.release() logger.info("saved user '%s'.", self.handle)
def save(self, send_net=True, ctime=None): """ Save message in 'Msgs' sqlite db, and record index in 'tags' db. """ from x84.bbs.ini import CFG from x84.bbs import getsession session = getsession() use_session = bool(session is not None) log = logging.getLogger(__name__) new = self.idx is None or self._stime is None # persist message record to MSGDB db_msg = DBProxy(MSGDB, use_session=use_session) with db_msg: if new: self.idx = max(map(int, db_msg.keys()) or [-1]) + 1 if ctime is not None: self._ctime = self._stime = ctime else: self._stime = datetime.datetime.now() new = True db_msg['%d' % (self.idx, )] = self # persist message idx to TAGDB db_tag = DBProxy(TAGDB, use_session=use_session) with db_tag: for tag in db_tag.keys(): msgs = db_tag[tag] if tag in self.tags and self.idx not in msgs: msgs.add(self.idx) db_tag[tag] = msgs log.debug("msg {self.idx} tagged '{tag}'".format(self=self, tag=tag)) elif tag not in self.tags and self.idx in msgs: msgs.remove(self.idx) db_tag[tag] = msgs log.info("msg {self.idx} removed tag '{tag}'".format( self=self, tag=tag)) for tag in [_tag for _tag in self.tags if _tag not in db_tag]: db_tag[tag] = set([self.idx]) # persist message as child to parent; if not hasattr(self, 'parent'): self.parent = None assert self.parent not in self.children if self.parent is not None: parent_msg = get_msg(self.parent) if self.idx != parent_msg.idx: parent_msg.children.add(self.idx) parent_msg.save() else: log.error('Parent idx same as message idx; stripping') self.parent = None with db_msg: db_msg['%d' % (self.idx)] = self if send_net and new and CFG.has_option('msg', 'network_tags'): self.queue_for_network() log.info( u"saved {new}{public}msg {post}, addressed to '{self.recipient}'.". format(new='new ' if new else '', public='public ' if 'public' in self.tags else '', post='post' if self.parent is None else 'reply', self=self))
def get_msg(idx=0): """ Return Msg record instance by index ``idx``. """ return DBProxy(MSGDB)['%d' % int(idx)]
def get_user(handle): """ Returns User record, keyed by handle. """ return DBProxy(USERDB)[handle]
def list_tags(): """ Return set of available tags. """ return [_tag.decode('utf8') for _tag in DBProxy(TAGDB).keys()]
def save(self): """ Save message in 'Msgs' sqlite db, and record index in 'tags' db. """ db_msg = DBProxy(MSGDB) new = self.idx is None or self._stime is None # persist message record to MSGDB db_msg.acquire() if new: self.idx = max([int(key) for key in db_msg.keys()] or [-1]) + 1 self._stime = datetime.datetime.now() new = True db_msg['%d' % (self.idx,)] = self db_msg.release() # persist message idx to TAGDB db_tag = DBProxy(TAGDB) db_tag.acquire() for tag, msgs in db_tag.iteritems(): if tag in self.tags and not self.idx in msgs: msgs.add(self.idx) db_tag[tag] = msgs logger.info(u"msg %s tagged '%s'", self.idx, tag,) elif tag not in self.tags and self.idx in msgs: msgs.remove(self.idx) db_tag[tag] = msgs logger.info(u"msg %s untagged '%s'", self.idx, tag,) for tag in [_tag for _tag in self.tags if not _tag in db_tag]: db_tag[tag] = set([self.idx]) db_tag.release() # persist message as child to parent; if not hasattr(self, 'parent'): self.parent = None assert self.parent not in self.children if self.parent is not None: parent_msg = get_msg(self.parent) if not hasattr(parent_msg, 'children'): parent_msg.children = set( ) # intermediary conversion; deleteme parent_msg.children.add(self.idx) parent_msg.save() logger.info(u"saved %s%s%s, addressed to '%s'.", 'new ' if new else u'', 'public ' if 'public' in self.tags else u'', 'message' if self.parent is None else u'reply', self.recipient,)
def __getitem__(self, key): # pylint: disable=C0111, # Missing docstring return DBProxy(USERDB, 'attrs')[self.handle][key]
def save(self, send_net=True, ctime=None): """ Save message in 'Msgs' sqlite db, and record index in 'tags' db. """ from x84.bbs.ini import CFG from x84.bbs import getsession session = getsession() use_session = bool(session is not None) log = logging.getLogger(__name__) new = self.idx is None or self._stime is None # persist message record to MSGDB db_msg = DBProxy(MSGDB, use_session=use_session) with db_msg: if new: self.idx = max([int(key) for key in db_msg.keys()] or [-1]) + 1 if ctime is not None: self._ctime = self._stime = ctime else: self._stime = datetime.datetime.now() new = True db_msg['%d' % (self.idx,)] = self # persist message idx to TAGDB db_tag = DBProxy(TAGDB, use_session=use_session) with db_tag: for tag in db_tag.keys(): msgs = db_tag[tag] if tag in self.tags and self.idx not in msgs: msgs.add(self.idx) db_tag[tag] = msgs log.debug("msg {self.idx} tagged '{tag}'" .format(self=self, tag=tag)) elif tag not in self.tags and self.idx in msgs: msgs.remove(self.idx) db_tag[tag] = msgs log.info("msg {self.idx} removed tag '{tag}'" .format(self=self, tag=tag)) for tag in [_tag for _tag in self.tags if _tag not in db_tag]: db_tag[tag] = set([self.idx]) # persist message as child to parent; if not hasattr(self, 'parent'): self.parent = None assert self.parent not in self.children if self.parent is not None: parent_msg = get_msg(self.parent) if self.idx != parent_msg.idx: parent_msg.children.add(self.idx) parent_msg.save() else: log.error('Parent idx same as message idx; stripping') self.parent = None with db_msg: db_msg['%d' % (self.idx)] = self if send_net and new and CFG.has_option('msg', 'network_tags'): self.queue_for_network() log.info( u"saved {new}{public}msg {post}, addressed to '{self.recipient}'." .format(new='new ' if new else '', public='public ' if 'public' in self.tags else '', post='post' if self.parent is None else 'reply', self=self))
def save(self, send_net=True, ctime=None): """ Save message to database, recording 'tags' db. As a side-effect, it may queue message for delivery to external systems, when configured. """ log = logging.getLogger(__name__) session = getsession() use_session = bool(session is not None) new = self.idx is None or self._stime is None # persist message record to MSGDB with DBProxy(MSGDB, use_session=use_session) as db_msg: if new: self.idx = max(map(int, db_msg.keys()) or [-1]) + 1 if ctime is not None: self._ctime = self._stime = ctime else: self._stime = datetime.datetime.now() new = True db_msg['%d' % (self.idx, )] = self # persist message idx to TAGDB with DBProxy(TAGDB, use_session=use_session) as db_tag: for tag in db_tag.keys(): msgs = db_tag[tag] if tag in self.tags and self.idx not in msgs: msgs.add(self.idx) db_tag[tag] = msgs log.debug("msg {self.idx} tagged '{tag}'".format(self=self, tag=tag)) elif tag not in self.tags and self.idx in msgs: msgs.remove(self.idx) db_tag[tag] = msgs log.info("msg {self.idx} removed tag '{tag}'".format( self=self, tag=tag)) for tag in [_tag for _tag in self.tags if _tag not in db_tag]: db_tag[tag] = set([self.idx]) # persist message as child to parent; assert self.parent not in self.children, ('circular reference', self.parent, self.children) if self.parent is not None: try: parent_msg = get_msg(self.parent) except KeyError: log.warn('Child message {0}.parent = {1}: ' 'parent does not exist!'.format( self.idx, self.parent)) else: if self.idx != parent_msg.idx: parent_msg.children.add(self.idx) parent_msg.save() else: log.error('Parent idx same as message idx; stripping') self.parent = None with db_msg: db_msg['%d' % (self.idx)] = self # persist message record to PRIVDB if 'public' not in self.tags: with DBProxy(PRIVDB, use_session=use_session) as db_priv: db_priv[self.recipient] = (db_priv.get(self.recipient, set()) | set([self.idx])) # if either any of 'server_tags' or 'network_tags' are enabled, # then queue for potential delivery. if send_net and new and (get_ini(section='msg', key='network_tags') or get_ini(section='msg', key='server_tags')): self.queue_for_network() log.info(u"saved {new} {public_or_private} {message_or_reply}" u", addressed to '{self.recipient}'.".format( new='new ' if new else '', public_or_private=('public' if 'public' in self.tags else 'private'), message_or_reply=('message' if self.parent is None else 'reply'), self=self))