openmedialibrary/oml/user/api.py

535 lines
14 KiB
Python
Raw Normal View History

2014-05-04 17:26:43 +00:00
# -*- coding: utf-8 -*-
2014-09-02 22:32:44 +00:00
2014-05-04 17:26:43 +00:00
from copy import deepcopy
2014-05-17 00:14:15 +00:00
import json
2014-08-12 08:16:57 +00:00
import os
2014-05-04 17:26:43 +00:00
2014-05-25 18:06:12 +00:00
import ox
2014-05-04 17:26:43 +00:00
2017-06-03 20:50:14 +00:00
from changelog import add_record
2014-08-12 08:16:57 +00:00
from oxtornado import actions
from utils import update_dict, user_sort_key
2014-09-02 22:32:44 +00:00
from . import models
2014-05-04 17:26:43 +00:00
import settings
import state
2016-01-16 13:11:20 +00:00
import tor_request
2014-05-04 17:26:43 +00:00
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-19 20:14:24 +00:00
def init(data):
2014-05-04 17:26:43 +00:00
'''
2014-05-18 23:24:04 +00:00
takes {
}
returns {
config
user
preferences
ui
}
2014-05-04 17:26:43 +00:00
'''
response = {}
2016-01-18 06:34:20 +00:00
if os.path.exists(settings.oml_data_path):
with open(settings.oml_data_path) as fd:
2014-05-04 17:26:43 +00:00
config = json.load(fd)
2019-01-15 08:38:42 +00:00
if not settings.FULLTEXT_SUPPORT:
config['itemKeys'] = [k for k in config['itemKeys'] if k['id'] != 'fulltext']
2014-05-04 17:26:43 +00:00
else:
config = {}
response['config'] = config
response['user'] = deepcopy(config['user'])
2016-01-10 13:53:29 +00:00
response['version'] = settings.MINOR_VERSION
2014-05-04 17:26:43 +00:00
if settings.preferences:
response['user']['preferences'] = settings.preferences
response['user']['id'] = settings.USER_ID
response['user']['online'] = state.online
if settings.ui:
2016-01-13 16:39:25 +00:00
for f in settings.ui['filters']:
if f['id'] == 'classification':
f['id'] = 'categories'
settings.ui._save()
2014-05-04 17:26:43 +00:00
response['user']['ui'] = settings.ui
return response
actions.register(init)
2019-01-17 10:30:22 +00:00
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')
2014-05-19 20:14:24 +00:00
def setPreferences(data):
2014-05-18 23:24:04 +00:00
'''
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']
2016-04-14 10:57:45 +00:00
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
2014-05-04 17:26:43 +00:00
update_dict(settings.preferences, data)
2014-05-25 12:16:04 +00:00
if 'username' in data:
u = state.user()
u.update_name()
u.save()
if change_username:
2017-06-03 20:50:14 +00:00
add_record('editusername', data['username'])
2019-01-19 10:41:05 +00:00
if state.nodes and state.nodes.local:
state.nodes.local._update_if_ip_changed()
if change_contact:
2017-06-03 20:50:14 +00:00
add_record('editcontact', data['contact'])
if change_path:
state.tasks.queue('changelibrarypath', change_path)
2016-04-14 10:57:45 +00:00
if change_autostart:
import integration
if settings.preferences['autostart']:
integration.install_autostart()
else:
integration.uninstall_autostart()
2014-05-04 17:26:43 +00:00
return settings.preferences
actions.register(setPreferences, cache=False)
2014-05-04 17:26:43 +00:00
2016-01-17 10:10:10 +00:00
def resetUI(data):
'''
takes {
}
'''
2016-01-18 06:34:20 +00:00
ui_json = os.path.join(settings.data_path, 'ui.json')
2016-01-17 10:10:10 +00:00
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)
2014-05-19 20:14:24 +00:00
def setUI(data):
2014-05-18 23:24:04 +00:00
'''
takes {
key: value,
'sub.key': value
}
'''
2014-05-04 17:26:43 +00:00
update_dict(settings.ui, data)
2016-02-11 06:17:46 +00:00
#return settings.ui
return {}
actions.register(setUI, cache=False)
2014-05-04 17:26:43 +00:00
2014-05-19 20:14:24 +00:00
def getUsers(data):
2014-05-18 23:24:04 +00:00
'''
returns {
users: []
}
'''
2014-05-04 17:26:43 +00:00
users = []
ids = set()
2016-02-07 08:25:12 +00:00
local = set()
2016-07-04 10:06:50 +00:00
for u in models.User.query.filter(models.User.id != settings.USER_ID).all():
2014-05-04 17:26:43 +00:00
users.append(u.json())
ids.add(u.id)
2016-01-05 17:52:17 +00:00
if state.nodes:
2016-03-14 13:31:56 +00:00
for id in state.nodes.local:
2016-01-05 17:52:17 +00:00
if id not in ids:
2016-03-14 13:31:56 +00:00
n = state.nodes.local[id].copy()
2016-01-05 17:52:17 +00:00
n['online'] = True
n['name'] = n['username']
users.append(n)
2016-02-07 08:25:12 +00:00
local.add(id)
for n in users:
n['local'] = n['id'] in local
users.sort(key=user_sort_key)
2014-05-04 17:26:43 +00:00
return {
"users": users
}
actions.register(getUsers)
2019-01-17 10:30:22 +00:00
def getUsersPublic(data):
return {
'users': []
}
actions.register(getUsersPublic, 'getUsers', version='public')
2014-05-19 20:14:24 +00:00
def getLists(data):
2014-05-18 23:24:04 +00:00
'''
returns {
lists: []
}
'''
from item.models import Item
from user.models import List
2014-05-12 12:57:47 +00:00
lists = []
2014-05-18 23:24:04 +00:00
lists.append({
'id': '',
'items': Item.query.count(),
'name': 'Libraries',
'type': 'libraries',
2014-05-25 12:16:04 +00:00
'user': None,
2014-05-18 23:24:04 +00:00
})
2019-01-28 10:09:00 +00:00
List.get_or_create(':Inbox')
2014-05-04 17:26:43 +00:00
for u in models.User.query.filter((models.User.peered==True)|(models.User.id==settings.USER_ID)):
2014-05-12 12:57:47 +00:00
lists += u.lists_json()
2014-05-04 17:26:43 +00:00
return {
'lists': lists
}
actions.register(getLists)
2019-01-17 10:30:22 +00:00
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')
2014-05-18 23:24:04 +00:00
def validate_query(query):
2014-05-25 20:08:44 +00:00
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)
2016-01-07 06:55:09 +00:00
validate_conditions(c['conditions'])
2014-05-25 20:08:44 +00:00
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)
2014-05-19 20:14:24 +00:00
def addList(data):
2014-05-18 23:24:04 +00:00
'''
takes {
name
items
query
}
'''
logger.debug('addList %s', data)
2014-05-04 17:26:43 +00:00
user_id = settings.USER_ID
2014-05-18 23:24:04 +00:00
if 'query' in data:
validate_query(data['query'])
if data['name']:
2014-05-04 17:26:43 +00:00
l = models.List.create(user_id, data['name'], data.get('query'))
if 'items' in data:
l.add_items(data['items'])
return l.json()
2014-05-18 23:24:04 +00:00
else:
raise Exception('name not set')
2014-05-04 17:26:43 +00:00
return {}
actions.register(addList, cache=False)
2014-05-19 20:14:24 +00:00
def editList(data):
2014-05-18 23:24:04 +00:00
'''
takes {
id
name
query
}
'''
2014-05-17 14:26:59 +00:00
logger.debug('editList %s', data)
2014-05-04 17:26:43 +00:00
l = models.List.get_or_create(data['id'])
name = l.name
if 'name' in data:
l.name = data['name']
2014-05-25 20:08:44 +00:00
if 'query' in data and l.type != 'smart':
raise Exception('query only for smart lists')
if 'query' in data and l.type == 'smart':
2014-05-18 23:24:04 +00:00
validate_query(data['query'])
2014-05-04 17:26:43 +00:00
l._query = data['query']
if l.type == 'static' and name != l.name:
2017-06-03 20:50:14 +00:00
add_record('editlist', name, {'name': l.name})
2014-05-04 17:26:43 +00:00
l.save()
2014-05-17 14:26:59 +00:00
return l.json()
2014-05-04 17:26:43 +00:00
actions.register(editList, cache=False)
2014-05-19 20:14:24 +00:00
def removeList(data):
2014-05-18 23:24:04 +00:00
'''
takes {
id
}
'''
l = models.List.get(data['id'])
2019-01-28 10:09:00 +00:00
if l and l.name != 'Inbox':
2014-05-18 23:24:04 +00:00
l.remove()
return {}
actions.register(removeList, cache=False)
2014-05-19 20:14:24 +00:00
def addListItems(data):
2014-05-18 23:24:04 +00:00
'''
takes {
list
items
}
'''
2014-05-17 23:14:29 +00:00
if data['list'] == ':':
from item.models import Item
for item_id in data['items']:
2019-01-31 09:55:26 +00:00
i = Item.get(item_id, for_update=True)
2014-05-21 00:02:21 +00:00
i.queue_download()
i.update()
2019-01-28 10:09:00 +00:00
elif data['list'] and (data['list'].startswith(':') or data['list'].endswith(':')):
2014-05-17 23:14:29 +00:00
l = models.List.get_or_create(data['list'])
if l:
2019-01-28 10:09:00 +00:00
if l.name in ('Inbox', '') and l.user_id != settings.USER_ID:
state.tasks.queue('upload', {
'user': l.user_id,
'items': data['items']
})
else:
l.add_items(data['items'])
2016-01-17 11:02:17 +00:00
state.cache.clear('group:')
2014-05-17 23:14:29 +00:00
return l.json()
2014-05-04 17:26:43 +00:00
return {}
2014-05-12 12:57:47 +00:00
actions.register(addListItems, cache=False)
2014-05-04 17:26:43 +00:00
2014-05-19 20:14:24 +00:00
def removeListItems(data):
2014-05-18 23:24:04 +00:00
'''
takes {
list
items
}
'''
2014-05-12 12:57:47 +00:00
l = models.List.get(data['list'])
if l:
l.remove_items(data['items'])
2016-01-17 11:02:17 +00:00
state.cache.clear('group:')
2014-05-12 12:57:47 +00:00
return l.json()
2014-05-04 17:26:43 +00:00
return {}
2014-05-12 12:57:47 +00:00
actions.register(removeListItems, cache=False)
2014-05-04 17:26:43 +00:00
2014-05-19 20:14:24 +00:00
def sortLists(data):
2014-05-18 23:24:04 +00:00
'''
takes {
ids
}
'''
2014-05-04 17:26:43 +00:00
n = 0
2014-05-17 14:26:59 +00:00
logger.debug('sortLists %s', data)
2019-01-31 08:10:37 +00:00
lists = []
2014-05-04 17:26:43 +00:00
for id in data['ids']:
l = models.List.get(id)
2014-05-25 18:06:12 +00:00
l.index_ = n
2014-05-04 17:26:43 +00:00
n += 1
2019-01-28 10:09:00 +00:00
if l.type == 'static' and l.name not in ('', 'Inbox'):
2014-05-25 18:06:12 +00:00
lists.append(l.name)
2014-08-09 16:14:14 +00:00
state.db.session.add(l)
state.db.session.commit()
2014-05-25 18:06:12 +00:00
if lists:
2017-06-03 20:50:14 +00:00
add_record('orderlists', lists)
2014-05-04 17:26:43 +00:00
return {}
actions.register(sortLists, cache=False)
2014-05-19 20:14:24 +00:00
def editUser(data):
2014-05-18 23:24:04 +00:00
'''
takes {
id
nickname
}
'''
2014-05-04 17:26:43 +00:00
if 'nickname' in data:
p = models.User.get_or_create(data['id'])
2014-05-25 12:16:04 +00:00
if data['nickname']:
p.info['nickname'] = data['nickname']
elif 'nickname' in p.info:
del p.info['nickname']
2014-05-25 18:06:12 +00:00
old = p.nickname
2014-05-25 12:16:04 +00:00
p.update_name()
2014-05-25 18:06:12 +00:00
if old != p.nickname:
models.List.rename_user(old, p.nickname)
2014-05-04 17:26:43 +00:00
p.save()
2014-05-25 12:44:07 +00:00
return p.json()
2014-05-04 17:26:43 +00:00
return {}
actions.register(editUser, cache=False)
2014-05-25 18:06:12 +00:00
def sortUsers(data):
'''
takes {
ids
}
'''
n = 0
for id in data['ids']:
u = models.User.get(id)
u.info['index'] = n
n += 1
2014-08-09 16:14:14 +00:00
state.db.session.add(u)
state.db.session.commit()
2016-01-19 10:05:16 +00:00
if state.tasks:
state.tasks.queue('syncmetadata')
2014-05-25 18:06:12 +00:00
return {}
actions.register(sortUsers, cache=False)
2014-05-19 20:14:24 +00:00
2014-05-20 00:33:06 +00:00
def requestPeering(data):
2014-05-18 23:24:04 +00:00
'''
takes {
id
message
nickname (optional)
2014-05-18 23:24:04 +00:00
}
'''
2024-06-08 11:39:27 +00:00
if len(data.get('id', '')) != settings.ID_LENGTH:
2014-05-17 14:26:59 +00:00
logger.debug('invalid user id')
2014-05-17 00:14:15 +00:00
return {}
2014-05-18 03:01:24 +00:00
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()
2014-05-18 03:01:24 +00:00
u.save()
2019-02-02 07:13:37 +00:00
state.nodes.peer_queue(u.id, 'peering', 'requestPeering')
2014-05-04 17:26:43 +00:00
return {}
2014-05-20 00:33:06 +00:00
actions.register(requestPeering, cache=False)
2014-05-19 20:14:24 +00:00
2014-05-04 17:26:43 +00:00
2014-05-19 20:14:24 +00:00
def acceptPeering(data):
2014-05-18 23:24:04 +00:00
'''
takes {
id
message
}
'''
2024-06-08 11:39:27 +00:00
if len(data.get('id', '')) != settings.ID_LENGTH:
2014-05-17 14:26:59 +00:00
logger.debug('invalid user id')
2014-05-17 00:14:15 +00:00
return {}
2014-05-17 14:26:59 +00:00
logger.debug('acceptPeering... %s', data)
2014-05-18 03:01:24 +00:00
u = models.User.get_or_create(data['id'])
u.info['message'] = data.get('message', '')
u.update_peering(True)
2019-02-02 07:13:37 +00:00
state.nodes.peer_queue(u.id, 'peering', 'acceptPeering')
2014-05-04 17:26:43 +00:00
return {}
actions.register(acceptPeering, cache=False)
2014-05-19 20:14:24 +00:00
def rejectPeering(data):
2014-05-18 23:24:04 +00:00
'''
takes {
id
message
}
'''
2024-06-08 11:39:27 +00:00
if len(data.get('id', '')) not in (16, 43, 56):
logger.debug('invalid user id: %s', data)
2014-05-17 00:14:15 +00:00
return {}
2014-05-18 03:01:24 +00:00
u = models.User.get_or_create(data['id'])
u.info['message'] = data.get('message', '')
u.update_peering(False)
2019-02-02 07:13:37 +00:00
state.nodes.peer_queue(u.id, 'peering', 'rejectPeering')
2014-05-04 17:26:43 +00:00
return {}
actions.register(rejectPeering, cache=False)
2014-05-19 20:14:24 +00:00
def removePeering(data):
2014-05-18 23:24:04 +00:00
'''
takes {
id
message
}
'''
2024-06-08 11:39:27 +00:00
if len(data.get('id', '')) not in (16, 43, 56):
logger.debug('invalid user id: %s', data)
2014-05-17 00:14:15 +00:00
return {}
u = models.User.get(data['id'], for_update=True)
2019-02-02 08:59:12 +00:00
if u:
u.info['message'] = data.get('message', '')
u.update_peering(False)
state.nodes.peer_queue(u.id, 'peering', 'removePeering')
2014-05-04 17:26:43 +00:00
return {}
actions.register(removePeering, cache=False)
2014-05-12 23:43:27 +00:00
2014-05-19 20:14:24 +00:00
def cancelPeering(data):
2014-05-18 23:24:04 +00:00
'''
takes {
}
'''
2024-06-08 11:39:27 +00:00
if len(data.get('id', '')) != settings.ID_LENGTH:
logger.debug('invalid user id: %s', data)
2014-05-17 00:14:15 +00:00
return {}
2014-05-18 03:01:24 +00:00
u = models.User.get_or_create(data['id'])
u.info['message'] = data.get('message', '')
u.update_peering(False)
2019-02-02 07:13:37 +00:00
state.nodes.peer_queue(u.id, 'peering', 'cancelPeering')
2014-05-12 23:43:27 +00:00
return {}
actions.register(cancelPeering, cache=False)
2014-05-17 00:14:15 +00:00
2014-05-19 20:14:24 +00:00
def getActivity(data):
2014-05-18 23:24:04 +00:00
'''
return {
activity
progress
}
'''
2014-05-17 00:14:15 +00:00
return state.activity
actions.register(getActivity, cache=False)
2016-01-16 13:11:20 +00:00
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)