openmedialibrary/oml/user/api.py

536 lines
14 KiB
Python

# -*- coding: utf-8 -*-
from copy import deepcopy
import json
import os
import ox
from changelog import add_record
from oxtornado import actions
from utils import update_dict, user_sort_key
from . import models
import settings
import state
import tor_request
import logging
logger = logging.getLogger(__name__)
def init(data):
'''
takes {
}
returns {
config
user
preferences
ui
}
'''
response = {}
if os.path.exists(settings.oml_data_path):
with open(settings.oml_data_path) as fd:
config = json.load(fd)
if not settings.FULLTEXT_SUPPORT:
config['itemKeys'] = [k for k in config['itemKeys'] if k['id'] != 'fulltext']
else:
config = {}
response['config'] = config
response['user'] = deepcopy(config['user'])
response['version'] = settings.MINOR_VERSION
if settings.preferences:
response['user']['preferences'] = settings.preferences
response['user']['id'] = settings.USER_ID
response['user']['online'] = state.online
if settings.ui:
for f in settings.ui['filters']:
if f['id'] == 'classification':
f['id'] = 'categories'
settings.ui._save()
response['user']['ui'] = settings.ui
return response
actions.register(init)
def public_init(data):
response = init(data)
name = response['user']['preferences']['username']
response['user'] = response['config']['user']
response['user']['preferences']['username'] = name
response['user']['ui']['page'] = ''
response['user']['ui']['showFolder'] = {'': True}
response['readOnly'] = True
for page in response['config']['pages']:
if page['id'] == 'preferences':
#page['parts'] = [p for p in page['parts'] if p['id'] in ('appearance', 'extensions')]
page['parts'] = [p for p in page['parts'] if p['id'] in ('appearance',)]
return response
actions.register(public_init, action='init', version='public')
def setPreferences(data):
'''
takes {
key: value,
'sub.key': value
}
'''
change_contact = 'contact' in data and \
data['contact'] != settings.preferences['contact']
change_username = 'username' in data and \
data['username'] != settings.preferences['username']
change_autostart = 'autostart' in data and \
data['autostart'] != settings.preferences['autostart']
if 'libraryPath' in data and \
data['libraryPath'] != settings.preferences['libraryPath']:
change_path = [settings.preferences['libraryPath'], data['libraryPath']]
else:
change_path = False
update_dict(settings.preferences, data)
if 'username' in data:
u = state.user()
u.update_name()
u.save()
if change_username:
add_record('editusername', data['username'])
if state.nodes and state.nodes.local:
state.nodes.local._update_if_ip_changed()
if change_contact:
add_record('editcontact', data['contact'])
if change_path:
state.tasks.queue('changelibrarypath', change_path)
if change_autostart:
import integration
if settings.preferences['autostart']:
integration.install_autostart()
else:
integration.uninstall_autostart()
return settings.preferences
actions.register(setPreferences, cache=False)
def resetUI(data):
'''
takes {
}
'''
ui_json = os.path.join(settings.data_path, 'ui.json')
if os.path.exists(ui_json):
os.unlink(ui_json)
settings.ui = settings.pdict(ui_json, settings.config['user']['ui'])
return settings.ui
actions.register(resetUI, cache=False)
def setUI(data):
'''
takes {
key: value,
'sub.key': value
}
'''
update_dict(settings.ui, data)
#return settings.ui
return {}
actions.register(setUI, cache=False)
def getUsers(data):
'''
returns {
users: []
}
'''
users = []
ids = set()
local = set()
for u in models.User.query.filter(models.User.id != settings.USER_ID).all():
users.append(u.json())
ids.add(u.id)
if state.nodes:
for id in state.nodes.local:
if id not in ids:
n = state.nodes.local[id].copy()
n['online'] = True
n['name'] = n['username']
users.append(n)
local.add(id)
for n in users:
n['local'] = n['id'] in local
users.sort(key=user_sort_key)
return {
"users": users
}
actions.register(getUsers)
def getUsersPublic(data):
return {
'users': []
}
actions.register(getUsersPublic, 'getUsers', version='public')
def getLists(data):
'''
returns {
lists: []
}
'''
from item.models import Item
from user.models import List
lists = []
lists.append({
'id': '',
'items': Item.query.count(),
'name': 'Libraries',
'type': 'libraries',
'user': None,
})
List.get_or_create(':Public')
for u in models.User.query.filter((models.User.peered==True)|(models.User.id==settings.USER_ID)):
lists += u.lists_json()
return {
'lists': lists
}
actions.register(getLists)
def getListsPublic(data):
'''
returns {
lists: []
}
'''
from item.models import Item
from sqlalchemy.sql import operators
user = state.user()
lists = []
lists.append({
'id': '',
'items': user.items.count(),
'name': 'Libraries',
'type': 'libraries',
'user': None,
})
lists += user.lists_json()
return {
'lists': lists
}
actions.register(getListsPublic, 'getLists', version='public')
def validate_query(query):
validate_conditions(query['conditions'])
def validate_conditions(conditions):
for c in conditions:
if 'conditions' in c:
if list(sorted(c.keys())) != ['conditions', 'operator']:
raise Exception('invalid query condition', c)
validate_conditions(c['conditions'])
else:
if list(sorted(c.keys())) != ['key', 'operator', 'value']:
raise Exception('invalid query condition', c)
if c['key'] == 'list' and ':' not in c['value']:
raise Exception('invalid query condition', c)
def addList(data):
'''
takes {
name
items
query
}
'''
logger.debug('addList %s', data)
user_id = settings.USER_ID
if 'query' in data:
validate_query(data['query'])
if data['name']:
l = models.List.create(user_id, data['name'], data.get('query'))
if 'items' in data:
l.add_items(data['items'])
return l.json()
else:
raise Exception('name not set')
return {}
actions.register(addList, cache=False)
def editList(data):
'''
takes {
id
name
query
}
'''
logger.debug('editList %s', data)
l = models.List.get_or_create(data['id'])
name = l.name
if 'name' in data:
l.name = data['name']
if 'query' in data and l.type != 'smart':
raise Exception('query only for smart lists')
if 'query' in data and l.type == 'smart':
validate_query(data['query'])
l._query = data['query']
if l.type == 'static' and name != l.name:
add_record('editlist', name, {'name': l.name})
l.save()
return l.json()
actions.register(editList, cache=False)
def removeList(data):
'''
takes {
id
}
'''
l = models.List.get(data['id'])
if l and l.name != 'Public':
l.remove()
return {}
actions.register(removeList, cache=False)
def addListItems(data):
'''
takes {
list
items
}
'''
if data['list'] == ':':
from item.models import Item
for item_id in data['items']:
i = Item.get(item_id)
i.queue_download()
i.update()
elif data['list'] and (data['list'].startswith(':') or
data['list'].endswith(':Public') or
data['list'].enswtih(':')):
l = models.List.get_or_create(data['list'])
if l:
if l.name in ('Public', '') and l.user_id != settings.USER_ID:
state.tasks.queue('upload', {
'user': l.user_id,
'items': data['items']
})
else:
l.add_items(data['items'])
state.cache.clear('group:')
return l.json()
return {}
actions.register(addListItems, cache=False)
def removeListItems(data):
'''
takes {
list
items
}
'''
l = models.List.get(data['list'])
if l:
l.remove_items(data['items'])
state.cache.clear('group:')
return l.json()
return {}
actions.register(removeListItems, cache=False)
def sortLists(data):
'''
takes {
ids
}
'''
n = 0
logger.debug('sortLists %s', data)
lists = ['Public']
for id in data['ids']:
l = models.List.get(id)
l.index_ = n
n += 1
if l.type == 'static':
lists.append(l.name)
state.db.session.add(l)
state.db.session.commit()
if lists:
add_record('orderlists', lists)
return {}
actions.register(sortLists, cache=False)
def editUser(data):
'''
takes {
id
nickname
}
'''
if 'nickname' in data:
p = models.User.get_or_create(data['id'])
if data['nickname']:
p.info['nickname'] = data['nickname']
elif 'nickname' in p.info:
del p.info['nickname']
old = p.nickname
p.update_name()
if old != p.nickname:
models.List.rename_user(old, p.nickname)
p.save()
return p.json()
return {}
actions.register(editUser, cache=False)
def sortUsers(data):
'''
takes {
ids
}
'''
n = 0
for id in data['ids']:
u = models.User.get(id)
u.info['index'] = n
n += 1
state.db.session.add(u)
state.db.session.commit()
if state.tasks:
state.tasks.queue('syncmetadata')
return {}
actions.register(sortUsers, cache=False)
def requestPeering(data):
'''
takes {
id
message
nickname (optional)
}
'''
if len(data.get('id', '')) != 16:
logger.debug('invalid user id')
return {}
u = models.User.get_or_create(data['id'])
u.pending = 'sent'
u.queued = True
u.info['message'] = data.get('message', '')
if data.get('nickname'):
u.info['nickname'] = data.get('nickname', '')
u.update_name()
u.save()
state.nodes.queue(u.id, 'peering', 'requestPeering')
return {}
actions.register(requestPeering, cache=False)
def acceptPeering(data):
'''
takes {
id
message
}
'''
if len(data.get('id', '')) != 16:
logger.debug('invalid user id')
return {}
logger.debug('acceptPeering... %s', data)
u = models.User.get_or_create(data['id'])
u.info['message'] = data.get('message', '')
u.update_peering(True)
state.nodes.queue(u.id, 'peering', 'acceptPeering')
return {}
actions.register(acceptPeering, cache=False)
def rejectPeering(data):
'''
takes {
id
message
}
'''
if len(data.get('id', '')) not in (16, 43):
logger.debug('invalid user id')
return {}
u = models.User.get_or_create(data['id'])
u.info['message'] = data.get('message', '')
u.update_peering(False)
state.nodes.queue(u.id, 'peering', 'rejectPeering')
return {}
actions.register(rejectPeering, cache=False)
def removePeering(data):
'''
takes {
id
message
}
'''
if len(data.get('id', '')) not in (16, 43):
logger.debug('invalid user id')
return {}
u = models.User.get_or_create(data['id'])
u.info['message'] = data.get('message', '')
u.update_peering(False)
state.nodes.queue(u.id, 'peering', 'removePeering')
return {}
actions.register(removePeering, cache=False)
def cancelPeering(data):
'''
takes {
}
'''
if len(data.get('id', '')) != 16:
logger.debug('invalid user id')
return {}
u = models.User.get_or_create(data['id'])
u.info['message'] = data.get('message', '')
u.update_peering(False)
state.nodes.queue(u.id, 'peering', 'cancelPeering')
return {}
actions.register(cancelPeering, cache=False)
def getActivity(data):
'''
return {
activity
progress
}
'''
return state.activity
actions.register(getActivity, cache=False)
def contact(data):
'''
return {
}
'''
response = {}
url = 'http://rnogx24drkbnrxa3.onion/contact'
headers = {
'User-Agent': settings.USER_AGENT,
}
try:
data = json.dumps(data).encode()
opener = tor_request.get_opener()
opener.addheaders = list(zip(headers.keys(), headers.values()))
r = opener.open(url, data)
error = r.status != 200
except:
logger.debug('failed to send contact', exc_info=True)
error = True
if error:
response = {'error': True}
return response
actions.register(contact, cache=False)