Compare commits
No commits in common. "dd0e22a97985090e62d8537c938cdb888cc4be90" and "1c8a5c3764d9637b877f498ac248dacc4bf59b44" have entirely different histories.
dd0e22a979
...
1c8a5c3764
23 changed files with 110 additions and 255 deletions
|
|
@ -318,7 +318,6 @@
|
||||||
"receivedRequests": "notify",
|
"receivedRequests": "notify",
|
||||||
"rejectMessage": "",
|
"rejectMessage": "",
|
||||||
"sendDiagnostics": false,
|
"sendDiagnostics": false,
|
||||||
"enableReadOnlyService": false,
|
|
||||||
"sendRequests": "manually",
|
"sendRequests": "manually",
|
||||||
"uploadRate": null,
|
"uploadRate": null,
|
||||||
"username": ""
|
"username": ""
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from sqlalchemy.sql import operators
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,6 @@ def find(data):
|
||||||
response['size'] = sum(size)
|
response['size'] = sum(size)
|
||||||
return response
|
return response
|
||||||
actions.register(find)
|
actions.register(find)
|
||||||
actions.register(find, version='public')
|
|
||||||
|
|
||||||
|
|
||||||
def get(data):
|
def get(data):
|
||||||
|
|
@ -129,7 +128,6 @@ def get(data):
|
||||||
response = item.json(data['keys'] if 'keys' in data else None)
|
response = item.json(data['keys'] if 'keys' in data else None)
|
||||||
return response
|
return response
|
||||||
actions.register(get)
|
actions.register(get)
|
||||||
actions.register(get, version='public')
|
|
||||||
|
|
||||||
|
|
||||||
def edit(data):
|
def edit(data):
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ logger = logging.getLogger(__name__)
|
||||||
def parse(data):
|
def parse(data):
|
||||||
query = {}
|
query = {}
|
||||||
query['range'] = [0, 100]
|
query['range'] = [0, 100]
|
||||||
if 'group' not in data:
|
if not 'group' in data:
|
||||||
query['sort'] = [{'key': 'title', 'operator': '+'}]
|
query['sort'] = [{'key':'title', 'operator':'+'}]
|
||||||
for key in ('keys', 'group', 'list', 'range', 'sort', 'query'):
|
for key in ('keys', 'group', 'list', 'range', 'sort', 'query'):
|
||||||
if key in data:
|
if key in data:
|
||||||
query[key] = data[key]
|
query[key] = data[key]
|
||||||
|
|
@ -26,7 +26,7 @@ def parse(data):
|
||||||
query['range'] = [0, 0]
|
query['range'] = [0, 0]
|
||||||
#print data
|
#print data
|
||||||
query['qs'] = models.Item.find(data)
|
query['qs'] = models.Item.find(data)
|
||||||
if 'group' not in query:
|
if not 'group' in query:
|
||||||
query['qs'] = order(query['qs'], query['sort'])
|
query['qs'] = order(query['qs'], query['sort'])
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ def find(title=None, author=None):
|
||||||
isbns.add(info['isbn'])
|
isbns.add(info['isbn'])
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def info_old(isbn):
|
def info(isbn):
|
||||||
url = 'http://books.google.com/books/feeds/volumes?' + urlencode({
|
url = 'http://books.google.com/books/feeds/volumes?' + urlencode({
|
||||||
'q': 'isnb:' + isbn,
|
'q': 'isnb:' + isbn,
|
||||||
'max-results':1,
|
'max-results':1,
|
||||||
|
|
@ -139,7 +139,7 @@ def info_old(isbn):
|
||||||
return info
|
return info
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def info(value):
|
def info_newapi(value):
|
||||||
key = 'isbn'
|
key = 'isbn'
|
||||||
url = 'https://www.googleapis.com/books/v1/volumes?q=%s:%s' % (key, value)
|
url = 'https://www.googleapis.com/books/v1/volumes?q=%s:%s' % (key, value)
|
||||||
api_key = settings.server.get('google_api_key')
|
api_key = settings.server.get('google_api_key')
|
||||||
|
|
|
||||||
102
oml/oxtornado.py
102
oml/oxtornado.py
|
|
@ -71,9 +71,8 @@ def defaultcontext():
|
||||||
class ApiHandler(tornado.web.RequestHandler):
|
class ApiHandler(tornado.web.RequestHandler):
|
||||||
executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
|
executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
|
||||||
|
|
||||||
def initialize(self, context=None, public=False):
|
def initialize(self, context=None):
|
||||||
self._context = context
|
self._context = context
|
||||||
self._public = public
|
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
self.write('use POST')
|
self.write('use POST')
|
||||||
|
|
@ -82,7 +81,7 @@ class ApiHandler(tornado.web.RequestHandler):
|
||||||
def api_task(self, request):
|
def api_task(self, request):
|
||||||
import settings
|
import settings
|
||||||
context = self._context
|
context = self._context
|
||||||
if context is None:
|
if context == None:
|
||||||
context = defaultcontext
|
context = defaultcontext
|
||||||
action = request.arguments.get('action', [None])[0].decode('utf-8')
|
action = request.arguments.get('action', [None])[0].decode('utf-8')
|
||||||
data = request.arguments.get('data', [b'{}'])[0]
|
data = request.arguments.get('data', [b'{}'])[0]
|
||||||
|
|
@ -97,10 +96,7 @@ class ApiHandler(tornado.web.RequestHandler):
|
||||||
else:
|
else:
|
||||||
if settings.DEBUG_API:
|
if settings.DEBUG_API:
|
||||||
logger.debug('API %s %s', action, data)
|
logger.debug('API %s %s', action, data)
|
||||||
if self._public:
|
f = actions.get(action)
|
||||||
f = actions.versions['public'].get(action)
|
|
||||||
else:
|
|
||||||
f = actions.get(action)
|
|
||||||
if f:
|
if f:
|
||||||
with context():
|
with context():
|
||||||
try:
|
try:
|
||||||
|
|
@ -130,60 +126,50 @@ class ApiHandler(tornado.web.RequestHandler):
|
||||||
class ApiActions(dict):
|
class ApiActions(dict):
|
||||||
properties = {}
|
properties = {}
|
||||||
versions = {}
|
versions = {}
|
||||||
|
|
||||||
def _api(self, data, version=None):
|
|
||||||
'''
|
|
||||||
returns list of all known api actions
|
|
||||||
takes {
|
|
||||||
docs: bool
|
|
||||||
}
|
|
||||||
if docs is true, action properties contain docstrings
|
|
||||||
returns {
|
|
||||||
actions: {
|
|
||||||
'api': {
|
|
||||||
cache: true,
|
|
||||||
doc: 'recursion'
|
|
||||||
},
|
|
||||||
'hello': {
|
|
||||||
cache: true,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
data = data or {}
|
|
||||||
docs = data.get('docs', False)
|
|
||||||
code = data.get('code', False)
|
|
||||||
if version:
|
|
||||||
_actions = list(self.versions[version].keys())
|
|
||||||
else:
|
|
||||||
_actions = list(self.keys())
|
|
||||||
_actions.sort()
|
|
||||||
actions = {}
|
|
||||||
for a in _actions:
|
|
||||||
actions[a] = self.properties[a]
|
|
||||||
if docs:
|
|
||||||
actions[a]['doc'] = self.doc(a, version)
|
|
||||||
if code:
|
|
||||||
actions[a]['code'] = self.code(a, version)
|
|
||||||
return {'actions': actions}
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.register(self._api, 'api')
|
|
||||||
|
|
||||||
def doc(self, name, version=None):
|
def api(data):
|
||||||
if version:
|
'''
|
||||||
f = self.versions[version][name]
|
returns list of all known api actions
|
||||||
else:
|
takes {
|
||||||
f = self[name]
|
docs: bool
|
||||||
|
}
|
||||||
|
if docs is true, action properties contain docstrings
|
||||||
|
returns {
|
||||||
|
actions: {
|
||||||
|
'api': {
|
||||||
|
cache: true,
|
||||||
|
doc: 'recursion'
|
||||||
|
},
|
||||||
|
'hello': {
|
||||||
|
cache: true,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
data = data or {}
|
||||||
|
docs = data.get('docs', False)
|
||||||
|
code = data.get('code', False)
|
||||||
|
_actions = list(self.keys())
|
||||||
|
_actions.sort()
|
||||||
|
actions = {}
|
||||||
|
for a in _actions:
|
||||||
|
actions[a] = self.properties[a]
|
||||||
|
if docs:
|
||||||
|
actions[a]['doc'] = self.doc(a)
|
||||||
|
if code:
|
||||||
|
actions[a]['code'] = self.code(a)
|
||||||
|
return {'actions': actions}
|
||||||
|
self.register(api)
|
||||||
|
|
||||||
|
def doc(self, name):
|
||||||
|
f = self[name]
|
||||||
return trim(f.__doc__)
|
return trim(f.__doc__)
|
||||||
|
|
||||||
def code(self, name, version=None):
|
def code(self, name, version=None):
|
||||||
if version:
|
f = self[name]
|
||||||
f = self.versions[version][name]
|
|
||||||
else:
|
|
||||||
f = self[name]
|
|
||||||
if name != 'api' and hasattr(f, 'func_closure') and f.__closure__:
|
if name != 'api' and hasattr(f, 'func_closure') and f.__closure__:
|
||||||
fc = [c for c in f.__closure__ if hasattr(c.cell_contents, '__call__')]
|
fc = [c for c in f.__closure__ if hasattr(c.cell_contents, '__call__')]
|
||||||
f = fc[len(fc)-1].cell_contents
|
f = fc[len(fc)-1].cell_contents
|
||||||
|
|
@ -195,9 +181,8 @@ class ApiActions(dict):
|
||||||
if not action:
|
if not action:
|
||||||
action = method.__name__
|
action = method.__name__
|
||||||
if version:
|
if version:
|
||||||
if version not in self.versions:
|
if not version in self.versions:
|
||||||
self.versions[version] = {}
|
self.versions[version] = {}
|
||||||
self.register(lambda data: self._api(data, version), action='api', version=version)
|
|
||||||
self.versions[version][action] = method
|
self.versions[version][action] = method
|
||||||
else:
|
else:
|
||||||
self[action] = method
|
self[action] = method
|
||||||
|
|
@ -207,5 +192,4 @@ class ApiActions(dict):
|
||||||
if action in self:
|
if action in self:
|
||||||
del self[action]
|
del self[action]
|
||||||
|
|
||||||
|
|
||||||
actions = ApiActions()
|
actions = ApiActions()
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ def run():
|
||||||
else:
|
else:
|
||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
log_format = '%(asctime)s:%(levelname)s:%(name)s:%(message)s'
|
log_format='%(asctime)s:%(levelname)s:%(name)s:%(message)s'
|
||||||
if debug:
|
if debug:
|
||||||
logging.basicConfig(level=logging.DEBUG, format=log_format)
|
logging.basicConfig(level=logging.DEBUG, format=log_format)
|
||||||
else:
|
else:
|
||||||
|
|
@ -109,7 +109,7 @@ def run():
|
||||||
'gzip': True
|
'gzip': True
|
||||||
}
|
}
|
||||||
|
|
||||||
common_handlers = [
|
handlers = [
|
||||||
(r'/(favicon.ico)', StaticFileHandler, {'path': settings.static_path}),
|
(r'/(favicon.ico)', StaticFileHandler, {'path': settings.static_path}),
|
||||||
(r'/static/oxjs/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'oxjs')}),
|
(r'/static/oxjs/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'oxjs')}),
|
||||||
(r'/static/cbr.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'reader', 'cbr.js')}),
|
(r'/static/cbr.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'reader', 'cbr.js')}),
|
||||||
|
|
@ -126,33 +126,17 @@ def run():
|
||||||
'attachment': True
|
'attachment': True
|
||||||
}),
|
}),
|
||||||
(r'/(.*)/(cover|preview)(\d*).jpg', IconHandler),
|
(r'/(.*)/(cover|preview)(\d*).jpg', IconHandler),
|
||||||
]
|
|
||||||
handlers = common_handlers + [
|
|
||||||
(r'/api/upload/', UploadHandler, dict(context=db.session)),
|
(r'/api/upload/', UploadHandler, dict(context=db.session)),
|
||||||
(r'/api/', oxtornado.ApiHandler, dict(context=db.session)),
|
(r'/api/', oxtornado.ApiHandler, dict(context=db.session)),
|
||||||
(r'/ws', websocket.Handler),
|
(r'/ws', websocket.Handler),
|
||||||
(r"(.*)", MainHandler),
|
(r"(.*)", MainHandler),
|
||||||
]
|
]
|
||||||
public_handlers = common_handlers + [
|
|
||||||
(r'/api/', oxtornado.ApiHandler, dict(context=db.session, public=True)),
|
|
||||||
(r'/ws', websocket.Handler, dict(public=True)),
|
|
||||||
(r"(.*)", MainHandler),
|
|
||||||
]
|
|
||||||
|
|
||||||
setup.create_db()
|
setup.create_db()
|
||||||
http_server = Application(handlers, **options)
|
http_server = Application(handlers, **options)
|
||||||
max_buffer_size = 2*1024*1024*1024
|
max_buffer_size = 2*1024*1024*1024
|
||||||
http_server.listen(settings.server['port'], settings.server['address'], max_buffer_size=max_buffer_size)
|
http_server.listen(settings.server['port'], settings.server['address'], max_buffer_size=max_buffer_size)
|
||||||
|
|
||||||
# public server
|
|
||||||
'''
|
|
||||||
public_port = settings.server.get('public_port')
|
|
||||||
public_address = settings.server['public_address']
|
|
||||||
if public_port:
|
|
||||||
public_server = Application(public_handlers, **options)
|
|
||||||
public_server.listen(public_port, public_address)
|
|
||||||
'''
|
|
||||||
|
|
||||||
if PID:
|
if PID:
|
||||||
with open(PID, 'w') as pid:
|
with open(PID, 'w') as pid:
|
||||||
pid.write('%s' % os.getpid())
|
pid.write('%s' % os.getpid())
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,6 @@ server_defaults = {
|
||||||
'port': 9842,
|
'port': 9842,
|
||||||
'address': '127.0.0.1',
|
'address': '127.0.0.1',
|
||||||
'node_port': 9851,
|
'node_port': 9851,
|
||||||
'public_address': '127.0.0.1',
|
|
||||||
'public_port': 9852,
|
|
||||||
'node_address': '',
|
'node_address': '',
|
||||||
'extract_text': True,
|
'extract_text': True,
|
||||||
'localnode_discovery': True,
|
'localnode_discovery': True,
|
||||||
|
|
|
||||||
|
|
@ -200,8 +200,6 @@ class Tor(object):
|
||||||
key_content = RSA.importKey(private_key).exportKey().decode()
|
key_content = RSA.importKey(private_key).exportKey().decode()
|
||||||
key_content = ''.join(key_content.strip().split('\n')[1:-1])
|
key_content = ''.join(key_content.strip().split('\n')[1:-1])
|
||||||
ports = {9851: settings.server['node_port']}
|
ports = {9851: settings.server['node_port']}
|
||||||
if settings.preferences.get('enableReadOnlyService'):
|
|
||||||
ports[80] = settings.server['public_port']
|
|
||||||
controller.remove_ephemeral_hidden_service(settings.USER_ID)
|
controller.remove_ephemeral_hidden_service(settings.USER_ID)
|
||||||
response = controller.create_ephemeral_hidden_service(ports,
|
response = controller.create_ephemeral_hidden_service(ports,
|
||||||
key_type='RSA1024', key_content=key_content,
|
key_type='RSA1024', key_content=key_content,
|
||||||
|
|
@ -209,8 +207,6 @@ class Tor(object):
|
||||||
if response.is_ok():
|
if response.is_ok():
|
||||||
logger.debug('published node as https://%s.onion:%s',
|
logger.debug('published node as https://%s.onion:%s',
|
||||||
settings.USER_ID, settings.server_defaults['node_port'])
|
settings.USER_ID, settings.server_defaults['node_port'])
|
||||||
if settings.preferences.get('enableReadOnlyService'):
|
|
||||||
logger.debug('published readonly version as hidden servers: http://%s.onion', settings.USER_ID)
|
|
||||||
else:
|
else:
|
||||||
logger.debug('failed to publish node to tor')
|
logger.debug('failed to publish node to tor')
|
||||||
else:
|
else:
|
||||||
|
|
@ -221,9 +217,6 @@ class Tor(object):
|
||||||
target_port=settings.server['node_port']
|
target_port=settings.server['node_port']
|
||||||
)
|
)
|
||||||
logger.debug('published node as https://%s:%s', result.hostname, settings.server_defaults['node_port'])
|
logger.debug('published node as https://%s:%s', result.hostname, settings.server_defaults['node_port'])
|
||||||
if settings.preferences.get('enableReadOnlyService'):
|
|
||||||
logger.error('can not publish read-only version, please update TOR')
|
|
||||||
|
|
||||||
|
|
||||||
def depublish(self):
|
def depublish(self):
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ def verify(release):
|
||||||
value = '\n'.join(value)
|
value = '\n'.join(value)
|
||||||
value = value.encode()
|
value = value.encode()
|
||||||
for digest in ('sha512', 'sha256', 'sha1'):
|
for digest in ('sha512', 'sha256', 'sha1'):
|
||||||
if 'signature_%s' % digest in release:
|
if 'signature_%s'%digest in release:
|
||||||
tls_sig = base64.b64decode(release['signature_%s' % digest].encode())
|
tls_sig = base64.b64decode(release['signature_%s'%digest].encode())
|
||||||
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, settings.OML_UPDATE_CERT)
|
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, settings.OML_UPDATE_CERT)
|
||||||
try:
|
try:
|
||||||
OpenSSL.crypto.verify(cert, tls_sig, value, digest)
|
OpenSSL.crypto.verify(cert, tls_sig, value, digest)
|
||||||
|
|
@ -301,7 +301,6 @@ def getVersion(data):
|
||||||
response['update'] = current < new
|
response['update'] = current < new
|
||||||
return response
|
return response
|
||||||
actions.register(getVersion, cache=False)
|
actions.register(getVersion, cache=False)
|
||||||
actions.register(getVersion, cache=False, version='public')
|
|
||||||
|
|
||||||
def restart(data):
|
def restart(data):
|
||||||
'''
|
'''
|
||||||
|
|
|
||||||
|
|
@ -55,21 +55,6 @@ def init(data):
|
||||||
return response
|
return response
|
||||||
actions.register(init)
|
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):
|
def setPreferences(data):
|
||||||
'''
|
'''
|
||||||
|
|
@ -164,12 +149,6 @@ def getUsers(data):
|
||||||
}
|
}
|
||||||
actions.register(getUsers)
|
actions.register(getUsers)
|
||||||
|
|
||||||
def getUsersPublic(data):
|
|
||||||
return {
|
|
||||||
'users': []
|
|
||||||
}
|
|
||||||
actions.register(getUsersPublic, 'getUsers', version='public')
|
|
||||||
|
|
||||||
|
|
||||||
def getLists(data):
|
def getLists(data):
|
||||||
'''
|
'''
|
||||||
|
|
@ -193,29 +172,6 @@ def getLists(data):
|
||||||
}
|
}
|
||||||
actions.register(getLists)
|
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):
|
def validate_query(query):
|
||||||
validate_conditions(query['conditions'])
|
validate_conditions(query['conditions'])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,7 @@ class List(db.Model):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def rename_user(cls, old, new):
|
def rename_user(cls, old, new):
|
||||||
for l in cls.query.filter(cls._query != None):
|
for l in cls.query.filter(cls._query is not None):
|
||||||
|
|
||||||
def update_conditions(conditions):
|
def update_conditions(conditions):
|
||||||
changed = False
|
changed = False
|
||||||
|
|
@ -320,7 +320,7 @@ class List(db.Model):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
if l._query and update_conditions(l._query.get('conditions', [])):
|
if update_conditions(l._query.get('conditions', [])):
|
||||||
l.save()
|
l.save()
|
||||||
|
|
||||||
def add_items(self, items, commit=True):
|
def add_items(self, items, commit=True):
|
||||||
|
|
|
||||||
13
oml/utils.py
13
oml/utils.py
|
|
@ -142,14 +142,13 @@ def get_user_id(private_key, cert_path):
|
||||||
fd.write(dump_privatekey(FILETYPE_PEM, key))
|
fd.write(dump_privatekey(FILETYPE_PEM, key))
|
||||||
os.chmod(private_key, 0o400)
|
os.chmod(private_key, 0o400)
|
||||||
user_id = get_service_id(private_key)
|
user_id = get_service_id(private_key)
|
||||||
if not os.path.exists(cert_path) or \
|
if not os.path.exists(cert_path):
|
||||||
(datetime.now() - datetime.fromtimestamp(os.path.getmtime(cert_path))).days > 60:
|
|
||||||
ca = X509()
|
ca = X509()
|
||||||
ca.set_version(2)
|
ca.set_version(2)
|
||||||
ca.set_serial_number(1)
|
ca.set_serial_number(1)
|
||||||
ca.get_subject().CN = user_id
|
ca.get_subject().CN = user_id
|
||||||
ca.gmtime_adj_notBefore(0)
|
ca.gmtime_adj_notBefore(0)
|
||||||
ca.gmtime_adj_notAfter(90 * 24 * 60 * 60)
|
ca.gmtime_adj_notAfter(24 * 60 * 60)
|
||||||
ca.set_issuer(ca.get_subject())
|
ca.set_issuer(ca.get_subject())
|
||||||
ca.set_pubkey(key)
|
ca.set_pubkey(key)
|
||||||
ca.add_extensions([
|
ca.add_extensions([
|
||||||
|
|
@ -199,7 +198,7 @@ def update_dict(root, data):
|
||||||
keys = [part.replace('\0', '.') for part in key.replace('\\.', '\0').split('.')]
|
keys = [part.replace('\0', '.') for part in key.replace('\\.', '\0').split('.')]
|
||||||
value = data[key]
|
value = data[key]
|
||||||
p = root
|
p = root
|
||||||
while len(keys) > 1:
|
while len(keys)>1:
|
||||||
key = keys.pop(0)
|
key = keys.pop(0)
|
||||||
if isinstance(p, list):
|
if isinstance(p, list):
|
||||||
p = p[get_position_by_id(p, key)]
|
p = p[get_position_by_id(p, key)]
|
||||||
|
|
@ -207,7 +206,7 @@ def update_dict(root, data):
|
||||||
if key not in p:
|
if key not in p:
|
||||||
p[key] = {}
|
p[key] = {}
|
||||||
p = p[key]
|
p = p[key]
|
||||||
if value is None and keys[0] in p:
|
if value == None and keys[0] in p:
|
||||||
del p[keys[0]]
|
del p[keys[0]]
|
||||||
else:
|
else:
|
||||||
p[keys[0]] = value
|
p[keys[0]] = value
|
||||||
|
|
@ -445,11 +444,11 @@ def send_debug():
|
||||||
opener.addheaders = list(zip(headers.keys(), headers.values()))
|
opener.addheaders = list(zip(headers.keys(), headers.values()))
|
||||||
r = opener.open(url, result)
|
r = opener.open(url, result)
|
||||||
if r.status != 200:
|
if r.status != 200:
|
||||||
logger.debug('failed to send debug information (server error)')
|
logger.debug('failed to send debug information')
|
||||||
else:
|
else:
|
||||||
settings.server['last_debug'] = timestamp
|
settings.server['last_debug'] = timestamp
|
||||||
except:
|
except:
|
||||||
logger.error('failed to send debug information (connection error)', exc_info=True)
|
logger.debug('failed to send debug information')
|
||||||
|
|
||||||
def iexists(path):
|
def iexists(path):
|
||||||
parts = path.split(os.sep)
|
parts = path.split(os.sep)
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Handler(WebSocketHandler):
|
class Handler(WebSocketHandler):
|
||||||
|
|
||||||
def initialize(self, public=False):
|
|
||||||
self._public = public
|
|
||||||
|
|
||||||
def check_origin(self, origin):
|
def check_origin(self, origin):
|
||||||
# allow access to websocket from site, installer and loader (local file)
|
# allow access to websocket from site, installer and loader (local file)
|
||||||
return self.request.host in origin or \
|
return self.request.host in origin or \
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="development">
|
<div id="development">
|
||||||
<p>
|
<p>
|
||||||
The latest code is in our <a href="https://code.0x2620.org/0x2620/openmedialibrary">git repository</a>.
|
The latest code is in our <a href="https://git.0x2620.org/openmedialibrary.git">git repository</a>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
For everything else, there's IRC, and our development mailing list. Your feedback is welcome.
|
For everything else, there's IRC, and our development mailing list. Your feedback is welcome.
|
||||||
|
|
|
||||||
|
|
@ -15,21 +15,14 @@ oml.UI = (function() {
|
||||||
|
|
||||||
that.reset = function() {
|
that.reset = function() {
|
||||||
var ui = oml.user.ui;
|
var ui = oml.user.ui;
|
||||||
|
oml.api.resetUI({}, function() {
|
||||||
function reload() {
|
|
||||||
ui = oml.config.user.ui;
|
ui = oml.config.user.ui;
|
||||||
ui._list = oml.getListState(ui.find);
|
ui._list = oml.getListState(ui.find);
|
||||||
ui._filterState = oml.getFilterState(ui.find);
|
ui._filterState = oml.getFilterState(ui.find);
|
||||||
ui._findState = oml.getFindState(ui.find);
|
ui._findState = oml.getFindState(ui.find);
|
||||||
Ox.Theme(ui.theme);
|
Ox.Theme(ui.theme);
|
||||||
oml.$ui.appPanel.reload();
|
oml.$ui.appPanel.reload();
|
||||||
}
|
});
|
||||||
if (oml.readOnly) {
|
|
||||||
oml.localStorage('ui', oml.config.user.ui);
|
|
||||||
reload();
|
|
||||||
} else {
|
|
||||||
oml.api.resetUI({}, reload);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// sets oml.user.ui.key to value
|
// sets oml.user.ui.key to value
|
||||||
|
|
@ -168,11 +161,7 @@ oml.UI = (function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (Ox.len(set)) {
|
if (Ox.len(set)) {
|
||||||
if (oml.readOnly) {
|
oml.api.setUI(set);
|
||||||
oml.localStorage('ui', oml.user.ui);
|
|
||||||
} else {
|
|
||||||
oml.api.setUI(set);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (triggerEvents) {
|
if (triggerEvents) {
|
||||||
Ox.forEach(trigger, function(value, key) {
|
Ox.forEach(trigger, function(value, key) {
|
||||||
|
|
@ -193,4 +182,4 @@ oml.UI = (function() {
|
||||||
|
|
||||||
return that;
|
return that;
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
@ -25,13 +25,12 @@ oml.ui.appDialog = function() {
|
||||||
title: Ox._('Software Development'),
|
title: Ox._('Software Development'),
|
||||||
selected: ui.page == 'development'
|
selected: ui.page == 'development'
|
||||||
},
|
},
|
||||||
].concat(oml.readOnly ? [] : [
|
|
||||||
{
|
{
|
||||||
id: 'contact',
|
id: 'contact',
|
||||||
title: Ox._('Send Feedback'),
|
title: Ox._('Send Feedback'),
|
||||||
selected: ui.page == 'contact'
|
selected: ui.page == 'contact'
|
||||||
}
|
}
|
||||||
]),
|
],
|
||||||
|
|
||||||
$panel = Ox.TabPanel({
|
$panel = Ox.TabPanel({
|
||||||
content: function(id) {
|
content: function(id) {
|
||||||
|
|
@ -96,7 +95,7 @@ oml.ui.appDialog = function() {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
that = Ox.Dialog({
|
that = Ox.Dialog({
|
||||||
buttons: (oml.readOnly ? [] : [
|
buttons: [
|
||||||
Ox.Button({
|
Ox.Button({
|
||||||
id: 'update',
|
id: 'update',
|
||||||
style: 'squared',
|
style: 'squared',
|
||||||
|
|
@ -107,7 +106,6 @@ oml.ui.appDialog = function() {
|
||||||
oml.UI.set({page: 'update'});
|
oml.UI.set({page: 'update'});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
]).concat([
|
|
||||||
{},
|
{},
|
||||||
Ox.Button({
|
Ox.Button({
|
||||||
id: 'close',
|
id: 'close',
|
||||||
|
|
@ -118,7 +116,7 @@ oml.ui.appDialog = function() {
|
||||||
that.close();
|
that.close();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
]),
|
],
|
||||||
closeButton: true,
|
closeButton: true,
|
||||||
content: $panel,
|
content: $panel,
|
||||||
fixedSize: true,
|
fixedSize: true,
|
||||||
|
|
|
||||||
|
|
@ -270,10 +270,9 @@ oml.ui.infoView = function(externalData, isMixed) {
|
||||||
items: [
|
items: [
|
||||||
{id: 'read', title: Ox._('Read in Open Media Libary')},
|
{id: 'read', title: Ox._('Read in Open Media Libary')},
|
||||||
{id: 'open', title: Ox._('Open in External Reader')},
|
{id: 'open', title: Ox._('Open in External Reader')},
|
||||||
].concat(oml.readOnly ? [] : [
|
|
||||||
{},
|
{},
|
||||||
{id: 'show', title: Ox._('Show File')}
|
{id: 'show', title: Ox._('Show File')}
|
||||||
]),
|
],
|
||||||
overlap: 'left',
|
overlap: 'left',
|
||||||
style: 'squared',
|
style: 'squared',
|
||||||
title: 'select',
|
title: 'select',
|
||||||
|
|
@ -285,11 +284,7 @@ oml.ui.infoView = function(externalData, isMixed) {
|
||||||
if (data_.id == 'read') {
|
if (data_.id == 'read') {
|
||||||
oml.UI.set({itemView: 'book'});
|
oml.UI.set({itemView: 'book'});
|
||||||
} else if (data_.id == 'open') {
|
} else if (data_.id == 'open') {
|
||||||
if (oml.readOnly) {
|
oml.api.openFile({id: oml.user.ui.item});
|
||||||
document.location.href = '/' + oml.user.ui.item + '/get/'
|
|
||||||
} else {
|
|
||||||
oml.api.openFile({id: oml.user.ui.item});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
oml.api.openFolder({id: oml.user.ui.item});
|
oml.api.openFolder({id: oml.user.ui.item});
|
||||||
}
|
}
|
||||||
|
|
@ -387,9 +382,9 @@ oml.ui.infoView = function(externalData, isMixed) {
|
||||||
Ox.print('BOOK DATA', data)
|
Ox.print('BOOK DATA', data)
|
||||||
|
|
||||||
var $div,
|
var $div,
|
||||||
isEditable = !oml.readOnly && (isMultiple || (
|
isEditable = isMultiple || (
|
||||||
data.mediastate == 'available' && !externalData
|
data.mediastate == 'available' && !externalData
|
||||||
)),
|
),
|
||||||
src = !externalData
|
src = !externalData
|
||||||
? '/' + data.id + '/' + ui.icons + '512.jpg?' + data.modified
|
? '/' + data.id + '/' + ui.icons + '512.jpg?' + data.modified
|
||||||
: data.cover,
|
: data.cover,
|
||||||
|
|
@ -756,29 +751,28 @@ oml.ui.infoView = function(externalData, isMixed) {
|
||||||
].join(', ')
|
].join(', ')
|
||||||
)
|
)
|
||||||
.appendTo($data);
|
.appendTo($data);
|
||||||
if (!oml.readOnly) {
|
|
||||||
renderIdentifyButton(data).appendTo($data);
|
|
||||||
|
|
||||||
['accessed', 'modified', 'added', 'created'].forEach(function(id) {
|
renderIdentifyButton(data).appendTo($data);
|
||||||
var title;
|
|
||||||
if (data[id]) {
|
|
||||||
title = Ox.getObjectById(oml.config.itemKeys, id).title;
|
|
||||||
$('<div>')
|
|
||||||
.css({
|
|
||||||
marginTop: '8px',
|
|
||||||
fontWeight: 'bold'
|
|
||||||
})
|
|
||||||
.text(title)
|
|
||||||
.appendTo($data);
|
|
||||||
$('<div>')
|
|
||||||
.text(Ox.formatDate(data[id], '%B %e, %Y'))
|
|
||||||
.appendTo($data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (data.mediastate == 'available') {
|
['accessed', 'modified', 'added', 'created'].forEach(function(id) {
|
||||||
renderShareButton(data).appendTo($data);
|
var title;
|
||||||
|
if (data[id]) {
|
||||||
|
title = Ox.getObjectById(oml.config.itemKeys, id).title;
|
||||||
|
$('<div>')
|
||||||
|
.css({
|
||||||
|
marginTop: '8px',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
})
|
||||||
|
.text(title)
|
||||||
|
.appendTo($data);
|
||||||
|
$('<div>')
|
||||||
|
.text(Ox.formatDate(data[id], '%B %e, %Y'))
|
||||||
|
.appendTo($data);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data.mediastate == 'available') {
|
||||||
|
renderShareButton(data).appendTo($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('<div>').css({height: '16px'}).appendTo($data);
|
$('<div>').css({height: '16px'}).appendTo($data);
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,7 @@ oml.ui.mainMenu = function() {
|
||||||
fromMenu = false,
|
fromMenu = false,
|
||||||
|
|
||||||
that = Ox.MainMenu({
|
that = Ox.MainMenu({
|
||||||
extras: oml.readOnly ? [
|
extras: [
|
||||||
oml.$ui.loadingIcon = oml.ui.loadingIcon()
|
|
||||||
] : [
|
|
||||||
oml.$ui.updateButton = oml.ui.updateButton(),
|
oml.$ui.updateButton = oml.ui.updateButton(),
|
||||||
oml.$ui.transferButton = oml.ui.transferButton(),
|
oml.$ui.transferButton = oml.ui.transferButton(),
|
||||||
oml.$ui.peersButton = oml.ui.peersButton(),
|
oml.$ui.peersButton = oml.ui.peersButton(),
|
||||||
|
|
@ -41,7 +39,6 @@ oml.ui.mainMenu = function() {
|
||||||
id: 'contact',
|
id: 'contact',
|
||||||
title: Ox._('Send Feedback')
|
title: Ox._('Send Feedback')
|
||||||
},
|
},
|
||||||
].concat(oml.readOnly ? [] : [
|
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
id: 'update',
|
id: 'update',
|
||||||
|
|
@ -53,7 +50,7 @@ oml.ui.mainMenu = function() {
|
||||||
title: Ox._('Quit Open Media Library'),
|
title: Ox._('Quit Open Media Library'),
|
||||||
keyboard: 'control q'
|
keyboard: 'control q'
|
||||||
}
|
}
|
||||||
])
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'userMenu',
|
id: 'userMenu',
|
||||||
|
|
@ -64,7 +61,6 @@ oml.ui.mainMenu = function() {
|
||||||
title: Ox._('Preferences...'),
|
title: Ox._('Preferences...'),
|
||||||
keyboard: 'control ,'
|
keyboard: 'control ,'
|
||||||
},
|
},
|
||||||
].concat(oml.readOnly ? [] : [
|
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
id: 'peers',
|
id: 'peers',
|
||||||
|
|
@ -74,7 +70,7 @@ oml.ui.mainMenu = function() {
|
||||||
id: 'transfers',
|
id: 'transfers',
|
||||||
title: Ox._('Transfers...')
|
title: Ox._('Transfers...')
|
||||||
}
|
}
|
||||||
])
|
]
|
||||||
},
|
},
|
||||||
getListMenu(),
|
getListMenu(),
|
||||||
getEditMenu(),
|
getEditMenu(),
|
||||||
|
|
@ -299,7 +295,6 @@ oml.ui.mainMenu = function() {
|
||||||
keyboard: 'shift control s',
|
keyboard: 'shift control s',
|
||||||
disabled: true
|
disabled: true
|
||||||
},
|
},
|
||||||
].concat(oml.readOnly ? [] : [
|
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
id: 'sorttitles',
|
id: 'sorttitles',
|
||||||
|
|
@ -309,7 +304,7 @@ oml.ui.mainMenu = function() {
|
||||||
id: 'sortnames',
|
id: 'sortnames',
|
||||||
title: Ox._('Sort Names...')
|
title: Ox._('Sort Names...')
|
||||||
}
|
}
|
||||||
])
|
]
|
||||||
},
|
},
|
||||||
getFindMenu(),
|
getFindMenu(),
|
||||||
{
|
{
|
||||||
|
|
@ -482,19 +477,15 @@ oml.ui.mainMenu = function() {
|
||||||
} else if (id == 'invertselection') {
|
} else if (id == 'invertselection') {
|
||||||
oml.$ui.list.invertSelection();
|
oml.$ui.list.invertSelection();
|
||||||
} else if (id == 'download') {
|
} else if (id == 'download') {
|
||||||
if (oml.readOnly) {
|
oml.api.addListItems({
|
||||||
document.location.href = '/' + ui.listSelection[0] + '/get/'
|
items: ui.listSelection.filter(function(id) {
|
||||||
} else {
|
return oml.$ui.list.value(id, 'mediastate') == 'unavailable';
|
||||||
oml.api.addListItems({
|
}),
|
||||||
items: ui.listSelection.filter(function(id) {
|
list: ':'
|
||||||
return oml.$ui.list.value(id, 'mediastate') == 'unavailable';
|
}, function(result) {
|
||||||
}),
|
Ox.Request.clearCache();
|
||||||
list: ':'
|
// FIXME: reload?
|
||||||
}, function(result) {
|
});
|
||||||
Ox.Request.clearCache();
|
|
||||||
// FIXME: reload?
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (Ox.contains(['cut', 'cutadd'], id)) {
|
} else if (Ox.contains(['cut', 'cutadd'], id)) {
|
||||||
var action = data.id == 'cut' ? 'copy' : 'add';
|
var action = data.id == 'cut' ? 'copy' : 'add';
|
||||||
fromMenu = true;
|
fromMenu = true;
|
||||||
|
|
@ -750,7 +741,7 @@ oml.ui.mainMenu = function() {
|
||||||
clipboardItems > 1 ? Ox.formatNumber(clipboardItems) + ' ' : ''
|
clipboardItems > 1 ? Ox.formatNumber(clipboardItems) + ' ' : ''
|
||||||
) + Ox._(clipboardItems == 1 ? 'Book' : 'Books'),
|
) + Ox._(clipboardItems == 1 ? 'Book' : 'Books'),
|
||||||
canSelect = !ui.item,
|
canSelect = !ui.item,
|
||||||
canDownload = !!unavailableItems || (oml.readOnly && selectionItems == 1),
|
canDownload = !!unavailableItems,
|
||||||
canCopy = canSelect && selectionItems,
|
canCopy = canSelect && selectionItems,
|
||||||
canCut = canCopy && listData.editable,
|
canCut = canCopy && listData.editable,
|
||||||
canPaste = listData.editable && clipboardItems,
|
canPaste = listData.editable && clipboardItems,
|
||||||
|
|
@ -766,7 +757,7 @@ oml.ui.mainMenu = function() {
|
||||||
return {
|
return {
|
||||||
id: 'editMenu',
|
id: 'editMenu',
|
||||||
title: Ox._('Edit'),
|
title: Ox._('Edit'),
|
||||||
items: [].concat(oml.readOnly ? [] : [
|
items: [
|
||||||
{
|
{
|
||||||
id: 'import',
|
id: 'import',
|
||||||
title: Ox._(oml.user.importing ? 'Importing Books...' : 'Import Books...') // FIXME
|
title: Ox._(oml.user.importing ? 'Importing Books...' : 'Import Books...') // FIXME
|
||||||
|
|
@ -776,7 +767,6 @@ oml.ui.mainMenu = function() {
|
||||||
title: Ox._(oml.user.exporting ? 'Exporting Books...' : 'Export Books...') // FIXME
|
title: Ox._(oml.user.exporting ? 'Exporting Books...' : 'Export Books...') // FIXME
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
]).concat([
|
|
||||||
{
|
{
|
||||||
id: 'selectall',
|
id: 'selectall',
|
||||||
title: Ox._('Select All'),
|
title: Ox._('Select All'),
|
||||||
|
|
@ -802,7 +792,6 @@ oml.ui.mainMenu = function() {
|
||||||
disabled: !canDownload,
|
disabled: !canDownload,
|
||||||
keyboard: 'control d'
|
keyboard: 'control d'
|
||||||
},
|
},
|
||||||
]).concat(oml.readOnly ? [] : [
|
|
||||||
{
|
{
|
||||||
id: 'cut',
|
id: 'cut',
|
||||||
title: Ox._('Cut {0}', [selectionItemName]),
|
title: Ox._('Cut {0}', [selectionItemName]),
|
||||||
|
|
@ -876,7 +865,7 @@ oml.ui.mainMenu = function() {
|
||||||
title: Ox._('Clear History'),
|
title: Ox._('Clear History'),
|
||||||
disabled: !historyItems,
|
disabled: !historyItems,
|
||||||
}
|
}
|
||||||
])
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -941,14 +930,6 @@ oml.ui.mainMenu = function() {
|
||||||
isLibrary = Ox.endsWith(ui._list, ':'),
|
isLibrary = Ox.endsWith(ui._list, ':'),
|
||||||
isList = !isLibraries && !isLibrary,
|
isList = !isLibraries && !isLibrary,
|
||||||
isOwnList = ui._list[0] == ':';
|
isOwnList = ui._list[0] == ':';
|
||||||
|
|
||||||
if (oml.readOnly) {
|
|
||||||
return {
|
|
||||||
id: 'listMenu',
|
|
||||||
title: Ox._('List'),
|
|
||||||
items: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
id: 'listMenu',
|
id: 'listMenu',
|
||||||
title: Ox._('List'),
|
title: Ox._('List'),
|
||||||
|
|
|
||||||
|
|
@ -50,12 +50,8 @@
|
||||||
$ui: {},
|
$ui: {},
|
||||||
config: data.config,
|
config: data.config,
|
||||||
user: data.user,
|
user: data.user,
|
||||||
readOnly: data.readOnly,
|
|
||||||
version: data.version
|
version: data.version
|
||||||
});
|
});
|
||||||
if (oml.readOnly) {
|
|
||||||
oml.user.ui = oml.localStorage('ui') || oml.user.ui;
|
|
||||||
}
|
|
||||||
['preferences', 'ui'].forEach(function(key) {
|
['preferences', 'ui'].forEach(function(key) {
|
||||||
// make sure all valid settings are present
|
// make sure all valid settings are present
|
||||||
oml.user[key] = Ox.extend(
|
oml.user[key] = Ox.extend(
|
||||||
|
|
|
||||||
|
|
@ -142,14 +142,6 @@ oml.ui.preferencesPanel = function() {
|
||||||
value: preferences.autostart,
|
value: preferences.autostart,
|
||||||
help: 'Launch Open Media Library in the background once you login to your computer.'
|
help: 'Launch Open Media Library in the background once you login to your computer.'
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
{
|
|
||||||
id: 'enableReadOnlyService',
|
|
||||||
title: 'Read-Only Hidden Service',
|
|
||||||
value: preferences.enableReadOnlyService,
|
|
||||||
help: 'Make a read-only version of your library available as a TOR Hidden service.<br>\n Your library will be available at http://' + oml.user.id + '.onion/'
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
id: 'showDebugMenu',
|
id: 'showDebugMenu',
|
||||||
title: 'Show Debug Menu',
|
title: 'Show Debug Menu',
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ oml.ui.userDialog = function() {
|
||||||
title: Ox._('Preferences'),
|
title: Ox._('Preferences'),
|
||||||
selected: ui.page == 'preferences'
|
selected: ui.page == 'preferences'
|
||||||
},
|
},
|
||||||
].concat(oml.readOnly ? [] : [
|
|
||||||
{
|
{
|
||||||
id: 'peers',
|
id: 'peers',
|
||||||
title: Ox._('Peers'),
|
title: Ox._('Peers'),
|
||||||
|
|
@ -27,7 +26,7 @@ oml.ui.userDialog = function() {
|
||||||
title: Ox._('Transfers'),
|
title: Ox._('Transfers'),
|
||||||
selected: ui.page == 'transfers'
|
selected: ui.page == 'transfers'
|
||||||
}
|
}
|
||||||
])
|
]
|
||||||
})
|
})
|
||||||
.bindEvent({
|
.bindEvent({
|
||||||
change: function(data) {
|
change: function(data) {
|
||||||
|
|
@ -71,4 +70,4 @@ oml.ui.userDialog = function() {
|
||||||
|
|
||||||
return that;
|
return that;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -862,7 +862,7 @@ oml.getUsers = function(callback) {
|
||||||
}].concat(
|
}].concat(
|
||||||
Ox.sortBy(result.data.users.filter(function(user) {
|
Ox.sortBy(result.data.users.filter(function(user) {
|
||||||
return user.peered;
|
return user.peered;
|
||||||
}), 'index')
|
}), 'index')
|
||||||
);
|
);
|
||||||
ui._users = users;
|
ui._users = users;
|
||||||
callback(users);
|
callback(users);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue