openmedialibrary/oml/user/models.py

352 lines
11 KiB
Python
Raw Normal View History

2014-05-04 17:26:43 +00:00
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import json
2014-08-09 15:03:16 +00:00
import sqlalchemy as sa
2014-05-04 17:26:43 +00:00
from changelog import Changelog
2014-08-12 08:16:57 +00:00
from db import MutableDict
from queryparser import Parser
import db
2014-09-02 22:32:44 +00:00
import json_pickler
2014-05-04 17:26:43 +00:00
import settings
import state
2014-05-17 14:26:59 +00:00
import logging
2015-11-29 14:56:38 +00:00
logger = logging.getLogger(__name__)
2014-05-17 14:26:59 +00:00
2014-05-04 17:26:43 +00:00
class User(db.Model):
2014-08-09 15:03:16 +00:00
__tablename__ = 'user'
2014-05-04 17:26:43 +00:00
2014-08-09 15:03:16 +00:00
created = sa.Column(sa.DateTime())
modified = sa.Column(sa.DateTime())
2014-08-09 15:03:16 +00:00
id = sa.Column(sa.String(43), primary_key=True)
2014-09-02 22:32:44 +00:00
info = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json_pickler)))
2014-05-04 17:26:43 +00:00
2014-08-09 15:03:16 +00:00
nickname = sa.Column(sa.String(256), unique=True)
2014-05-04 17:26:43 +00:00
2014-08-09 15:03:16 +00:00
pending = sa.Column(sa.String(64)) # sent|received
queued = sa.Column(sa.Boolean())
peered = sa.Column(sa.Boolean())
online = sa.Column(sa.Boolean())
2014-05-04 17:26:43 +00:00
def __repr__(self):
return self.id
@classmethod
def get(cls, id):
return cls.query.filter_by(id=id).first()
@classmethod
def get_or_create(cls, id):
user = cls.get(id)
if not user:
user = cls(id=id, peered=False, online=False)
user.info = {}
2015-12-01 08:59:52 +00:00
if state.nodes and state.nodes._local and id in state.nodes._local._nodes:
user.info['local'] = state.nodes._local._nodes[id]
user.info['username'] = user.info['local']['username']
user.update_name()
2014-05-04 17:26:43 +00:00
user.save()
return user
def save(self):
2014-08-09 16:14:14 +00:00
state.db.session.add(self)
state.db.session.commit()
2014-05-04 17:26:43 +00:00
2014-05-25 12:16:04 +00:00
@property
def name(self):
name = self.nickname if self.id != settings.USER_ID else ''
return name
@property
def library(self):
l = List.get_or_create(self.id, '')
if l.index_ != -1:
l.index_ = -1
l.save()
return l
2014-05-04 17:26:43 +00:00
def json(self):
j = {}
if self.info:
j.update(self.info)
j['id'] = self.id
if self.pending:
j['pending'] = self.pending
j['peered'] = self.peered
j['online'] = self.is_online()
2014-05-25 12:16:04 +00:00
j['nickname'] = self.info.get('nickname')
j['username'] = self.info.get('username') if self.id != settings.USER_ID else settings.preferences['username']
j['name'] = self.name
2014-05-04 17:26:43 +00:00
return j
def is_online(self):
return state.nodes and state.nodes.is_online(self.id)
2014-05-04 17:26:43 +00:00
def lists_json(self):
self.library
return [l.json() for l in self.lists.order_by('index_')]
2014-05-04 17:26:43 +00:00
def clear_list_cache(self):
if self.id == settings.USER_ID:
prefix = ':'
else:
prefix = self.id + ':'
for key in list(settings.list_cache):
if key.startswith(prefix):
del settings.list_cache[key]
def clear_smart_list_cache(self):
qs = List.query.filter_by(type='smart')
smart_lists = [':%d' % l.id for l in qs]
for key in list(settings.list_cache):
if key in smart_lists:
del settings.list_cache[key]
2014-05-04 17:26:43 +00:00
def update_peering(self, peered, username=None):
2014-05-13 10:36:02 +00:00
was_peering = self.peered
2014-05-04 17:26:43 +00:00
if peered:
2015-12-01 08:59:52 +00:00
logging.debug('update_peering, pending: %s queued: %s', self.pending, self.queued)
self.queued = self.pending != 'sent'
2014-05-04 17:26:43 +00:00
self.pending = ''
if username:
self.info['username'] = username
2014-05-25 12:16:04 +00:00
self.update_name()
2014-05-17 11:45:57 +00:00
# FIXME: need to set peered to False to not trigger changelog event
# before other side receives acceptPeering request
self.peered = False
self.save()
2014-05-13 10:36:02 +00:00
if not was_peering:
Changelog.record(state.user(), 'addpeer', self.id, self.nickname)
2014-05-17 11:45:57 +00:00
self.peered = True
self.save()
2014-05-04 17:26:43 +00:00
else:
2014-05-13 10:36:02 +00:00
self.pending = ''
2014-05-04 17:26:43 +00:00
self.peered = False
2015-12-01 08:59:52 +00:00
self.queued = False
2014-05-25 12:16:04 +00:00
self.update_name()
2014-05-17 11:45:57 +00:00
self.save()
2014-05-13 10:36:02 +00:00
List.query.filter_by(user_id=self.id).delete()
2014-05-04 17:26:43 +00:00
for i in self.items:
i.users.remove(self)
if not i.users:
i.delete()
2014-05-12 23:43:27 +00:00
Changelog.query.filter_by(user_id=self.id).delete()
if self.id in settings.ui['showFolder']:
del settings.ui['showFolder'][self.id]
self.clear_list_cache()
2014-05-13 10:36:02 +00:00
self.save()
if was_peering:
Changelog.record(state.user(), 'removepeer', self.id)
2014-05-04 17:26:43 +00:00
self.save()
2014-05-25 12:16:04 +00:00
def update_name(self):
if self.id == settings.USER_ID:
name = settings.preferences.get('username', 'anonymous')
else:
name = self.info.get('nickname') or self.info.get('username') or 'anonymous'
nickname = name
2014-05-04 17:26:43 +00:00
n = 2
while self.query.filter_by(nickname=nickname).filter(User.id!=self.id).first():
2014-05-25 12:16:04 +00:00
nickname = '%s [%d]' % (name, n)
2014-05-04 17:26:43 +00:00
n += 1
self.nickname = nickname
2015-11-26 11:06:01 +00:00
def migrate_id(self, service_id):
if len(service_id) == 16:
statements = [
2015-11-26 11:12:35 +00:00
"DELETE FROM user WHERE id = '{nid}'",
2015-11-26 11:06:01 +00:00
"UPDATE user SET id = '{nid}' WHERE id = '{oid}'",
"UPDATE list SET user_id = '{nid}' WHERE user_id = '{oid}'",
"UPDATE useritem SET user_id = '{nid}' WHERE user_id = '{oid}'",
"UPDATE changelog SET user_id = '{nid}' WHERE user_id = '{oid}'",
]
with db.session() as session:
for sql in statements:
2015-11-26 11:12:35 +00:00
session.connection().execute(sql.format(oid=self.id, nid=service_id))
2015-11-26 11:06:01 +00:00
session.commit()
2014-08-09 16:14:14 +00:00
list_items = sa.Table('listitem', db.metadata,
2014-08-09 15:03:16 +00:00
sa.Column('list_id', sa.Integer(), sa.ForeignKey('list.id')),
sa.Column('item_id', sa.String(32), sa.ForeignKey('item.id'))
2014-05-04 17:26:43 +00:00
)
class List(db.Model):
2014-08-09 15:03:16 +00:00
__tablename__ = 'list'
2014-05-04 17:26:43 +00:00
2014-08-09 15:03:16 +00:00
id = sa.Column(sa.Integer(), primary_key=True)
name = sa.Column(sa.String())
index_ = sa.Column(sa.Integer())
2014-05-04 17:26:43 +00:00
2014-08-09 15:03:16 +00:00
type = sa.Column(sa.String(64))
2014-09-02 22:32:44 +00:00
_query = sa.Column('query', MutableDict.as_mutable(sa.PickleType(pickler=json_pickler)))
2014-05-04 17:26:43 +00:00
2014-08-09 15:03:16 +00:00
user_id = sa.Column(sa.String(43), sa.ForeignKey('user.id'))
user = sa.orm.relationship('User', backref=sa.orm.backref('lists', lazy='dynamic'))
items = sa.orm.relationship('Item', secondary=list_items,
backref=sa.orm.backref('lists', lazy='dynamic'))
2014-05-04 17:26:43 +00:00
@classmethod
def get(cls, user_id, name=None):
2014-05-18 23:24:04 +00:00
if name is None:
2014-05-04 17:26:43 +00:00
user_id, name = cls.get_user_name(user_id)
return cls.query.filter_by(user_id=user_id, name=name).first()
@classmethod
def get_user_name(cls, user_id):
2014-05-18 23:24:04 +00:00
nickname, name = user_id.split(':', 1)
2014-05-04 17:26:43 +00:00
if nickname:
user = User.query.filter_by(nickname=nickname).first()
user_id = user.id
else:
user_id = settings.USER_ID
return user_id, name
@classmethod
2014-05-18 23:24:04 +00:00
def get_or_create(cls, user_id, name=None, query=None):
if name is None:
2014-05-04 17:26:43 +00:00
user_id, name = cls.get_user_name(user_id)
l = cls.get(user_id, name)
if not l:
2014-05-18 23:24:04 +00:00
l = cls.create(user_id, name, query)
2014-05-04 17:26:43 +00:00
return l
@classmethod
def create(cls, user_id, name, query=None):
2014-05-18 23:24:04 +00:00
prefix = name
n = 2
while cls.get(user_id, name):
name = '%s [%s]' % (prefix, n)
n += 1
l = cls(user_id=user_id, name=name)
2014-05-04 17:26:43 +00:00
l._query = query
l.type = 'smart' if l._query else 'static'
l.index_ = cls.query.filter_by(user_id=user_id).count()
2014-08-09 16:14:14 +00:00
state.db.session.add(l)
state.db.session.commit()
2014-05-04 17:26:43 +00:00
if user_id == settings.USER_ID:
if not l._query:
2014-05-25 18:06:12 +00:00
Changelog.record(state.user(), 'addlist', l.name)
2014-05-04 17:26:43 +00:00
return l
2014-05-25 18:06:12 +00:00
@classmethod
def rename_user(cls, old, new):
for l in cls.query.filter(cls._query!=None):
def update_conditions(conditions):
changed = False
for c in conditions:
if 'conditions' in c:
changed = update_conditions(conditions)
else:
if c.get('key') == 'list' and c.get('value', '').startswith('%s:' % old):
c['value'] = '%s:%s' % new, c['value'].split(':', 1)[1]
changed = True
return changed
if update_conditions(l._query.get('conditions', [])):
l.save()
2014-05-04 17:26:43 +00:00
def add_items(self, items):
from item.models import Item
for item_id in items:
i = Item.get(item_id)
2014-05-18 03:01:24 +00:00
if i:
self.items.append(i)
if self.user_id == settings.USER_ID:
i.queue_download()
i.update()
2014-08-09 16:14:14 +00:00
state.db.session.add(self)
state.db.session.commit()
2014-05-12 12:57:47 +00:00
if self.user_id == settings.USER_ID:
Changelog.record(self.user, 'addlistitems', self.name, items)
self.user.clear_smart_list_cache()
self.user.clear_list_cache()
def get_items(self):
if self.type == 'smart':
from item.models import Item, user_items
return Parser(Item, user_items).find({'query': self._query})
else:
return self.items
2014-05-04 17:26:43 +00:00
def remove_items(self, items):
from item.models import Item
for item_id in items:
i = Item.get(item_id)
2014-05-19 01:36:37 +00:00
if i in self.items:
self.items.remove(i)
2014-05-12 12:57:47 +00:00
i.update()
2014-08-09 16:14:14 +00:00
state.db.session.add(self)
state.db.session.commit()
2014-05-12 12:57:47 +00:00
if self.user_id == settings.USER_ID:
Changelog.record(self.user, 'removelistitems', self.name, items)
self.user.clear_smart_list_cache()
self.user.clear_list_cache()
2014-05-04 17:26:43 +00:00
def remove(self):
if not self._query:
for i in self.items:
self.items.remove(i)
if not self._query:
2014-05-12 12:57:47 +00:00
if self.user_id == settings.USER_ID:
Changelog.record(self.user, 'removelist', self.name)
2014-08-09 16:14:14 +00:00
state.db.session.delete(self)
state.db.session.commit()
2014-05-04 17:26:43 +00:00
@property
def public_id(self):
2014-05-12 12:57:47 +00:00
id = ''
if self.user_id != settings.USER_ID:
id += self.user.nickname
2014-09-02 22:32:44 +00:00
id = '%s:%s' % (id, self.name)
2014-05-12 12:57:47 +00:00
return id
@property
def find_id(self):
2014-05-04 17:26:43 +00:00
id = ''
if self.user_id != settings.USER_ID:
id += self.user_id
2014-09-02 22:32:44 +00:00
id = '%s:%s' % (id, self.id)
2014-05-04 17:26:43 +00:00
return id
2016-01-04 10:23:54 +00:00
2014-05-12 12:57:47 +00:00
def __repr__(self):
2015-03-07 16:19:24 +00:00
return self.public_id
2014-05-04 17:26:43 +00:00
def items_count(self):
key = self.find_id
2016-01-05 16:14:57 +00:00
if key in settings.list_cache:
value = settings.list_cache[key]
else:
if self.type == 'smart':
value = self.get_items().count()
2014-05-26 11:41:59 +00:00
else:
value = len(self.items)
2016-01-05 16:14:57 +00:00
settings.list_cache[key] = value
2014-05-26 11:41:59 +00:00
return value
2014-05-04 17:26:43 +00:00
def json(self):
r = {
'id': self.public_id,
2014-05-25 12:16:04 +00:00
'user': self.user.name,
2014-05-04 17:26:43 +00:00
'name': self.name,
'index': self.index_,
2014-05-04 17:26:43 +00:00
'items': self.items_count(),
'type': self.type
}
if self.name == '':
r['name'] = 'Library'
r['type'] = 'library'
del r['index']
2014-05-04 17:26:43 +00:00
if self.type == 'smart':
r['query'] = self._query
return r
def save(self):
2014-08-09 16:14:14 +00:00
state.db.session.add(self)
state.db.session.commit()